#![allow(unused_variables, unused_mut)]
use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::str::FromStr;
use std::str;
use std::env;
use hyper::client::{Client, RedirectPolicy};
use url::Url;
use xml::reader::EventReader;
use aws::common::credentials::{AwsCredentialsProvider, AwsCredentials};
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::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::*;
pub fn http_client(proxy: Option<Url>) -> Client {
let mut proxy_url: String = String::new();
let mut proxy_port: u16 = 0;
let is_proxy = match proxy {
Some(url) => {
proxy_url = url.host_str().unwrap_or("").to_string();
proxy_port = url.port_or_known_default().unwrap();
true
}
None => {
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();
true
}
_ => {
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();
true
}
_ => false,
}
}
}
}
};
match is_proxy {
true => Client::with_http_proxy(proxy_url, proxy_port),
_ => Client::new()
}
}
#[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());
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.signature);
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 => Err(S3Error::new("Something went wrong when creating a bucket."))
}
}
_ => {
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.events().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.signature);
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.events().peekable());
stack.next(); stack.next();
match status {
200 => {
Ok(())
}
_ => {
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error bucket head", aws))
}
}
}
pub fn list_buckets(&self) -> Result<ListBucketsOutput, S3Error> {
let mut request = SignedRequest::new("GET", "s3", self.region, "", "/", &self.endpoint.signature);
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.events().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, "/?lifecycle", &self.endpoint.signature);
let mut params = Params::new();
params.put("Action", "PutBucketLifecycle");
PutBucketLifecycleRequestWriter::write_params(&mut params, "", input);
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.events().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, "/?acl", &self.endpoint.signature);
let acls = build_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;
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.events().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, "/?policy", &self.endpoint.signature);
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.events().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, "/?website", &self.endpoint.signature);
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.events().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, "/?logging", &self.endpoint.signature);
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.events().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, "/?replication", &self.endpoint.signature);
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.events().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, "/?versioning", &self.endpoint.signature);
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.events().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.signature);
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.events().peekable());
stack.next(); 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, "/?tagging", &self.endpoint.signature);
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.events().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, "/?cors", &self.endpoint.signature);
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.events().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, "/?website", &self.endpoint.signature);
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.events().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, "/{}?policy", &self.endpoint.signature);
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.events().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, "/?replication", &self.endpoint.signature);
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.events().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, "/?cors", &self.endpoint.signature);
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.events().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, "/?acl", &self.endpoint.signature);
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.events().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, "/?logging", &self.endpoint.signature);
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.events().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, "/?notification", &self.endpoint.signature);
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.events().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, "/?versioning", &self.endpoint.signature);
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.events().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.signature);
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.events().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 get_object(&self, input: &GetObjectRequest) -> Result<GetObjectOutput, S3Error> {
let mut request = SignedRequest::new("GET", "s3", self.region, &input.bucket, &format!("/{}", input.key), &self.endpoint.signature);
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 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.events().peekable());
stack.next();
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error getting object", 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 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(),
body: response.body.clone().into_bytes(),
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.signature);
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.events().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 create_multipart_upload(&self, input: &CreateMultipartUploadRequest) -> Result<CreateMultipartUploadOutput, S3Error> {
let object_name = &input.key;
let mut request = SignedRequest::new("POST", "s3", self.region, &input.bucket, &format!("/{}", object_name), &self.endpoint.signature);
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.events().peekable());
stack.next();
match status {
200 => {
Ok(try!(CreateMultipartUploadOutputParser::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 upload_part(&self, input: &UploadPartRequest) -> Result<String, S3Error> {
let object_id = &input.key;
let mut request = SignedRequest::new("PUT", "s3", self.region, &input.bucket, &format!("/{}", object_id), &self.endpoint.signature);
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);
}
let mut params = Params::new();
let upload_id = &input.upload_id;
let part_number = &input.part_number;
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.events().peekable());
stack.next();
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error uploading a part", aws))
}
}
}
pub fn complete_multipart_upload(&self, input: &CompleteMultipartUploadRequest) -> Result<CompleteMultipartUploadOutput, S3Error> {
let mut request = SignedRequest::new("POST", "s3", self.region, &input.bucket,
&format!("/{}", input.key), &self.endpoint.signature);
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.events().peekable());
stack.next();
match status {
200 => {
Ok(try!(CompleteMultipartUploadOutputParser::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 delete_objects(&self, input: &DeleteObjectsRequest) -> Result<DeleteObjectsOutput, S3Error> {
Err(S3Error::new("not implemented"))
}
pub fn delete_object(&self, input: &DeleteObjectRequest) -> Result<DeleteObjectOutput, S3Error> {
let path : String;
if let Some(ref versionId) = input.version_id {
path = format!("/{}?versionId={}", input.key, versionId);
} else {
path = format!("/{}", input.key);
}
let mut request = SignedRequest::new("DELETE", "s3", self.region, &input.bucket, &path, &self.endpoint.signature);
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 {
204 => {
Ok(DeleteObjectOutput::default())
}
_ => {
let mut reader = EventReader::from_str(&result.body);
let mut stack = XmlResponse::new(reader.events().peekable());
stack.next();
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error deleting object", aws))
}
}
}
pub fn restore_object(&self, input: &RestoreObjectRequest) -> Result<RestoreObjectOutput, S3Error> {
let mut request = SignedRequest::new("POST", "s3", self.region, &input.bucket, &format!("/{}?restore", input.key), &self.endpoint.signature);
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.events().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) -> Result<PutObjectOutput, S3Error> {
let mut request = SignedRequest::new("PUT", "s3", self.region, &input.bucket, &format!("/{}", input.key), &self.endpoint.signature);
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 = sign_and_execute(&self.dispatcher, &mut request, 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.events().peekable());
stack.next();
let aws = try!(AWSError::parse_xml("Error", &mut stack));
Err(S3Error::with_aws("Error putting object", aws))
}
}
}
pub fn list_object_versions(&self, input: &ListObjectVersionsRequest) -> Result<ListVersionsResult, S3Error> {
let mut request = SignedRequest::new("GET", "s3", self.region, &input.bucket, "/?versions", &self.endpoint.signature);
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.events().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))
}
}
}
fn hostname(&self, bucket: Option<&BucketName>) -> String {
match bucket {
Some(b) => 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.events().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 build_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(())
}