summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan Ischo <bryan@ischo.com>2008-07-07 03:58:15 +0000
committerBryan Ischo <bryan@ischo.com>2008-07-07 03:58:15 +0000
commite15c6d4cf1310f3016a3aca6f298b0c0f3986982 (patch)
tree2893840b4c0c592d550e57d298d612b81989c4f9
parent07ce7e4123f0ec6b88e65269c6edd69e13b4935c (diff)
downloadceph-libs3-e15c6d4cf1310f3016a3aca6f298b0c0f3986982.tar.gz
* Reorganized errors; it's all simpler now
-rw-r--r--inc/libs3.h304
-rw-r--r--inc/private.h28
-rw-r--r--src/acl.c36
-rw-r--r--src/bucket.c47
-rw-r--r--src/general.c106
-rw-r--r--src/object.c53
-rw-r--r--src/request.c272
-rw-r--r--src/s3.c147
-rw-r--r--src/service.c10
9 files changed, 589 insertions, 414 deletions
diff --git a/inc/libs3.h b/inc/libs3.h
index e66d9e7..3ad5cc3 100644
--- a/inc/libs3.h
+++ b/inc/libs3.h
@@ -78,13 +78,14 @@
************************************************************************** **/
/**
- * S3Status is a status code as returned by a libs3 function. These status
- * codes identify the success or failure of the request to be sent to S3
- * and the response to be read.
+ * S3Status is a status code as returned by a libs3 function.
**/
typedef enum
{
S3StatusOK ,
+
+ // Errors that prevent the S3 request from being issued or response from
+ // being read
S3StatusFailure ,
S3StatusOutOfMemory ,
S3StatusFailedToCreateMutex ,
@@ -112,78 +113,76 @@ typedef enum
S3StatusHeadersTooLong ,
S3StatusKeyTooLong ,
S3StatusUriTooLong ,
- S3StatusXmlParseFailure
+ S3StatusXmlParseFailure ,
+
+ // Errors from the S3 service
+ S3StatusErrorAccessDenied ,
+ S3StatusErrorAccountProblem ,
+ S3StatusErrorAmbiguousGrantByEmailAddress ,
+ S3StatusErrorBadDigest ,
+ S3StatusErrorBucketAlreadyExists ,
+ S3StatusErrorBucketAlreadyOwnedByYou ,
+ S3StatusErrorBucketNotEmpty ,
+ S3StatusErrorCredentialsNotSupported ,
+ S3StatusErrorCrossLocationLoggingProhibited ,
+ S3StatusErrorEntityTooSmall ,
+ S3StatusErrorEntityTooLarge ,
+ S3StatusErrorExpiredToken ,
+ S3StatusErrorIncompleteBody ,
+ S3StatusErrorIncorrectNumberOfFilesInPostRequest ,
+ S3StatusErrorInlineDataTooLarge ,
+ S3StatusErrorInternalError ,
+ S3StatusErrorInvalidAccessKeyId ,
+ S3StatusErrorInvalidAddressingHeader ,
+ S3StatusErrorInvalidArgument ,
+ S3StatusErrorInvalidBucketName ,
+ S3StatusErrorInvalidDigest ,
+ S3StatusErrorInvalidLocationConstraint ,
+ S3StatusErrorInvalidPayer ,
+ S3StatusErrorInvalidPolicyDocument ,
+ S3StatusErrorInvalidRange ,
+ S3StatusErrorInvalidSecurity ,
+ S3StatusErrorInvalidSOAPRequest ,
+ S3StatusErrorInvalidStorageClass ,
+ S3StatusErrorInvalidTargetBucketForLogging ,
+ S3StatusErrorInvalidToken ,
+ S3StatusErrorInvalidURI ,
+ S3StatusErrorKeyTooLong ,
+ S3StatusErrorMalformedACLError ,
+ S3StatusErrorMalformedXML ,
+ S3StatusErrorMaxMessageLengthExceeded ,
+ S3StatusErrorMaxPostPreDataLengthExceededError ,
+ S3StatusErrorMetadataTooLarge ,
+ S3StatusErrorMethodNotAllowed ,
+ S3StatusErrorMissingAttachment ,
+ S3StatusErrorMissingContentLength ,
+ S3StatusErrorMissingSecurityElement ,
+ S3StatusErrorMissingSecurityHeader ,
+ S3StatusErrorNoLoggingStatusForKey ,
+ S3StatusErrorNoSuchBucket ,
+ S3StatusErrorNoSuchKey ,
+ S3StatusErrorNotImplemented ,
+ S3StatusErrorNotSignedUp ,
+ S3StatusErrorOperationAborted ,
+ S3StatusErrorPermanentRedirect ,
+ S3StatusErrorPreconditionFailed ,
+ S3StatusErrorRedirect ,
+ S3StatusErrorRequestIsNotMultiPartContent ,
+ S3StatusErrorRequestTimeout ,
+ S3StatusErrorRequestTimeTooSkewed ,
+ S3StatusErrorRequestTorrentOfBucketError ,
+ S3StatusErrorSignatureDoesNotMatch ,
+ S3StatusErrorSlowDown ,
+ S3StatusErrorTemporaryRedirect ,
+ S3StatusErrorTokenRefreshRequired ,
+ S3StatusErrorTooManyBuckets ,
+ S3StatusErrorUnexpectedContent ,
+ S3StatusErrorUnresolvableGrantByEmailAddress ,
+ S3StatusErrorUserKeyMustBeSpecified ,
+ S3StatusErrorUnknown
} S3Status;
-typedef enum
-{
- S3ErrorCodeAccessDenied ,
- S3ErrorCodeAccountProblem ,
- S3ErrorCodeAmbiguousGrantByEmailAddress ,
- S3ErrorCodeBadDigest ,
- S3ErrorCodeBucketAlreadyExists ,
- S3ErrorCodeBucketAlreadyOwnedByYou ,
- S3ErrorCodeBucketNotEmpty ,
- S3ErrorCodeCredentialsNotSupported ,
- S3ErrorCodeCrossLocationLoggingProhibited ,
- S3ErrorCodeEntityTooSmall ,
- S3ErrorCodeEntityTooLarge ,
- S3ErrorCodeExpiredToken ,
- S3ErrorCodeIncompleteBody ,
- S3ErrorCodeIncorrectNumberOfFilesInPostRequest ,
- S3ErrorCodeInlineDataTooLarge ,
- S3ErrorCodeInternalError ,
- S3ErrorCodeInvalidAccessKeyId ,
- S3ErrorCodeInvalidAddressingHeader ,
- S3ErrorCodeInvalidArgument ,
- S3ErrorCodeInvalidBucketName ,
- S3ErrorCodeInvalidDigest ,
- S3ErrorCodeInvalidLocationConstraint ,
- S3ErrorCodeInvalidPayer ,
- S3ErrorCodeInvalidPolicyDocument ,
- S3ErrorCodeInvalidRange ,
- S3ErrorCodeInvalidSecurity ,
- S3ErrorCodeInvalidSOAPRequest ,
- S3ErrorCodeInvalidStorageClass ,
- S3ErrorCodeInvalidTargetBucketForLogging ,
- S3ErrorCodeInvalidToken ,
- S3ErrorCodeInvalidURI ,
- S3ErrorCodeKeyTooLong ,
- S3ErrorCodeMalformedACLError ,
- S3ErrorCodeMalformedXML ,
- S3ErrorCodeMaxMessageLengthExceeded ,
- S3ErrorCodeMaxPostPreDataLengthExceededError ,
- S3ErrorCodeMetadataTooLarge ,
- S3ErrorCodeMethodNotAllowed ,
- S3ErrorCodeMissingAttachment ,
- S3ErrorCodeMissingContentLength ,
- S3ErrorCodeMissingSecurityElement ,
- S3ErrorCodeMissingSecurityHeader ,
- S3ErrorCodeNoLoggingStatusForKey ,
- S3ErrorCodeNoSuchBucket ,
- S3ErrorCodeNoSuchKey ,
- S3ErrorCodeNotImplemented ,
- S3ErrorCodeNotSignedUp ,
- S3ErrorCodeOperationAborted ,
- S3ErrorCodePermanentRedirect ,
- S3ErrorCodePreconditionFailed ,
- S3ErrorCodeRedirect ,
- S3ErrorCodeRequestIsNotMultiPartContent ,
- S3ErrorCodeRequestTimeout ,
- S3ErrorCodeRequestTimeTooSkewed ,
- S3ErrorCodeRequestTorrentOfBucketError ,
- S3ErrorCodeSignatureDoesNotMatch ,
- S3ErrorCodeSlowDown ,
- S3ErrorCodeTemporaryRedirect ,
- S3ErrorCodeTokenRefreshRequired ,
- S3ErrorCodeTooManyBuckets ,
- S3ErrorCodeUnexpectedContent ,
- S3ErrorCodeUnresolvableGrantByEmailAddress ,
- S3ErrorCodeUserKeyMustBeSpecified
-} S3ErrorCode;
-
-
/**
* S3Protocol represents a protocol that may be used for communicating a
* request to the Amazon S3 service.
@@ -270,7 +269,7 @@ struct S3Mutex;
typedef struct S3RequestContext S3RequestContext;
-typedef struct S3MetaHeader
+typedef struct S3NameValue
{
// This is the part after x-amz-meta-
const char *name;
@@ -278,7 +277,7 @@ typedef struct S3MetaHeader
// This is the value, not including any line terminators or leading or
// trailing whitespace.
const char *value;
-} S3MetaHeader;
+} S3NameValue;
/**
* S3ResponseHeaders is passed to the header callback function which is called
@@ -338,7 +337,7 @@ typedef struct S3ResponseHeaders
/**
* These are the metadata headers associated with the resource.
**/
- const S3MetaHeader *metaHeaders;
+ const S3NameValue *metaHeaders;
} S3ResponseHeaders;
@@ -546,16 +545,18 @@ typedef struct S3RequestHeaders
} S3RequestHeaders;
-typedef struct S3Error
+typedef struct S3ErrorDetails
{
- S3ErrorCode code;
-
const char *message;
const char *resource;
const char *furtherDetails;
-} S3Error;
+
+ int extraDetailsCount;
+
+ S3NameValue *extraDetails;
+} S3ErrorDetails;
/** **************************************************************************
@@ -590,8 +591,10 @@ typedef void (S3MutexDestroyCallback)(struct S3Mutex *mutex);
typedef S3Status (S3ResponseHeadersCallback)(const S3ResponseHeaders *headers,
void *callbackData);
-typedef void (S3ResponseCompleteCallback)(S3Status status, int httpResponseCode,
- S3Error *error, void *callbackData);
+typedef void (S3ResponseCompleteCallback)(S3Status status,
+ int httpResponseCode,
+ S3ErrorDetails *errorDetails,
+ void *callbackData);
/**
@@ -711,6 +714,14 @@ void S3_deinitialize();
/**
+ * Returns a string with the textual name of an S3Status code
+ *
+ * @return a string with the textual name of an S3Status code
+ **/
+const char *S3_get_status_name(S3Status status);
+
+
+/**
* This function may be used to validate an S3 bucket name as being in the
* correct form for use with the S3 service. Amazon S3 limits the allowed
* characters in S3 bucket names, as well as imposing some additional rules on
@@ -867,12 +878,11 @@ typedef struct S3GetObjectHandler
* response to this operation
* @param callbackData will be passed in as the callbackData parameter to
* callback
- * @return S3Status ???
**/
-S3Status S3_list_service(S3Protocol protocol, const char *accessKeyId,
- const char *secretAccessKey,
- S3RequestContext *requestContext,
- S3ListServiceHandler *handler, void *callbackData);
+void S3_list_service(S3Protocol protocol, const char *accessKeyId,
+ const char *secretAccessKey,
+ S3RequestContext *requestContext,
+ S3ListServiceHandler *handler, void *callbackData);
/** **************************************************************************
@@ -900,14 +910,13 @@ S3Status S3_list_service(S3Protocol protocol, const char *accessKeyId,
* NULL-terminated. On successful return of this function, this will
* be set to the name of the geographic location of S3 bucket, or will
* be left as a zero-length string if no location was available.
- * @return S3Status ???
**/
-S3Status S3_test_bucket(S3Protocol protocol, const char *accessKeyId,
- const char *secretAccessKey, const char *bucketName,
- int locationConstraintReturnSize,
- char *locationConstraintReturn,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData);
+void S3_test_bucket(S3Protocol protocol, const char *accessKeyId,
+ const char *secretAccessKey, const char *bucketName,
+ int locationConstraintReturnSize,
+ char *locationConstraintReturn,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData);
/**
@@ -925,13 +934,11 @@ S3Status S3_test_bucket(S3Protocol protocol, const char *accessKeyId,
* the bucket to create.
* @return S3Status ???
**/
-S3Status S3_create_bucket(S3Protocol protocol, const char *accessKeyId,
- const char *secretAccessKey,
- const char *bucketName,
- S3CannedAcl cannedAcl,
- const char *locationConstraint,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData);
+void S3_create_bucket(S3Protocol protocol, const char *accessKeyId,
+ const char *secretAccessKey, const char *bucketName,
+ S3CannedAcl cannedAcl, const char *locationConstraint,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData);
/**
@@ -945,10 +952,10 @@ S3Status S3_create_bucket(S3Protocol protocol, const char *accessKeyId,
* @param bucketName is the name of the bucket to be deleted
* @return S3Status ???
**/
-S3Status S3_delete_bucket(S3Protocol protocol, const char *accessKeyId,
- const char *secretAccessKey, const char *bucketName,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData);
+void S3_delete_bucket(S3Protocol protocol, const char *accessKeyId,
+ const char *secretAccessKey, const char *bucketName,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData);
/**
@@ -971,11 +978,11 @@ S3Status S3_delete_bucket(S3Protocol protocol, const char *accessKeyId,
* @param callbackData will be passed into the callback
* @return S3Status ???
**/
-S3Status S3_list_bucket(S3BucketContext *bucketContext,
- const char *prefix, const char *marker,
- const char *delimiter, int maxkeys,
- S3RequestContext *requestContext,
- S3ListBucketHandler *handler, void *callbackData);
+void S3_list_bucket(S3BucketContext *bucketContext,
+ const char *prefix, const char *marker,
+ const char *delimiter, int maxkeys,
+ S3RequestContext *requestContext,
+ S3ListBucketHandler *handler, void *callbackData);
/**
@@ -989,11 +996,11 @@ S3Status S3_list_bucket(S3BucketContext *bucketContext,
/*
// xxx todo - possible Cache-Control
*/
-S3Status S3_put_object(S3BucketContext *bucketContext,
- const char *key, uint64_t contentLength,
- const S3RequestHeaders *requestHeaders,
- S3RequestContext *requestContext,
- S3PutObjectHandler *handler, void *callbackData);
+void S3_put_object(S3BucketContext *bucketContext, const char *key,
+ uint64_t contentLength,
+ const S3RequestHeaders *requestHeaders,
+ S3RequestContext *requestContext,
+ S3PutObjectHandler *handler, void *callbackData);
/*
@@ -1001,12 +1008,12 @@ S3Status S3_put_object(S3BucketContext *bucketContext,
// destinationKey NULL means the same object key as [key]
// if pOptionalHeaders is NULL, existing headers will not be changed
*/
-S3Status S3_copy_object(S3BucketContext *bucketContext,
- const char *key, const char *destinationBucket,
- const char *destinationKey,
- const S3RequestHeaders *requestHeaders,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData);
+void S3_copy_object(S3BucketContext *bucketContext,
+ const char *key, const char *destinationBucket,
+ const char *destinationKey,
+ const S3RequestHeaders *requestHeaders,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData);
/*
@@ -1022,25 +1029,24 @@ S3Status S3_copy_object(S3BucketContext *bucketContext,
// expect.
// ifModifiedSince and ifUnmodifiedSince if > 0 will be used
*/
-S3Status S3_get_object(S3BucketContext *bucketContext, const char *key,
- long ifModifiedSince, long ifUnmodifiedSince,
- const char *ifMatchETag, const char *ifNotMatchETag,
- const char *byteRange, S3RequestContext *requestContext,
- S3GetObjectHandler *handler, void *callbackData);
+void S3_get_object(S3BucketContext *bucketContext, const char *key,
+ long ifModifiedSince, long ifUnmodifiedSince,
+ const char *ifMatchETag, const char *ifNotMatchETag,
+ const char *byteRange, S3RequestContext *requestContext,
+ S3GetObjectHandler *handler, void *callbackData);
// ifModifiedSince and ifUnmodifiedSince if > 0 will be used
-S3Status S3_head_object(S3BucketContext *bucketContext, const char *key,
- long ifModifiedSince, long ifUnmodifiedSince,
- const char *ifMatchETag, const char *ifNotMatchETag,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData);
+void S3_head_object(S3BucketContext *bucketContext, const char *key,
+ long ifModifiedSince, long ifUnmodifiedSince,
+ const char *ifMatchETag, const char *ifNotMatchETag,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData);
-S3Status S3_delete_object(S3BucketContext *bucketContext,
- const char *key,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData);
+void S3_delete_object(S3BucketContext *bucketContext, const char *key,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData);
/** **************************************************************************
@@ -1052,27 +1058,27 @@ S3Status S3_delete_object(S3BucketContext *bucketContext,
// aclBuffer must be less than or equal to S3_ACL_BUFFER_MAXLEN bytes in size,
// and does not need to be zero-terminated
*/
-S3Status S3_set_acl(S3BucketContext *bucketContext, const char *key,
- int aclGrantCount, S3AclGrant *aclGrants,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData);
+void S3_set_acl(S3BucketContext *bucketContext, const char *key,
+ int aclGrantCount, S3AclGrant *aclGrants,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData);
-S3Status S3_add_acl_grants(S3BucketContext *bucketContext, const char *key,
- int aclGrantCount, S3AclGrant *aclGrants,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData);
+void S3_add_acl_grants(S3BucketContext *bucketContext, const char *key,
+ int aclGrantCount, S3AclGrant *aclGrants,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData);
-S3Status S3_remove_acl_grants(S3BucketContext *bucketContext, const char *key,
- int aclGrantsCount, S3AclGrant *aclGrants,
- S3RequestContext *requestContext,
- void *callbackData);
+void S3_remove_acl_grants(S3BucketContext *bucketContext, const char *key,
+ int aclGrantsCount, S3AclGrant *aclGrants,
+ S3RequestContext *requestContext,
+ void *callbackData);
-S3Status S3_clear_acl(S3BucketContext *bucketContext, const char *key,
- S3RequestContext *requestContext,
- S3ResponseHandler *hander, void *callbackData);
+void S3_clear_acl(S3BucketContext *bucketContext, const char *key,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *hander, void *callbackData);
/**
diff --git a/inc/private.h b/inc/private.h
index fe21272..b190d5b 100644
--- a/inc/private.h
+++ b/inc/private.h
@@ -191,6 +191,10 @@ typedef struct Request
// True if this request has already been used
int used;
+ // The status of this Request, as will be reported to the user via the
+ // complete callback
+ S3Status status;
+
// The CURL structure driving the request
CURL *curl;
@@ -217,7 +221,7 @@ typedef struct Request
int responseMetaHeaderStringsLen;
// Response meta headers
- S3MetaHeader responseMetaHeaders[MAX_META_HEADER_COUNT];
+ S3NameValue responseMetaHeaders[MAX_META_HEADER_COUNT];
// Callback to make when headers are available
S3ResponseHeadersCallback *headersCallback;
@@ -249,7 +253,7 @@ typedef struct Request
SimpleXml errorXmlParser;
// If S3 did send an XML error, this is the parsed form of it
- S3Error s3Error;
+ S3ErrorDetails s3ErrorDetails;
// These are the buffers used to store the S3Error values
char s3ErrorCode[1024];
@@ -266,6 +270,20 @@ typedef struct Request
// These are the buffers used to store the S3Error values
char s3ErrorFurtherDetails[1024];
int s3ErrorFurtherDetailsLen;
+
+ // The extra details; we support up to 8 of them
+ S3NameValue s3ErrorExtraDetails[8];
+ // This is the buffer from which the names used in s3ErrorExtraDetails
+ // are allocated
+ char s3ErrorExtraDetailsNames[512];
+ // And this is the length of each element of s3ErrorExtraDetailsNames
+ int s3ErrorExtraDetailsNamesLen;
+ // These are the buffers of values in the s3ErrorExtraDetails. They
+ // are kept separate so that they can be individually appended to.
+ char s3ErrorExtraDetailsValues[8][1024];
+ // And these are the individual lengths of each of each element of
+ // s3ErrorExtraDetailsValues
+ int s3ErrorExtraDetailsValuesLens[8];
// The callbacks to make for the data payload of the response
union {
@@ -310,10 +328,8 @@ S3Status request_api_initialize(const char *userAgentInfo);
void request_api_deinitialize();
// Perform a request; if context is 0, performs the request immediately;
-// otherwise, sets it up to be performed by context. If S3StatusOK is
-// returned, the request was successfully completed/added to the context.
-// Otherwise, it was never even started due to an error with the request.
-S3Status request_perform(RequestParams *params, S3RequestContext *context);
+// otherwise, sets it up to be performed by context.
+void request_perform(RequestParams *params, S3RequestContext *context);
// Called by the internal request code or internal request context code when a
// curl has finished the request
diff --git a/src/acl.c b/src/acl.c
index 9008967..fe65a35 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -24,37 +24,33 @@
#include "private.h"
-S3Status S3_set_acl(S3BucketContext *bucketContext, const char *key,
- int aclGrantCount, S3AclGrant *aclGrants,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData)
+void S3_set_acl(S3BucketContext *bucketContext, const char *key,
+ int aclGrantCount, S3AclGrant *aclGrants,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData)
{
- return S3StatusOK;
}
-S3Status S3_add_acl_grants(S3BucketContext *bucketContext, const char *key,
- int aclGrantCount, S3AclGrant *aclGrants,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData)
+void S3_add_acl_grants(S3BucketContext *bucketContext, const char *key,
+ int aclGrantCount, S3AclGrant *aclGrants,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData)
{
- return S3StatusOK;
}
-S3Status S3_remove_acl_grants(S3BucketContext *bucketContext, const char *key,
- int aclGrantsCount, S3AclGrant *aclGrants,
- S3RequestContext *requestContext,
- void *callbackData)
+void S3_remove_acl_grants(S3BucketContext *bucketContext, const char *key,
+ int aclGrantsCount, S3AclGrant *aclGrants,
+ S3RequestContext *requestContext,
+ void *callbackData)
{
- return S3StatusOK;
}
-S3Status S3_clear_acl(S3BucketContext *bucketContext, const char *key,
- S3RequestContext *requestContext,
- S3ResponseHandler *requestHandler,
- void *callbackData)
+void S3_clear_acl(S3BucketContext *bucketContext, const char *key,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *requestHandler,
+ void *callbackData)
{
- return S3StatusOK;
}
diff --git a/src/bucket.c b/src/bucket.c
index b029e65..1575d4f 100644
--- a/src/bucket.c
+++ b/src/bucket.c
@@ -64,12 +64,12 @@ static size_t create_bucket_read_callback(void *data, size_t s, size_t n,
}
-S3Status S3_test_bucket(S3Protocol protocol, const char *accessKeyId,
- const char *secretAccessKey, const char *bucketName,
- int locationConstraintReturnSize,
- char *locationConstraintReturn,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData)
+void S3_test_bucket(S3Protocol protocol, const char *accessKeyId,
+ const char *secretAccessKey, const char *bucketName,
+ int locationConstraintReturnSize,
+ char *locationConstraintReturn,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData)
{
// Set up the RequestParams
RequestParams params =
@@ -98,16 +98,15 @@ S3Status S3_test_bucket(S3Protocol protocol, const char *accessKeyId,
}
// Perform the request
- return request_perform(&params, requestContext);
+ request_perform(&params, requestContext);
}
-S3Status S3_create_bucket(S3Protocol protocol, const char *accessKeyId,
- const char *secretAccessKey, const char *bucketName,
- S3CannedAcl cannedAcl,
- const char *locationConstraint,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData)
+void S3_create_bucket(S3Protocol protocol, const char *accessKeyId,
+ const char *secretAccessKey, const char *bucketName,
+ S3CannedAcl cannedAcl, const char *locationConstraint,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData)
{
// Set up S3RequestHeaders
S3RequestHeaders headers =
@@ -149,14 +148,14 @@ S3Status S3_create_bucket(S3Protocol protocol, const char *accessKeyId,
// xxx todo support locationConstraint
// Perform the request
- return request_perform(&params, requestContext);
+ request_perform(&params, requestContext);
}
-S3Status S3_delete_bucket(S3Protocol protocol, const char *accessKeyId,
- const char *secretAccessKey, const char *bucketName,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData)
+void S3_delete_bucket(S3Protocol protocol, const char *accessKeyId,
+ const char *secretAccessKey, const char *bucketName,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData)
{
// Set up the RequestParams
RequestParams params =
@@ -182,15 +181,13 @@ S3Status S3_delete_bucket(S3Protocol protocol, const char *accessKeyId,
// xxx todo support locationConstraint
// Perform the request
- return request_perform(&params, requestContext);
+ request_perform(&params, requestContext);
}
-S3Status S3_list_bucket(S3BucketContext *bucketContext,
- const char *prefix, const char *marker,
- const char *delimiter, int maxkeys,
- S3RequestContext *requestContext,
- S3ListBucketHandler *handler, void *callbackData)
+void S3_list_bucket(S3BucketContext *bucketContext, const char *prefix,
+ const char *marker, const char *delimiter, int maxkeys,
+ S3RequestContext *requestContext,
+ S3ListBucketHandler *handler, void *callbackData)
{
- return S3StatusOK;
}
diff --git a/src/general.c b/src/general.c
index e9db8d7..8a46cc8 100644
--- a/src/general.c
+++ b/src/general.c
@@ -162,6 +162,112 @@ void S3_deinitialize()
}
+const char *S3_get_status_name(S3Status status)
+{
+ switch (status) {
+#define handlecase(s) \
+ case S3Status##s: \
+ return #s
+
+ handlecase(OK);
+ handlecase(Failure);
+ handlecase(OutOfMemory);
+ handlecase(FailedToCreateMutex);
+ handlecase(InvalidBucketNameTooLong);
+ handlecase(InvalidBucketNameFirstCharacter);
+ handlecase(InvalidBucketNameCharacter);
+ handlecase(InvalidBucketNameCharacterSequence);
+ handlecase(InvalidBucketNameTooShort);
+ handlecase(InvalidBucketNameDotQuadNotation);
+ handlecase(FailedToCreateRequest);
+ handlecase(FailedToInitializeRequest);
+ handlecase(FailedToCreateRequestContext);
+ handlecase(MetaHeadersTooLong);
+ handlecase(BadMetaHeader);
+ handlecase(BadContentType);
+ handlecase(ContentTypeTooLong);
+ handlecase(BadMD5);
+ handlecase(MD5TooLong);
+ handlecase(BadCacheControl);
+ handlecase(CacheControlTooLong);
+ handlecase(BadContentDispositionFilename);
+ handlecase(ContentDispositionFilenameTooLong);
+ handlecase(BadContentEncoding);
+ handlecase(ContentEncodingTooLong);
+ handlecase(HeadersTooLong);
+ handlecase(KeyTooLong);
+ handlecase(UriTooLong);
+ handlecase(XmlParseFailure);
+ handlecase(ErrorAccessDenied);
+ handlecase(ErrorAccountProblem);
+ handlecase(ErrorAmbiguousGrantByEmailAddress);
+ handlecase(ErrorBadDigest);
+ handlecase(ErrorBucketAlreadyExists);
+ handlecase(ErrorBucketAlreadyOwnedByYou);
+ handlecase(ErrorBucketNotEmpty);
+ handlecase(ErrorCredentialsNotSupported);
+ handlecase(ErrorCrossLocationLoggingProhibited);
+ handlecase(ErrorEntityTooSmall);
+ handlecase(ErrorEntityTooLarge);
+ handlecase(ErrorExpiredToken);
+ handlecase(ErrorIncompleteBody);
+ handlecase(ErrorIncorrectNumberOfFilesInPostRequest);
+ handlecase(ErrorInlineDataTooLarge);
+ handlecase(ErrorInternalError);
+ handlecase(ErrorInvalidAccessKeyId);
+ handlecase(ErrorInvalidAddressingHeader);
+ handlecase(ErrorInvalidArgument);
+ handlecase(ErrorInvalidBucketName);
+ handlecase(ErrorInvalidDigest);
+ handlecase(ErrorInvalidLocationConstraint);
+ handlecase(ErrorInvalidPayer);
+ handlecase(ErrorInvalidPolicyDocument);
+ handlecase(ErrorInvalidRange);
+ handlecase(ErrorInvalidSecurity);
+ handlecase(ErrorInvalidSOAPRequest);
+ handlecase(ErrorInvalidStorageClass);
+ handlecase(ErrorInvalidTargetBucketForLogging);
+ handlecase(ErrorInvalidToken);
+ handlecase(ErrorInvalidURI);
+ handlecase(ErrorKeyTooLong);
+ handlecase(ErrorMalformedACLError);
+ handlecase(ErrorMalformedXML);
+ handlecase(ErrorMaxMessageLengthExceeded);
+ handlecase(ErrorMaxPostPreDataLengthExceededError);
+ handlecase(ErrorMetadataTooLarge);
+ handlecase(ErrorMethodNotAllowed);
+ handlecase(ErrorMissingAttachment);
+ handlecase(ErrorMissingContentLength);
+ handlecase(ErrorMissingSecurityElement);
+ handlecase(ErrorMissingSecurityHeader);
+ handlecase(ErrorNoLoggingStatusForKey);
+ handlecase(ErrorNoSuchBucket);
+ handlecase(ErrorNoSuchKey);
+ handlecase(ErrorNotImplemented);
+ handlecase(ErrorNotSignedUp);
+ handlecase(ErrorOperationAborted);
+ handlecase(ErrorPermanentRedirect);
+ handlecase(ErrorPreconditionFailed);
+ handlecase(ErrorRedirect);
+ handlecase(ErrorRequestIsNotMultiPartContent);
+ handlecase(ErrorRequestTimeout);
+ handlecase(ErrorRequestTimeTooSkewed);
+ handlecase(ErrorRequestTorrentOfBucketError);
+ handlecase(ErrorSignatureDoesNotMatch);
+ handlecase(ErrorSlowDown);
+ handlecase(ErrorTemporaryRedirect);
+ handlecase(ErrorTokenRefreshRequired);
+ handlecase(ErrorTooManyBuckets);
+ handlecase(ErrorUnexpectedContent);
+ handlecase(ErrorUnresolvableGrantByEmailAddress);
+ handlecase(ErrorUserKeyMustBeSpecified);
+ handlecase(ErrorUnknown);
+ }
+
+ return "Unknown";
+}
+
+
S3Status S3_validate_bucket_name(const char *bucketName, S3UriStyle uriStyle)
{
int virtualHostStyle = (uriStyle == S3UriStyleVirtualHost);
diff --git a/src/object.c b/src/object.c
index 3a21c22..d20d958 100644
--- a/src/object.c
+++ b/src/object.c
@@ -24,51 +24,44 @@
#include "private.h"
-S3Status S3_put_object(S3BucketContext *bucketContext,
- const char *key, uint64_t contentLength,
- const S3RequestHeaders *requestHeaders,
- S3RequestContext *requestContext,
- S3PutObjectHandler *handler, void *callbackData)
+void S3_put_object(S3BucketContext *bucketContext, const char *key,
+ uint64_t contentLength,
+ const S3RequestHeaders *requestHeaders,
+ S3RequestContext *requestContext,
+ S3PutObjectHandler *handler, void *callbackData)
{
- return S3StatusOK;
}
-S3Status S3_copy_object(S3BucketContext *bucketContext,
- const char *key, const char *destinationBucket,
- const char *destinationKey,
- const S3RequestHeaders *requestHeaders,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData)
+void S3_copy_object(S3BucketContext *bucketContext, const char *key,
+ const char *destinationBucket, const char *destinationKey,
+ const S3RequestHeaders *requestHeaders,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData)
{
- return S3StatusOK;
}
-S3Status S3_get_object(S3BucketContext *bucketContext, const char *key,
- long ifModifiedSince, long ifUnmodifiedSince,
- const char *ifMatchETag, const char *ifNotMatchETag,
- const char *byteRange, S3RequestContext *requestContext,
- S3GetObjectHandler *handler, void *callbackData)
+void S3_get_object(S3BucketContext *bucketContext, const char *key,
+ long ifModifiedSince, long ifUnmodifiedSince,
+ const char *ifMatchETag, const char *ifNotMatchETag,
+ const char *byteRange, S3RequestContext *requestContext,
+ S3GetObjectHandler *handler, void *callbackData)
{
- return S3StatusOK;
}
-S3Status S3_head_object(S3BucketContext *bucketContext, const char *key,
- long ifModifiedSince, long ifUnmodifiedSince,
- const char *ifMatchETag, const char *ifNotMatchETag,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData)
+void S3_head_object(S3BucketContext *bucketContext, const char *key,
+ long ifModifiedSince, long ifUnmodifiedSince,
+ const char *ifMatchETag, const char *ifNotMatchETag,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData)
{
- return S3StatusOK;
}
-S3Status S3_delete_object(S3BucketContext *bucketContext,
- const char *key,
- S3RequestContext *requestContext,
- S3ResponseHandler *handler, void *callbackData)
+void S3_delete_object(S3BucketContext *bucketContext, const char *key,
+ S3RequestContext *requestContext,
+ S3ResponseHandler *handler, void *callbackData)
{
- return S3StatusOK;
}
diff --git a/src/request.c b/src/request.c
index e0c57e9..9b4df4f 100644
--- a/src/request.c
+++ b/src/request.c
@@ -185,7 +185,7 @@ static size_t curl_header_func(void *ptr, size_t size, size_t nmemb, void *data)
return len;
}
// Copy name in
- S3MetaHeader *metaHeader =
+ S3NameValue *metaHeader =
&(request->responseMetaHeaders
[request->responseHeaders.metaHeadersCount++]);
metaHeader->name = &(request->responseMetaHeaderStrings
@@ -224,7 +224,7 @@ static S3Status errorXmlCallback(const char *elementPath, const char *data,
} while (0)
#define RESET_FIELD(requestField, errorField) \
- request->s3Error. errorField = request-> requestField;
+ request->s3ErrorDetails. errorField = request-> requestField;
if (!strcmp(elementPath, "Error")) {
@@ -251,8 +251,63 @@ static S3Status errorXmlCallback(const char *elementPath, const char *data,
// ignore it
return S3StatusOK;
}
- // OK, it's an unknown error element ... pass these back?
- // xxx todo
+ // It's an unknown error element. First try to find it in the
+ // existing set of unknown error elements.
+ const char *elementName = &(elementPath[sizeof("Error/") - 1]);
+ int i;
+ for (i = 0; i < request->s3ErrorDetails.extraDetailsCount; i++) {
+ if (!strcmp(elementName, request->s3ErrorExtraDetails[i].name)) {
+ // Found it.
+ break;
+ }
+ }
+
+ // If none matched ...
+ if (i == request->s3ErrorDetails.extraDetailsCount) {
+ // If we already are at the maximum number that we can accept,
+ // punt on this one
+ if (request->s3ErrorDetails.extraDetailsCount ==
+ sizeof(request->s3ErrorExtraDetails)) {
+ // It won't fit. Ignore it.
+ return S3StatusOK;
+ }
+ // OK, we got a new one
+ request->s3ErrorExtraDetailsValuesLens[i] = 0;
+ request->s3ErrorDetails.extraDetailsCount++;
+ request->s3ErrorExtraDetails[i].name =
+ &(request->s3ErrorExtraDetailsNames
+ [request->s3ErrorExtraDetailsNamesLen]);
+ request->s3ErrorExtraDetails[i].value =
+ request->s3ErrorExtraDetailsValues[i];
+ }
+
+ int elementNameLen = strlen(elementName);
+
+ // Copy the name in
+ int copied = snprintf
+ (&(request->s3ErrorExtraDetailsNames
+ [request->s3ErrorExtraDetailsNamesLen]),
+ sizeof(request->s3ErrorExtraDetailsNames) -
+ request->s3ErrorExtraDetailsNamesLen - 1, "%s", elementName);
+
+ // Add in the copied amount
+ request->s3ErrorExtraDetailsNamesLen += (copied + 1);
+
+ // If the element name didn't fit, ignore this element. Note that
+ // this leaves the partially copied name in the buffer. This is as
+ // desired because we don't want to leave the window open for another
+ // shorter element that comes later to get in.
+ if (copied < elementNameLen) {
+ return S3StatusOK;
+ }
+
+ // Copy the value in
+ request->s3ErrorExtraDetailsValuesLens[i] +=
+ snprintf(&(request->s3ErrorExtraDetailsValues[i]
+ [request->s3ErrorExtraDetailsValuesLens[i]]),
+ sizeof(request->s3ErrorExtraDetailsValues[i]) -
+ request->s3ErrorExtraDetailsValuesLens[i] - 1,
+ "%.*s", dataLen, data);
}
return S3StatusOK;
@@ -273,22 +328,26 @@ static size_t curl_write_func(void *ptr, size_t size, size_t nmemb, void *data)
(request->httpResponseCode > 299)) {
// If we haven't set up for reading an error yet, do so
if (!request->errorXmlParserInitialized) {
- request->errorXmlParserInitialized = 1;
// Set up the simplexml parser
if (simplexml_initialize
(&(request->errorXmlParser),
&errorXmlCallback, request) != S3StatusOK) {
return 0;
}
+ request->errorXmlParserInitialized = 1;
// Set up the S3Error that we will be returning
request->s3ErrorCodeLen = 0;
- request->s3Error.message = 0;
+ request->s3ErrorDetails.message = 0;
request->s3ErrorMessageLen = 0;
- request->s3Error.resource = 0;
+ request->s3ErrorDetails.resource = 0;
request->s3ErrorResourceLen = 0;
- request->s3Error.furtherDetails = 0;
+ request->s3ErrorDetails.furtherDetails = 0;
request->s3ErrorFurtherDetailsLen = 0;
+ request->s3ErrorDetails.extraDetailsCount = 0;
+ request->s3ErrorDetails.extraDetails =
+ request->s3ErrorExtraDetails;
+ request->s3ErrorExtraDetailsNamesLen = 0;
}
// Now put the data into the xml parser
@@ -977,6 +1036,10 @@ static void request_destroy(Request *request)
curl_easy_cleanup(request->curl);
+ if (request->errorXmlParserInitialized) {
+ simplexml_deinitialize(&(request->errorXmlParser));
+ }
+
free(request);
}
@@ -1001,6 +1064,10 @@ static S3Status request_initialize(Request *request,
else {
request->used = 1;
}
+
+ // Request status is initialized to no error, will be updated whenever
+ // an error occurs
+ request->status = S3StatusOK;
// This must be done before any error is returned
request->headers = 0;
@@ -1160,31 +1227,36 @@ void request_api_deinitialize()
}
-S3Status request_perform(RequestParams *params, S3RequestContext *context)
+void request_perform(RequestParams *params, S3RequestContext *context)
{
Request *request;
S3Status status;
+#define return_status(status) \
+ (*(params->handler->completeCallback)) \
+ (status, 0, 0, params->callbackData); \
+ return
+
// Validate the bucket name
if (params->bucketName &&
((status = S3_validate_bucket_name(params->bucketName,
params->uriStyle)) != S3StatusOK)) {
- return status;
+ return_status(status);
}
// Compose the amz headers
if ((status = compose_amz_headers(params)) != S3StatusOK) {
- return status;
+ return_status(status);
}
// Compose standard headers
if ((status = compose_standard_headers(params)) != S3StatusOK) {
- return status;
+ return_status(status);
}
// URL encode the key
if ((status = encode_key(params)) != S3StatusOK) {
- return status;
+ return_status(status);
}
// Compute the canonicalized amz headers
@@ -1195,27 +1267,28 @@ S3Status request_perform(RequestParams *params, S3RequestContext *context)
// Compose Authorization header
if ((status = compose_auth_header(params)) != S3StatusOK) {
- return status;
+ return_status(status);
}
// Get an initialized Request structure now
if ((status = request_get(params, &request)) != S3StatusOK) {
- return status;
+ return_status(status);
}
// If a RequestContext was provided, add the request to the curl multi
if (context) {
switch (curl_multi_add_handle(context->curlm, request->curl)) {
case CURLM_OK:
- return S3StatusOK;
+ return_status(S3StatusOK);
default:
request_release(request);
// xxx todo - more specific errors
- return S3StatusFailure;
+ return_status(S3StatusFailure);
}
}
// Else, perform the request immediately
else {
+ S3Status status;
switch (curl_easy_perform(request->curl)) {
case CURLE_OK:
status = S3StatusOK;
@@ -1228,7 +1301,6 @@ S3Status request_perform(RequestParams *params, S3RequestContext *context)
// Finish the request, ensuring that all callbacks have been made, and
// also releases the request
request_finish(request, status);
- return S3StatusOK;
}
}
@@ -1237,90 +1309,100 @@ void request_finish(Request *request, S3Status status)
{
request_headers_done(request);
- // Convert the error status string into a code
- if (request->errorXmlParserInitialized) {
- if (request->s3ErrorCodeLen) {
+ if (status == S3StatusOK) {
+ // Convert the error status string into a code
+ if (request->errorXmlParserInitialized) {
+ if (request->s3ErrorCodeLen) {
#define HANDLE_CODE(name) \
- do { \
- if (!strcmp(request->s3ErrorCode, #name)) { \
- request->s3Error.code = S3ErrorCode##name; \
- goto code_set; \
- } \
- } while (0)
-
- HANDLE_CODE(AccessDenied);
- HANDLE_CODE(AccountProblem);
- HANDLE_CODE(AmbiguousGrantByEmailAddress);
- HANDLE_CODE(BadDigest);
- HANDLE_CODE(BucketAlreadyExists);
- HANDLE_CODE(BucketAlreadyOwnedByYou);
- HANDLE_CODE(BucketNotEmpty);
- HANDLE_CODE(CredentialsNotSupported);
- HANDLE_CODE(CrossLocationLoggingProhibited);
- HANDLE_CODE(EntityTooSmall);
- HANDLE_CODE(EntityTooLarge);
- HANDLE_CODE(ExpiredToken);
- HANDLE_CODE(IncompleteBody);
- HANDLE_CODE(IncorrectNumberOfFilesInPostRequest);
- HANDLE_CODE(InlineDataTooLarge);
- HANDLE_CODE(InternalError);
- HANDLE_CODE(InvalidAccessKeyId);
- HANDLE_CODE(InvalidAddressingHeader);
- HANDLE_CODE(InvalidArgument);
- HANDLE_CODE(InvalidBucketName);
- HANDLE_CODE(InvalidDigest);
- HANDLE_CODE(InvalidLocationConstraint);
- HANDLE_CODE(InvalidPayer);
- HANDLE_CODE(InvalidPolicyDocument);
- HANDLE_CODE(InvalidRange);
- HANDLE_CODE(InvalidSecurity);
- HANDLE_CODE(InvalidSOAPRequest);
- HANDLE_CODE(InvalidStorageClass);
- HANDLE_CODE(InvalidTargetBucketForLogging);
- HANDLE_CODE(InvalidToken);
- HANDLE_CODE(InvalidURI);
- HANDLE_CODE(KeyTooLong);
- HANDLE_CODE(MalformedACLError);
- HANDLE_CODE(MalformedXML);
- HANDLE_CODE(MaxMessageLengthExceeded);
- HANDLE_CODE(MaxPostPreDataLengthExceededError);
- HANDLE_CODE(MetadataTooLarge);
- HANDLE_CODE(MethodNotAllowed);
- HANDLE_CODE(MissingAttachment);
- HANDLE_CODE(MissingContentLength);
- HANDLE_CODE(MissingSecurityElement);
- HANDLE_CODE(MissingSecurityHeader);
- HANDLE_CODE(NoLoggingStatusForKey);
- HANDLE_CODE(NoSuchBucket);
- HANDLE_CODE(NoSuchKey);
- HANDLE_CODE(NotImplemented);
- HANDLE_CODE(NotSignedUp);
- HANDLE_CODE(OperationAborted);
- HANDLE_CODE(PermanentRedirect);
- HANDLE_CODE(PreconditionFailed);
- HANDLE_CODE(Redirect);
- HANDLE_CODE(RequestIsNotMultiPartContent);
- HANDLE_CODE(RequestTimeout);
- HANDLE_CODE(RequestTimeTooSkewed);
- HANDLE_CODE(RequestTorrentOfBucketError);
- HANDLE_CODE(SignatureDoesNotMatch);
- HANDLE_CODE(SlowDown);
- HANDLE_CODE(TemporaryRedirect);
- HANDLE_CODE(TokenRefreshRequired);
- HANDLE_CODE(TooManyBuckets);
- HANDLE_CODE(UnexpectedContent);
- HANDLE_CODE(UnresolvableGrantByEmailAddress);
- HANDLE_CODE(UserKeyMustBeSpecified);
- }
+ do { \
+ if (!strcmp(request->s3ErrorCode, #name)) { \
+ request->status = S3StatusError##name; \
+ goto code_set; \
+ } \
+ } while (0)
+
+ HANDLE_CODE(AccessDenied);
+ HANDLE_CODE(AccountProblem);
+ HANDLE_CODE(AmbiguousGrantByEmailAddress);
+ HANDLE_CODE(BadDigest);
+ HANDLE_CODE(BucketAlreadyExists);
+ HANDLE_CODE(BucketAlreadyOwnedByYou);
+ HANDLE_CODE(BucketNotEmpty);
+ HANDLE_CODE(CredentialsNotSupported);
+ HANDLE_CODE(CrossLocationLoggingProhibited);
+ HANDLE_CODE(EntityTooSmall);
+ HANDLE_CODE(EntityTooLarge);
+ HANDLE_CODE(ExpiredToken);
+ HANDLE_CODE(IncompleteBody);
+ HANDLE_CODE(IncorrectNumberOfFilesInPostRequest);
+ HANDLE_CODE(InlineDataTooLarge);
+ HANDLE_CODE(InternalError);
+ HANDLE_CODE(InvalidAccessKeyId);
+ HANDLE_CODE(InvalidAddressingHeader);
+ HANDLE_CODE(InvalidArgument);
+ HANDLE_CODE(InvalidBucketName);
+ HANDLE_CODE(InvalidDigest);
+ HANDLE_CODE(InvalidLocationConstraint);
+ HANDLE_CODE(InvalidPayer);
+ HANDLE_CODE(InvalidPolicyDocument);
+ HANDLE_CODE(InvalidRange);
+ HANDLE_CODE(InvalidSecurity);
+ HANDLE_CODE(InvalidSOAPRequest);
+ HANDLE_CODE(InvalidStorageClass);
+ HANDLE_CODE(InvalidTargetBucketForLogging);
+ HANDLE_CODE(InvalidToken);
+ HANDLE_CODE(InvalidURI);
+ HANDLE_CODE(KeyTooLong);
+ HANDLE_CODE(MalformedACLError);
+ HANDLE_CODE(MalformedXML);
+ HANDLE_CODE(MaxMessageLengthExceeded);
+ HANDLE_CODE(MaxPostPreDataLengthExceededError);
+ HANDLE_CODE(MetadataTooLarge);
+ HANDLE_CODE(MethodNotAllowed);
+ HANDLE_CODE(MissingAttachment);
+ HANDLE_CODE(MissingContentLength);
+ HANDLE_CODE(MissingSecurityElement);
+ HANDLE_CODE(MissingSecurityHeader);
+ HANDLE_CODE(NoLoggingStatusForKey);
+ HANDLE_CODE(NoSuchBucket);
+ HANDLE_CODE(NoSuchKey);
+ HANDLE_CODE(NotImplemented);
+ HANDLE_CODE(NotSignedUp);
+ HANDLE_CODE(OperationAborted);
+ HANDLE_CODE(PermanentRedirect);
+ HANDLE_CODE(PreconditionFailed);
+ HANDLE_CODE(Redirect);
+ HANDLE_CODE(RequestIsNotMultiPartContent);
+ HANDLE_CODE(RequestTimeout);
+ HANDLE_CODE(RequestTimeTooSkewed);
+ HANDLE_CODE(RequestTorrentOfBucketError);
+ HANDLE_CODE(SignatureDoesNotMatch);
+ HANDLE_CODE(SlowDown);
+ HANDLE_CODE(TemporaryRedirect);
+ HANDLE_CODE(TokenRefreshRequired);
+ HANDLE_CODE(TooManyBuckets);
+ HANDLE_CODE(UnexpectedContent);
+ HANDLE_CODE(UnresolvableGrantByEmailAddress);
+ HANDLE_CODE(UserKeyMustBeSpecified);
+ }
- request->s3Error.code = 0;
+ request->status = S3StatusErrorUnknown;
+ }
+ }
+ else {
+ request->status = status;
}
code_set:
+ if (request->s3ErrorDetails.extraDetailsCount) {
+ request->s3ErrorDetails.extraDetails =
+ request->s3ErrorExtraDetails;
+ }
+
(*(request->completeCallback))
- (status, request->httpResponseCode,
- request->errorXmlParserInitialized ? &(request->s3Error) : 0,
+ (request->status, request->httpResponseCode,
+ request->errorXmlParserInitialized ? &(request->s3ErrorDetails) : 0,
request->callbackData);
request_release(request);
diff --git a/src/s3.c b/src/s3.c
index eb3b8a8..5739f92 100644
--- a/src/s3.c
+++ b/src/s3.c
@@ -53,7 +53,7 @@ static const char *secretAccessKeyG = 0;
// Request results, saved as globals -----------------------------------------
static int statusG = 0, httpResponseCodeG = 0;
-static S3Error *errorG = 0;
+static S3ErrorDetails *errorG = 0;
// Option prefixes -----------------------------------------------------------
@@ -122,6 +122,39 @@ static void S3_init()
}
+static void printError()
+{
+ if (statusG < S3StatusErrorAccessDenied) {
+ fprintf(stderr, "ERROR: %s\n", S3_get_status_name(statusG));
+ }
+ else {
+ fprintf(stderr, "ERROR: S3 returned an unexpected error:\n");
+ fprintf(stderr, " HTTP Code: %d\n", httpResponseCodeG);
+ fprintf(stderr, " S3 Error: %s\n", S3_get_status_name(statusG));
+ if (errorG) {
+ if (errorG->message) {
+ fprintf(stderr, " Message: %s\n", errorG->message);
+ }
+ if (errorG->resource) {
+ fprintf(stderr, " Resource: %s\n", errorG->resource);
+ }
+ if (errorG->furtherDetails) {
+ fprintf(stderr, " Further Details: %s\n",
+ errorG->furtherDetails);
+ }
+ if (errorG->extraDetailsCount) {
+ printf(" Extra Details:\n");
+ int i;
+ for (i = 0; i < errorG->extraDetailsCount; i++) {
+ printf(" %s: %s\n", errorG->extraDetails[i].name,
+ errorG->extraDetails[i].value);
+ }
+ }
+ }
+ }
+}
+
+
static void usageExit()
{
fprintf(stderr,
@@ -221,7 +254,7 @@ static S3Status responseHeadersCallback(const S3ResponseHeaders *headers,
// This callback does the same thing for every request type: saves the status
// and error stuff in global variables
static void responseCompleteCallback(S3Status status, int httpResponseCode,
- S3Error *error, void *callbackData)
+ S3ErrorDetails *error, void *callbackData)
{
statusG = status;
httpResponseCodeG = httpResponseCode;
@@ -251,20 +284,11 @@ static void list_service()
&listServiceCallback
};
- S3Status status = S3_list_service(protocolG, accessKeyIdG,
- secretAccessKeyG, 0,
- &listServiceHandler, 0);
+ S3_list_service(protocolG, accessKeyIdG, secretAccessKeyG, 0,
+ &listServiceHandler, 0);
- if (status != S3StatusOK) {
- fprintf(stderr, "ERROR: Failed to send request: %d\n", status);
- }
- else if (statusG != S3StatusOK) {
- fprintf(stderr, "ERROR: Failed to complete request: %d\n",
- statusG);
- }
- else if (httpResponseCodeG != 200) {
- fprintf(stderr, "ERROR: S3 returned error: %d\n",
- httpResponseCodeG);
+ if (statusG != S3StatusOK) {
+ printError();
}
S3_deinitialize();
@@ -296,58 +320,32 @@ static void test_bucket(int argc, char **argv, int optind)
};
char locationConstraint[64];
- S3Status status = S3_test_bucket(protocolG, accessKeyIdG, secretAccessKeyG,
- bucketName, sizeof(locationConstraint),
- locationConstraint, 0,
- &responseHandler, 0);
+ S3_test_bucket(protocolG, accessKeyIdG, secretAccessKeyG, bucketName,
+ sizeof(locationConstraint), locationConstraint, 0,
+ &responseHandler, 0);
- if (status != S3StatusOK) {
- fprintf(stderr, "ERROR: Failed to send request: %d\n", status);
- }
- else if (statusG != S3StatusOK) {
- fprintf(stderr, "ERROR: Failed to complete request: %d\n",
- statusG);
- }
- else if (httpResponseCodeG == 200) {
- printf("Bucket '%s' exists", bucketName);
+ switch (statusG) {
+ case S3StatusOK:
// bucket exists
+ printf("Bucket '%s' exists", bucketName);
if (locationConstraint[0]) {
printf(" in location %s\n", locationConstraint);
}
else {
printf(".\n");
}
- }
- else if (httpResponseCodeG == 404) {
+ break;
+ case S3StatusErrorNoSuchBucket:
// bucket does not exist
printf("Bucket '%s' does not exist.\n", bucketName);
- }
- else if (httpResponseCodeG == 403) {
- if (errorG && (errorG->code == S3ErrorCodeAccessDenied)) {
- // bucket exists, but no access
- printf("Bucket '%s' exists, but is not accessible.\n", bucketName);
- }
- else {
- fprintf(stderr, "ERROR: S3 returned error:\n");
- fprintf(stderr, " HTTP Response Code: %d\n", httpResponseCodeG);
- if (errorG) {
- fprintf(stderr, " S3 Error Code: %d\n", errorG->code);
- if (errorG->message) {
- fprintf(stderr, " S3 Message: %s\n", errorG->message);
- }
- if (errorG->resource) {
- fprintf(stderr, " S3 Resource: %s\n", errorG->resource);
- }
- if (errorG->furtherDetails) {
- fprintf(stderr, " S3 Resource: %s\n",
- errorG->furtherDetails);
- }
- }
- }
- }
- else {
- fprintf(stderr, "ERROR: S3 returned error: %d\n",
- httpResponseCodeG);
+ break;
+ case S3StatusErrorAccessDenied:
+ // bucket exists, but no access
+ printf("Bucket '%s' exists, but is not accessible.\n", bucketName);
+ break;
+ default:
+ printError();
+ break;
}
S3_deinitialize();
@@ -407,21 +405,11 @@ static void create_bucket(int argc, char **argv, int optind)
&responseHeadersCallback, &responseCompleteCallback
};
- S3Status status = S3_create_bucket(protocolG, accessKeyIdG,
- secretAccessKeyG, bucketName, cannedAcl,
- locationConstraint, 0,
- &responseHandler, 0);
+ S3_create_bucket(protocolG, accessKeyIdG, secretAccessKeyG, bucketName,
+ cannedAcl, locationConstraint, 0, &responseHandler, 0);
- if (status != S3StatusOK) {
- fprintf(stderr, "ERROR: Failed to send request: %d\n", status);
- }
- else if (statusG != S3StatusOK) {
- fprintf(stderr, "ERROR: Failed to complete request: %d\n",
- statusG);
- }
- else if (httpResponseCodeG != 200) {
- fprintf(stderr, "ERROR: S3 returned error: %d\n",
- httpResponseCodeG);
+ if (statusG != S3StatusOK) {
+ printError();
}
S3_deinitialize();
@@ -448,20 +436,11 @@ static void delete_bucket(int argc, char **argv, int optind)
&responseHeadersCallback, &responseCompleteCallback
};
- S3Status status = S3_delete_bucket(protocolG, accessKeyIdG,
- secretAccessKeyG, bucketName, 0,
- &responseHandler, 0);
+ S3_delete_bucket(protocolG, accessKeyIdG, secretAccessKeyG, bucketName, 0,
+ &responseHandler, 0);
- if (status != S3StatusOK) {
- fprintf(stderr, "ERROR: Failed to send request: %d\n", status);
- }
- else if (statusG != S3StatusOK) {
- fprintf(stderr, "ERROR: Failed to complete request: %d\n",
- statusG);
- }
- else if (httpResponseCodeG != 204) {
- fprintf(stderr, "ERROR: S3 returned error: %d\n",
- httpResponseCodeG);
+ if (statusG != S3StatusOK) {
+ printError();
}
S3_deinitialize();
diff --git a/src/service.c b/src/service.c
index 3350661..4f72dbc 100644
--- a/src/service.c
+++ b/src/service.c
@@ -52,10 +52,10 @@ static size_t write_callback(void *data, size_t s, size_t n, void *req)
}
-S3Status S3_list_service(S3Protocol protocol, const char *accessKeyId,
- const char *secretAccessKey,
- S3RequestContext *requestContext,
- S3ListServiceHandler *handler, void *callbackData)
+void S3_list_service(S3Protocol protocol, const char *accessKeyId,
+ const char *secretAccessKey,
+ S3RequestContext *requestContext,
+ S3ListServiceHandler *handler, void *callbackData)
{
// Set up the RequestParams
RequestParams params =
@@ -79,7 +79,7 @@ S3Status S3_list_service(S3Protocol protocol, const char *accessKeyId,
};
// Perform the request
- return request_perform(&params, requestContext);
+ request_perform(&params, requestContext);
}