diff options
author | Bryan Ischo <bryan@ischo.com> | 2008-07-07 03:58:15 +0000 |
---|---|---|
committer | Bryan Ischo <bryan@ischo.com> | 2008-07-07 03:58:15 +0000 |
commit | e15c6d4cf1310f3016a3aca6f298b0c0f3986982 (patch) | |
tree | 2893840b4c0c592d550e57d298d612b81989c4f9 | |
parent | 07ce7e4123f0ec6b88e65269c6edd69e13b4935c (diff) | |
download | ceph-libs3-e15c6d4cf1310f3016a3aca6f298b0c0f3986982.tar.gz |
* Reorganized errors; it's all simpler now
-rw-r--r-- | inc/libs3.h | 304 | ||||
-rw-r--r-- | inc/private.h | 28 | ||||
-rw-r--r-- | src/acl.c | 36 | ||||
-rw-r--r-- | src/bucket.c | 47 | ||||
-rw-r--r-- | src/general.c | 106 | ||||
-rw-r--r-- | src/object.c | 53 | ||||
-rw-r--r-- | src/request.c | 272 | ||||
-rw-r--r-- | src/s3.c | 147 | ||||
-rw-r--r-- | src/service.c | 10 |
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 @@ -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(¶ms, requestContext); + request_perform(¶ms, 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(¶ms, requestContext); + request_perform(¶ms, 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(¶ms, requestContext); + request_perform(¶ms, 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); @@ -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(¶ms, requestContext); + request_perform(¶ms, requestContext); } |