#![allow(unused_variables, unused_mut)]
use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::str::FromStr;
use std::str;
use std::env;
use std::time::Instant;
use hyper::client::{Client, ProxyConfig, RedirectPolicy};
use hyper::net::HttpsConnector;
use hyper_openssl::OpensslClient;
use url::Url;
use xml::EventReader;
use chrono::{self, UTC};
use aws::common::credentials::{AwsCredentials, AwsCredentialsProvider};
use aws::common::region::Region;
use aws::common::xmlutil::*;
use aws::common::params::{Params, ServiceParams};
use aws::common::signature::SignedRequest;
use aws::common::request::{DispatchSignedRequest, HttpResponse};
use aws::common::common::Operation;
use aws::errors::s3::*;
use aws::errors::aws::*;
use aws::s3::endpoint::*;
use aws::s3::writeparse::*;
use aws::s3::bucket::*;
use aws::s3::object::*;
use aws::s3::acl::*;
use aws::s3::admin::*;
pub fn http_client(proxy: Option<Url>, endpoint: Url) -> Client {
let mut proxy_url: String = String::new();
let mut proxy_port: u16 = 0;
let mut proxy_is_https: bool = false;
let endpoint_domain = endpoint.host_str().unwrap();
let is_proxy = match proxy {
Some(url) => {
proxy_url = url.host_str().unwrap_or("").to_string();
proxy_port = url.port_or_known_default().unwrap();
proxy_is_https = url.scheme() == "https";
true
},
None => {
match env::var("http_proxy") {
Ok(url) => {
match Url::parse(&url) {
Ok(url) => {
proxy_url = url.host_str().unwrap().to_string();
proxy_port = url.port_or_known_default().unwrap();
proxy_is_https = url.scheme() == "https";
true
},
Err(e) => false,
}
},
_ => {
match env::var("HTTP_PROXY") {
Ok(url) => {
let url = Url::parse(&url).unwrap();
proxy_url = url.host_str().unwrap_or("").to_string();
proxy_port = url.port_or_known_default().unwrap();
proxy_is_https = url.scheme() == "https";
true
},
_ => false,
}
},
}
},
};
match is_proxy {
true => {
let mut is_proxy = true;
match env::var("no_proxy") {
Ok(domain_list) => {
if domain_list.contains(endpoint_domain) {
is_proxy = false;
}
},
_ => {},
}
match is_proxy {
true => {
match proxy_is_https {
true => {
let ssl = OpensslClient::new().unwrap();
let connector = HttpsConnector::new(ssl.clone());
let proxy_config = ProxyConfig::new("https", proxy_url, proxy_port, connector, ssl);
Client::with_proxy_config(proxy_config)
},
false => Client::with_http_proxy(proxy_url, proxy_port),
}
},
_ => {
hyper_ssl_client()
},
}
},
_ => {
hyper_ssl_client()
},
}
}
fn hyper_ssl_client() -> Client {
let ssl = OpensslClient::new().unwrap();
let connector = HttpsConnector::new(ssl);
Client::with_connector(connector)
}
#[derive(Debug)]
pub struct S3Client<P, D>
where P: AwsCredentialsProvider,
D: DispatchSignedRequest,
{
credentials_provider: P,
dispatcher: D,
region: Region,
endpoint: Endpoint,
}
impl<P> S3Client<P, Client>
where P: AwsCredentialsProvider,
{
pub fn new(credentials_provider: P, endpoint: Endpoint) -> Self {
let mut client = http_client(endpoint.proxy.clone(), endpoint.endpoint.clone().unwrap());
client.set_redirect_policy(RedirectPolicy::FollowNone);
S3Client::with_request_dispatcher(client, credentials_provider, endpoint)
}
}
impl<P, D> S3Client<P, D>
where P: AwsCredentialsProvider,
D: DispatchSignedRequest,
{
pub fn with_request_dispatcher(request_dispatcher: D, credentials_provider: P, endpoint: Endpoint) -> Self {
S3Client {
credentials_provider: credentials_provider,
region: endpoint.region.clone(),
endpoint: endpoint,
dispatcher: request_dispatcher,
}
}
pub fn endpoint(&self) -> &Endpoint {
&self.endpoint
}
pub fn create_bucket(&self, input: &CreateBucketRequest) -> Result<CreateBucketOutput, S3Error> {
let mut create_config: Vec<u8>;
let mut request = SignedRequest::new("PUT",
"s3",
self.region,
&input.bucket,
"/",
&self.endpoint);
if needs_create_bucket_config(self.region) {
create_config = create_bucket_config_xml(self.region);
request.set_payload(Some(&create_config));
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
match input.acl {
None => {},
Some(ref canned_acl) => request.add_header("x-amz-acl", &canned_acl_in_aws_format(canned_acl)),
}
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
match status {
200 => {
match result.headers.get("Location") {
Some(ref value) => Ok(CreateBucketOutput { location: value.to_string() }),
None => Ok(CreateBucketOutput { location: "".to_string() }),
}
},
_ => {
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error creating bucket", aws))
},
}
}
pub fn head_bucket(&self, input: &HeadBucketRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("HEAD",
"s3",
self.region,
&input.bucket,
"/",
&self.endpoint);
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
match status {
200 => {
Ok(())
},
_ => {
Err(S3Error::new("Error bucket does not exists or error in retrieving"))
},
}
}
pub fn list_buckets(&self) -> Result<ListBucketsOutput, S3Error> {
let mut request = SignedRequest::new(
"GET",
"s3",
self.region,
"",
"/",
&self.endpoint);
request.set_hostname(self.endpoint.hostname());
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
200 => {
Ok(try!(ListBucketsOutputParser::parse_xml("ListAllMyBucketsResult", &mut stack)))
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error listing buckets", aws))
},
}
}
pub fn put_bucket_lifecycle(&self, input: &PutBucketLifecycleRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("PUT",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?lifecycle"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("lifecycle", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(())
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error putting bucket lifecycle", aws))
},
}
}
pub fn put_bucket_acl(&self, input: &PutBucketAclRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("PUT",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?acl"} else {"/"},
&self.endpoint);
let acls = build_bucket_acls(&mut request, &input);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("acl", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
200 => {
Ok(())
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error putting bucket acl", aws))
},
}
}
pub fn put_bucket_policy(&self, input: &PutBucketPolicyRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("PUT",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?policy"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("policy", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
200 => {
Ok(())
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error putting bucket policy", aws))
},
}
}
pub fn put_bucket_website(&self, input: &PutBucketWebsiteRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("PUT",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?website"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("website", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
200 => {
Ok(())
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error putting bucket website", aws))
},
}
}
pub fn put_bucket_logging(&self, input: &PutBucketLoggingRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("PUT",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?logging"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("logging", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(())
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error putting bucket logging", aws))
},
}
}
pub fn put_bucket_replication(&self, input: &PutBucketReplicationRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("PUT",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?replication"} else {""},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("replication", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(())
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error putting bucket replication", aws))
},
}
}
pub fn put_bucket_versioning(&self, input: &PutBucketVersioningRequest) -> Result<(), S3Error> {
let mut payload: Vec<u8>;
let mut request = SignedRequest::new("PUT",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?versioning"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("versioning", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let xml = format!("<VersioningConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">
\
<Status>{}</Status>
</VersioningConfiguration>",
input.versioning_configuration.status);
payload = xml.into_bytes();
request.set_payload(Some(&payload));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(())
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error putting bucket versioning", aws))
},
}
}
pub fn delete_bucket(&self, input: &DeleteBucketRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("DELETE",
"s3",
self.endpoint.region,
&input.bucket,
"/",
&self.endpoint);
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let mut result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
match status {
204 => {
Ok(())
},
_ => {
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error deleting bucket", aws))
},
}
}
pub fn delete_bucket_tagging(&self, input: &DeleteBucketTaggingRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("DELETE",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?tagging"} else {""},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("tagging", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(())
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error deleting bucket tagging", aws))
},
}
}
pub fn delete_bucket_cors(&self, input: &DeleteBucketCorsRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("DELETE",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?cors"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("cors", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(())
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error deleting bucket cors", aws))
},
}
}
pub fn delete_bucket_website(&self, input: &DeleteBucketWebsiteRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("DELETE",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?website"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("website", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(())
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error deleting bucket website", aws))
},
}
}
pub fn delete_bucket_policy(&self, input: &DeleteBucketPolicyRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("DELETE",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?policy"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("policy", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(())
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error deleting bucket policy", aws))
},
}
}
pub fn delete_bucket_replication(&self, input: &DeleteBucketReplicationRequest) -> Result<(), S3Error> {
let mut request = SignedRequest::new("DELETE",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?replication"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("replication", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(())
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error deleting bucket replication", aws))
},
}
}
pub fn get_bucket_cors(&self, input: &GetBucketCorsRequest) -> Result<GetBucketCorsOutput, S3Error> {
let mut request = SignedRequest::new("GET",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?cors"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("cors", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(try!(GetBucketCorsOutputParser::parse_xml("GetBucketCorsOutput", &mut stack)))
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error getting bucket cors", aws))
},
}
}
pub fn get_bucket_acl(&self, input: &GetBucketAclRequest) -> Result<AccessControlPolicy, S3Error> {
let mut request = SignedRequest::new("GET",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?acl"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("acl", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
200 => {
Ok(try!(AccessControlPolicyParser::parse_xml("AccessControlPolicy", &mut stack)))
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error getting bucket acl", aws))
},
}
}
pub fn get_bucket_logging(&self, input: &GetBucketLoggingRequest)
-> Result<GetBucketLoggingOutput, S3Error> {
let mut request = SignedRequest::new("GET",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?logging"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("logging", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
200 => {
Ok(try!(GetBucketLoggingOutputParser::parse_xml("BucketLoggingStatus", &mut stack)))
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error getting bucket logging", aws))
},
}
}
pub fn get_bucket_notification_configuration(&self,
input: &GetBucketNotificationConfigurationRequest)
-> Result<NotificationConfiguration, S3Error> {
let mut request = SignedRequest::new(
"GET",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?notification"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("notification", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
200 => {
Ok(try!(NotificationConfigurationParser::parse_xml("NotificationConfiguration", &mut stack)))
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error getting bucket notification", aws))
},
}
}
pub fn get_bucket_versioning(&self,
input: &GetBucketVersioningRequest)
-> Result<GetBucketVersioningOutput, S3Error> {
let mut request = SignedRequest::new("GET",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?versioning"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("versioning", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); match status {
200 => {
Ok(try!(GetBucketVersioningOutputParser::parse_xml("VersioningConfiguration", &mut stack)))
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error getting bucket versioning", aws))
},
}
}
pub fn list_objects(&self, input:
&ListObjectsRequest)
-> Result<ListObjectsOutput, S3Error> {
let mut request = SignedRequest::new("GET",
"s3",
self.region,
&input.bucket,
"/",
&self.endpoint);
if input.version != None {
let mut params = Params::new();
params.put("list-type", "2");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); match status {
200 => {
Ok(try!(ListObjectsOutputParser::parse_xml("ListBucketResult", &mut stack)))
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error listing bucket objects", aws))
},
}
}
pub fn head_object(&self, input: &HeadObjectRequest) -> Result<HeadObjectOutput, S3Error> {
let mut request = SignedRequest::new("HEAD",
"s3",
self.region,
&input.bucket,
&format!("/{}", input.key),
&self.endpoint);
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let mut result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
match status {
200 => {
let head_object = try!(S3Client::<P,D>::head_object_from_response(&mut result));
Ok(head_object)
}
_ => {
let format = format!("Error getting object head with response: {} - {}", status, if status == 404 {"not found"} else {""});
Err(S3Error::new(format))
}
}
}
pub fn get_object(&self,
input: &GetObjectRequest,
operation: Option<&mut Operation>)
-> Result<GetObjectOutput, S3Error> {
let mut request = SignedRequest::new("GET",
"s3",
self.region,
&input.bucket,
&format!("/{}", input.key),
&self.endpoint);
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
if let Some(ref range) = input.range {
request.add_header("Range", range);
}
let mut result = new_sign_and_execute(&self.dispatcher,
&mut request,
operation,
try!(self.credentials_provider.credentials()));
let status = result.status;
match status {
200...206 => {
let s3_object = try!(S3Client::<P, D>::get_object_from_response(&mut result));
Ok(s3_object)
},
_ => {
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error getting object", aws))
},
}
}
pub fn get_object_acl(&self, input: &GetObjectAclRequest) -> Result<AccessControlPolicy, S3Error> {
let mut path: String;
if self.endpoint.signature == Signature::V2 {
path = format!("/{}?acl", input.key);
} else {
path = format!("/{}", input.key);
}
let mut request = SignedRequest::new("GET",
"s3",
self.region,
&input.bucket,
&path,
&self.endpoint);
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("acl", "");
request.set_params(params);
}
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); match status {
200 => {
Ok(try!(AccessControlPolicyParser::parse_xml("AccessControlPolicy", &mut stack)))
}
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error getting object acl", aws))
}
}
}
pub fn get_value_for_header(header_name: String, response: &HttpResponse) -> Result<String, S3Error> {
match response.headers.get(&header_name) {
Some(ref value) => Ok(value.to_string()),
_ => Ok(String::new()),
}
}
pub fn head_object_from_response(response: &mut HttpResponse) -> Result<HeadObjectOutput, S3Error> {
let delete_marker_string = try!(S3Client::<P,D>::get_value_for_header("x-amz-delete-marker".to_string(), &response));
let delete_marker : bool;
if delete_marker_string.is_empty() {
delete_marker = false;
} else {
delete_marker = try!(bool::from_str(&delete_marker_string));
}
let accept_ranges = try!(S3Client::<P,D>::get_value_for_header("accept-ranges".to_string(), response));
let last_modified = try!(S3Client::<P,D>::get_value_for_header("Last-Modified".to_string(), response));
let request_charged = try!(S3Client::<P,D>::get_value_for_header("x-amz-request-charged".to_string(), response));
let content_encoding = try!(S3Client::<P,D>::get_value_for_header("Content-Encoding".to_string(), response));
let replication_status = try!(S3Client::<P,D>::get_value_for_header("x-amz-replication-status".to_string(), response));
let storage_class = try!(S3Client::<P,D>::get_value_for_header("x-amz-storage-class".to_string(), response));
let server_side_encryption = try!(S3Client::<P,D>::get_value_for_header("x-amz-server-side-encryption".to_string(), response));
let ssekms_key_id = try!(S3Client::<P,D>::get_value_for_header("x-amz-server-side-encryption-aws-kms-key-id".to_string(), response));
let content_disposition = try!(S3Client::<P,D>::get_value_for_header("Content-Disposition".to_string(), response));
let metadata = try!(S3Client::<P,D>::get_value_for_header("x-amz-meta-".to_string(), response));
let website_redirect_location = try!(S3Client::<P,D>::get_value_for_header("x-amz-website-redirect-location".to_string(), response));
let expires = try!(S3Client::<P,D>::get_value_for_header("Expires".to_string(), response));
let cache_control = try!(S3Client::<P,D>::get_value_for_header("Cache-Control".to_string(), response));
let content_length_string = try!(S3Client::<P,D>::get_value_for_header("Content-Length".to_string(), response));
let content_length = try!(content_length_string.parse::<i32>());
let expiration = try!(S3Client::<P,D>::get_value_for_header("x-amz-expiration".to_string(), response));
let missing_meta_string = try!(S3Client::<P,D>::get_value_for_header("x-amz-missing-meta".to_string(), response));
let missing_meta : i32;
if missing_meta_string.is_empty() {
missing_meta = 0;
} else {
missing_meta = try!(missing_meta_string.parse::<i32>());
}
let restore = try!(S3Client::<P,D>::get_value_for_header("x-amz-restore".to_string(), response));
let sse_customer_algorithm = try!(S3Client::<P,D>::get_value_for_header("x-amz-server-side-encryption-customer-algorithm".to_string(), response));
let content_type = try!(S3Client::<P,D>::get_value_for_header("Content-Type".to_string(), response));
let content_language = try!(S3Client::<P,D>::get_value_for_header("Content-Language".to_string(), response));
let version_id = try!(S3Client::<P,D>::get_value_for_header("x-amz-version-id".to_string(), response));
let e_tag = try!(S3Client::<P,D>::get_value_for_header("ETag".to_string(), response));
let sse_customer_key_md5 = try!(S3Client::<P,D>::get_value_for_header("x-amz-server-side-encryption-customer-key-MD5".to_string(), response));
let head_object = HeadObjectOutput {
delete_marker: delete_marker,
accept_ranges: accept_ranges,
last_modified: last_modified,
request_charged: request_charged,
content_encoding: content_encoding,
replication_status: replication_status,
storage_class: storage_class,
server_side_encryption: server_side_encryption,
ssekms_key_id: ssekms_key_id,
content_disposition: content_disposition,
metadata: HashMap::new(),
website_redirect_location: website_redirect_location,
expires: expires,
cache_control: cache_control,
content_length: content_length,
expiration: expiration,
missing_meta: missing_meta,
restore: restore,
sse_customer_algorithm: sse_customer_algorithm,
content_type: content_type,
content_language: content_language,
version_id: version_id,
e_tag: e_tag,
sse_customer_key_md5: sse_customer_key_md5,
};
Ok(head_object)
}
pub fn get_object_from_response(response: &mut HttpResponse) -> Result<GetObjectOutput, S3Error> {
let delete_marker_string = try!(S3Client::<P, D>::get_value_for_header("x-amz-delete-marker".to_string(),
&response));
let delete_marker: bool;
if delete_marker_string.is_empty() {
delete_marker = false;
} else {
delete_marker = try!(bool::from_str(&delete_marker_string));
}
let accept_ranges = try!(S3Client::<P, D>::get_value_for_header("accept-ranges".to_string(), response));
let last_modified = try!(S3Client::<P, D>::get_value_for_header("Last-Modified".to_string(), response));
let content_range = try!(S3Client::<P, D>::get_value_for_header("Content-Range".to_string(), response));
let request_charged = try!(S3Client::<P, D>::get_value_for_header("x-amz-request-charged".to_string(),
response));
let content_encoding = try!(S3Client::<P, D>::get_value_for_header("Content-Encoding".to_string(), response));
let replication_status = try!(S3Client::<P, D>::get_value_for_header("x-amz-replication-status".to_string(),
response));
let storage_class = try!(S3Client::<P, D>::get_value_for_header("x-amz-storage-class".to_string(), response));
let server_side_encryption =
try!(S3Client::<P, D>::get_value_for_header("x-amz-server-side-encryption".to_string(), response));
let ssekms_key_id = try!(S3Client::<P, D>::get_value_for_header("x-amz-server-side-encryption-aws-kms-key-id"
.to_string(),
response));
let content_disposition = try!(S3Client::<P, D>::get_value_for_header("Content-Disposition".to_string(),
response));
let metadata = try!(S3Client::<P, D>::get_value_for_header("x-amz-meta-".to_string(), response));
let website_redirect_location =
try!(S3Client::<P, D>::get_value_for_header("x-amz-website-redirect-location".to_string(), response));
let expires = try!(S3Client::<P, D>::get_value_for_header("Expires".to_string(), response));
let cache_control = try!(S3Client::<P, D>::get_value_for_header("Cache-Control".to_string(), response));
let content_length_string = try!(S3Client::<P, D>::get_value_for_header("Content-Length".to_string(),
response));
let content_length = try!(content_length_string.parse::<i32>());
let expiration = try!(S3Client::<P, D>::get_value_for_header("x-amz-expiration".to_string(), response));
let missing_meta_string = try!(S3Client::<P, D>::get_value_for_header("x-amz-missing-meta".to_string(),
response));
let missing_meta: i32;
if missing_meta_string.is_empty() {
missing_meta = 0;
} else {
missing_meta = try!(missing_meta_string.parse::<i32>());
}
let restore = try!(S3Client::<P, D>::get_value_for_header("x-amz-restore".to_string(), response));
let sse_customer_algorithm =
try!(S3Client::<P, D>::get_value_for_header("x-amz-server-side-encryption-customer-algorithm".to_string(),
response));
let content_type = try!(S3Client::<P, D>::get_value_for_header("Content-Type".to_string(), response));
let content_language = try!(S3Client::<P, D>::get_value_for_header("Content-Language".to_string(), response));
let version_id = try!(S3Client::<P, D>::get_value_for_header("x-amz-version-id".to_string(), response));
let e_tag = try!(S3Client::<P, D>::get_value_for_header("ETag".to_string(), response));
let sse_customer_key_md5 =
try!(S3Client::<P, D>::get_value_for_header("x-amz-server-side-encryption-customer-key-MD5".to_string(),
response));
let s3_object = GetObjectOutput {
delete_marker: delete_marker,
accept_ranges: accept_ranges,
last_modified: last_modified,
content_range: content_range,
request_charged: request_charged,
content_encoding: content_encoding,
replication_status: replication_status,
storage_class: storage_class,
server_side_encryption: server_side_encryption,
ssekms_key_id: ssekms_key_id,
content_disposition: content_disposition,
metadata: HashMap::new(),
is_body: response.is_body,
body: response.body.clone().into_bytes(),
body_buffer: response.body_buffer.clone(),
website_redirect_location: website_redirect_location,
expires: expires,
cache_control: cache_control,
content_length: content_length,
expiration: expiration,
missing_meta: missing_meta,
restore: restore,
sse_customer_algorithm: sse_customer_algorithm,
content_type: content_type,
content_language: content_language,
version_id: version_id,
e_tag: e_tag,
sse_customer_key_md5: sse_customer_key_md5,
};
Ok(s3_object)
}
pub fn copy_object(&self, input: &CopyObjectRequest) -> Result<CopyObjectOutput, S3Error> {
let mut request = SignedRequest::new("PUT",
"s3",
self.region,
&input.bucket,
&format!("/{}", input.key),
&self.endpoint);
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(try!(CopyObjectOutputParser::parse_xml("CopyObjectOutput", &mut stack)))
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error copying object", aws))
},
}
}
pub fn delete_objects(&self, input: &DeleteObjectsRequest) -> Result<DeleteObjectsOutput, S3Error> {
Err(S3Error::new("not implemented"))
}
pub fn delete_object(&self,
input: &DeleteObjectRequest,
operation: Option<&mut Operation>)
-> Result<DeleteObjectOutput, S3Error> {
let path: String;
if let Some(ref version_id) = input.version_id {
if self.endpoint.signature == Signature::V2 {
path = format!("/{}?versionId={}", input.key, version_id);
} else {
path = format!("/{}", input.key);
}
} else {
path = format!("/{}", input.key);
}
let mut request = SignedRequest::new("DELETE",
"s3",
self.region,
&input.bucket,
&path,
&self.endpoint);
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
if self.endpoint.signature != Signature::V2 {
let mut params = Params::new();
DeleteObjectRequestWriter::write_params(&mut params, "", input);
request.set_params(params);
}
let result = new_sign_and_execute(&self.dispatcher,
&mut request,
operation,
try!(self.credentials_provider.credentials()));
let status = result.status;
match status {
204 => {
Ok(DeleteObjectOutput::default())
},
_ => {
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error deleting object", aws))
},
}
}
pub fn multipart_upload_create(&self,
input: &MultipartUploadCreateRequest)
-> Result<MultipartUploadCreateOutput, S3Error> {
let object_name = &input.key;
let path: String;
if self.endpoint.signature == Signature::V2 {
path = format!("/{}?uploads", object_name);
} else {
path = format!("/{}", object_name);
}
let mut request = SignedRequest::new("POST",
"s3",
self.region,
&input.bucket,
&path,
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("uploads", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
200 => {
Ok(try!(MultipartUploadCreateOutputParser::parse_xml("InitiateMultipartUploadResult", &mut stack)))
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error creating multipart object upload", aws))
},
}
}
pub fn multipart_upload_part(&self, input: &MultipartUploadPartRequest) -> Result<String, S3Error> {
let object_name = &input.key;
let upload_id = &input.upload_id;
let part_number = &input.part_number;
let path: String;
if self.endpoint.signature == Signature::V2 {
path = format!("/{}?partNumber={}&uploadId={}", object_name, part_number, upload_id);
} else {
path = format!("/{}", object_name);
}
let mut request = SignedRequest::new("PUT",
"s3",
self.region,
&input.bucket,
&path,
&self.endpoint);
request.set_payload(input.body);
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
if let Some(ref md5) = input.content_md5 {
request.add_header("Content-MD5", md5);
}
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("partNumber", &format!("{}", part_number));
params.put("uploadId", upload_id);
request.set_params(params);
}
let mut result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
match status {
200 => {
match result.headers.get("ETag") {
Some(ref value) => Ok(value.to_string()),
None => Err(S3Error::new("Couldn't find etag in response headers.")),
}
},
_ => {
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error uploading a part", aws))
},
}
}
pub fn multipart_upload_complete(&self,
input: &MultipartUploadCompleteRequest)
-> Result<MultipartUploadCompleteOutput, S3Error> {
let object_name = &input.key;
let upload_id = &input.upload_id;
let path: String;
if self.endpoint.signature == Signature::V2 {
path = format!("/{}?uploadId={}", object_name, upload_id);
} else {
path = format!("/{}", object_name);
}
let mut request = SignedRequest::new("POST",
"s3",
self.region,
&input.bucket,
&path,
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("uploadId", &input.upload_id.to_string());
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
request.set_payload(input.multipart_upload);
let mut result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
200 => {
Ok(try!(MultipartUploadCompleteOutputParser::parse_xml("CompleteMultipartUploadResult", &mut stack)))
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error completing multipart upload", aws))
},
}
}
pub fn multipart_upload_list(&self, input: &MultipartUploadListRequest)
-> Result<MultipartUploadListOutput, S3Error> {
let mut request = SignedRequest::new(
"GET",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V4 {"/"} else {"/?uploads"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("uploads", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher, &mut request, try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
200 => {
Ok(try!(MultipartUploadListOutputParser::parse_xml("ListMultipartUploadsResult", &mut stack)))
}
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error completing list_multipart_uploads", aws))
}
}
}
pub fn multipart_upload_list_parts(&self, input: &MultipartUploadListPartsRequest) -> Result<MultipartUploadListPartsOutput, S3Error> {
let object_name = &input.key;
let upload_id = &input.upload_id;
let path: String;
if self.endpoint.signature == Signature::V2 {
path = format!("/{}?uploadId={}", object_name, upload_id);
} else {
path = format!("/{}", object_name);
}
let mut request = SignedRequest::new(
"GET",
"s3",
self.region,
&input.bucket,
&path,
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("uploadId", &input.upload_id.to_string());
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let mut result = sign_and_execute(&self.dispatcher, &mut request, try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
200 => {
Ok(try!(MultipartUploadListPartsOutputParser::parse_xml("ListPartsResult", &mut stack)))
}
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error completing list_parts", aws))
}
}
}
pub fn multipart_upload_abort(&self, input: &MultipartUploadAbortRequest)
-> Result<MultipartUploadAbortOutput, S3Error> {
let object_name = &input.key;
let upload_id = &input.upload_id;
let path: String;
if self.endpoint.signature == Signature::V2 {
path = format!("/{}?uploadId={}", object_name, upload_id);
} else {
path = format!("/{}", object_name);
}
let mut request = SignedRequest::new(
"DELETE",
"s3",
self.region,
&input.bucket,
&path,
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("uploadId", &input.upload_id.to_string());
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher, &mut request, try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
204 => {
Ok(MultipartUploadAbortOutput::default())
}
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error completing list_parts", aws))
}
}
}
pub fn restore_object(&self, input: &RestoreObjectRequest) -> Result<RestoreObjectOutput, S3Error> {
let mut path: String;
if self.endpoint.signature == Signature::V2 {
path = format!("/{}?restore", input.key);
} else {
path = format!("/{}", input.key);
}
let mut request = SignedRequest::new("POST",
"s3",
self.region,
&input.bucket,
&path,
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("restore", "");
request.set_params(params);
}
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(try!(RestoreObjectOutputParser::parse_xml("RestoreObjectOutput", &mut stack)))
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error restoring object", aws))
},
}
}
pub fn put_object(&self,
input: &PutObjectRequest,
operation: Option<&mut Operation>)
-> Result<PutObjectOutput, S3Error> {
let path: String;
if input.key.starts_with("/") {
path = input.key.clone();
} else {
path = format!("/{}", input.key);
}
let mut request = SignedRequest::new("PUT",
"s3",
self.region,
&input.bucket,
&path,
&self.endpoint);
if let Some(ref class) = input.storage_class {
request.add_header("x-amz-storage-class", class);
}
if let Some(ref sse) = input.server_side_encryption {
if sse.to_string().to_ascii_lowercase() == "aes256" {
request.add_header("x-amz-server-side-encryption", sse);
} else {
match input.ssekms_key_id {
Some(ref key_id) => request.add_header("x-amz-server-side-encryption-aws-kms-key-id", key_id),
None => return Err(S3Error::new("KMS key specified but no key id provided.")),
}
request.add_header("x-amz-server-side-encryption", "aws:kms");
}
}
if let Some(ref cache_control) = input.cache_control {
request.add_header("Cache-Control", cache_control);
}
if let Some(ref md5) = input.content_md5 {
request.add_header("Content-MD5", md5);
}
if let Some(ref metadata) = input.metadata {
for (key, value) in metadata {
request.add_header(&format!("x-amz-meta-{}", key), value);
}
}
if let Some(ref acl) = input.acl {
request.add_header("x-amz-acl", &canned_acl_in_aws_format(acl));
}
match input.content_type {
Some(ref content_type) => request.set_content_type(content_type.to_string()),
None => request.set_content_type("binary/octet-stream".to_string()),
};
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
request.set_payload(input.body);
let mut result = new_sign_and_execute(&self.dispatcher,
&mut request,
operation,
try!(self.credentials_provider.credentials()));
let status = result.status;
match status {
200 => {
let mut put_result = PutObjectOutput::default();
Ok(put_result)
},
_ => {
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error putting object", aws))
},
}
}
pub fn put_object_acl(&self, input: &PutObjectAclRequest) -> Result<(), S3Error> {
let mut path: String;
if self.endpoint.signature == Signature::V2 {
path = format!("/{}?acl", input.key);
} else {
path = format!("/{}", input.key);
}
let mut request = SignedRequest::new("PUT",
"s3",
self.region,
&input.bucket,
&path,
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("acl", "");
request.set_params(params);
}
let acls = build_object_acls(&mut request, &input);
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
match status {
200 => {
Ok(())
}
_ => {
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error putting object acl", aws))
}
}
}
pub fn list_object_versions(&self, input: &ListObjectVersionsRequest) -> Result<ListVersionsResult, S3Error> {
let mut request = SignedRequest::new("GET",
"s3",
self.region,
&input.bucket,
if self.endpoint.signature == Signature::V2 {"/?versions"} else {"/"},
&self.endpoint);
if self.endpoint.signature == Signature::V4 {
let mut params = Params::new();
params.put("versions", "");
request.set_params(params);
}
let hostname = self.hostname(Some(&input.bucket));
request.set_hostname(Some(hostname));
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
match status {
200 => {
Ok(try!(ListVersionsResultParser::parse_xml("ListVersionsResult", &mut stack)))
},
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error listing object versions", aws))
},
}
}
pub fn admin(&self, input: &AdminRequest) -> Result<AdminOutput, S3Error> {
let input = input.clone();
let output_format: AdminOutputType;
let format = match input.format {
Some(AdminOutputType::Xml) => {
output_format = AdminOutputType::Xml;
"xml"
},
_ => {
output_format = AdminOutputType::Json;
"json"
},
};
let method = match input.method {
Some(method) => method.to_uppercase(),
_ => "GET".to_string(),
};
let mut request = SignedRequest::new(&method,
"s3",
self.region,
"",
&format!("/{}",
input.admin_path.unwrap_or("".to_string())),
&self.endpoint);
let mut params = input.params.clone();
if !params.contains_key("format") {
params.put("format", format);
}
request.set_path_options(input.path_options);
request.set_params(params);
request.set_hostname(self.endpoint.hostname());
let result = sign_and_execute(&self.dispatcher,
&mut request,
try!(self.credentials_provider.credentials()));
let status = result.status;
match status {
200 => {
let body: String;
if result.body.is_empty() {
body = "{}".to_string();
} else {
body = result.body;
}
let mut admin_output = AdminOutput{
code: status as u16,
payload: body,
format: output_format,
};
Ok(admin_output)
},
_ => {
Err(S3Error::new(format!("Admin error: {}", status)))
},
}
}
fn hostname(&self, bucket: Option<&BucketName>) -> String {
match bucket {
Some(b) => {
if b.contains(".") || !self.endpoint.is_bucket_virtual {
format!("{}", self.endpoint.hostname().unwrap())
} else {
format!("{}.{}", b, self.endpoint.hostname().unwrap())
}
},
None => format!("{}", self.endpoint.hostname().unwrap()),
}
}
}
fn extract_s3_redirect_location(response: HttpResponse) -> Result<String, S3Error> {
let mut reader = EventReader::from_str(&response.body);
let mut stack = XmlResponse::new(reader.into_iter().peekable());
stack.next();
extract_s3_temporary_endpoint_from_xml(&mut stack)
}
fn field_in_s3_redirect(name: &str) -> bool {
if name == "Code" || name == "Message" || name == "Bucket" || name == "RequestId" || name == "HostId" {
return true;
}
false
}
fn extract_s3_temporary_endpoint_from_xml<T: Peek + Next>(stack: &mut T) -> Result<String, S3Error> {
try!(start_element(&"Error".to_string(), stack));
loop {
let current_name = try!(peek_at_name(stack));
if current_name == "Endpoint" {
let obj = try!(string_field("Endpoint", stack));
return Ok(obj);
}
if field_in_s3_redirect(¤t_name) {
stack.next(); stack.next(); stack.next(); continue;
}
break;
}
Err(S3Error::new("Couldn't find redirect location for S3 bucket"))
}
fn sign_and_execute<D>(dispatcher: &D,
signed_request: &mut SignedRequest,
creds: AwsCredentials)
-> HttpResponse
where D: DispatchSignedRequest,
{
signed_request.sign(&creds);
let response = dispatcher.dispatch(signed_request).expect("Error dispatching request");
if response.status == 307 {
debug!("Got a redirect response, resending request.");
let new_hostname = extract_s3_redirect_location(response).unwrap();
signed_request.set_hostname(Some(new_hostname.to_string()));
signed_request.sign(&creds);
return dispatcher.dispatch(signed_request).unwrap();
}
response
}
fn new_sign_and_execute<D>(dispatcher: &D,
signed_request: &mut SignedRequest,
operation: Option<&mut Operation>,
creds: AwsCredentials)
-> HttpResponse
where D: DispatchSignedRequest,
{
signed_request.sign(&creds);
let response: HttpResponse;
if let Some(op) = operation {
op.object = format!("{}", signed_request.path);
op.method = signed_request.method.clone();
op.request = format!("{}{}{}",
signed_request.endpoint.clone().endpoint.unwrap().into_string(),
signed_request.bucket,
signed_request.path);
op.endpoint = signed_request.endpoint.clone().endpoint.unwrap().into_string();
if op.method.to_lowercase() == "put" {
op.payload_size = signed_request.payload.unwrap().len() as u64;
}
let start_time = UTC::now();
let now = Instant::now();
response = dispatcher.dispatch(signed_request).expect("Error dispatching timed request");
op.duration = Some(now.elapsed());
op.end_time = Some(start_time + chrono::Duration::from_std(op.duration.unwrap()).unwrap());
op.start_time = Some(start_time);
if op.method.to_lowercase() != "put" {
op.payload_size = response.body.len() as u64;
}
op.success = if response.status < 400 {true} else {false}; op.code = response.status;
} else {
response = dispatcher.dispatch(signed_request).expect("Error dispatching request");
}
if response.status == 307 {
debug!("Got a redirect response, resending request.");
let new_hostname = extract_s3_redirect_location(response).unwrap();
signed_request.set_hostname(Some(new_hostname.to_string()));
signed_request.sign(&creds);
return dispatcher.dispatch(signed_request).unwrap();
}
response
}
fn build_bucket_acls(request: &mut SignedRequest, input: &PutBucketAclRequest) -> Result<(), S3Error> {
match input.acl {
Some(ref canned_acl) => request.add_header("x-amz-acl", &canned_acl_in_aws_format(canned_acl)),
None => {},
}
Ok(())
}
fn build_object_acls(request: &mut SignedRequest, input: &PutObjectAclRequest) -> Result<(), S3Error> {
match input.acl {
Some(ref canned_acl) => request.add_header("x-amz-acl", &canned_acl_in_aws_format(canned_acl)),
None => {},
}
Ok(())
}