Include libs3 sources in the BlueSky tree.
[bluesky.git] / libs3-1.4 / src / error_parser.c
diff --git a/libs3-1.4/src/error_parser.c b/libs3-1.4/src/error_parser.c
new file mode 100644 (file)
index 0000000..baa206e
--- /dev/null
@@ -0,0 +1,239 @@
+/** **************************************************************************
+ * error_parser.c
+ * 
+ * Copyright 2008 Bryan Ischo <bryan@ischo.com>
+ * 
+ * This file is part of libs3.
+ * 
+ * libs3 is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3 of the License.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this library and its programs with the
+ * OpenSSL library, and distribute linked combinations including the two.
+ *
+ * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License version 3
+ * along with libs3, in a file named COPYING.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ ************************************************************************** **/
+
+#include <string.h>
+#include "error_parser.h"
+
+
+static S3Status errorXmlCallback(const char *elementPath, const char *data,
+                                 int dataLen, void *callbackData)
+{
+    // We ignore end of element callbacks because we don't care about them
+    if (!data) {
+        return S3StatusOK;
+    }
+
+    ErrorParser *errorParser = (ErrorParser *) callbackData;
+
+    int fit;
+
+    if (!strcmp(elementPath, "Error")) {
+        // Ignore, this is the Error element itself, we only care about subs
+    }
+    else if (!strcmp(elementPath, "Error/Code")) {
+        string_buffer_append(errorParser->code, data, dataLen, fit);
+    }
+    else if (!strcmp(elementPath, "Error/Message")) {
+        string_buffer_append(errorParser->message, data, dataLen, fit);
+        errorParser->s3ErrorDetails.message = errorParser->message;
+    }
+    else if (!strcmp(elementPath, "Error/Resource")) {
+        string_buffer_append(errorParser->resource, data, dataLen, fit);
+        errorParser->s3ErrorDetails.resource = errorParser->resource;
+    }
+    else if (!strcmp(elementPath, "Error/FurtherDetails")) {
+        string_buffer_append(errorParser->furtherDetails, data, dataLen, fit);
+        errorParser->s3ErrorDetails.furtherDetails = 
+            errorParser->furtherDetails;
+    }
+    else {
+        if (strncmp(elementPath, "Error/", sizeof("Error/") - 1)) {
+            // If for some weird reason it's not within the Error element,
+            // ignore it
+            return S3StatusOK;
+        }
+        // It's an unknown error element.  See if it matches the most
+        // recent error element.
+        const char *elementName = &(elementPath[sizeof("Error/") - 1]);
+        if (errorParser->s3ErrorDetails.extraDetailsCount && 
+            !strcmp(elementName, errorParser->s3ErrorDetails.extraDetails
+                    [errorParser->s3ErrorDetails.extraDetailsCount - 1].name)) {
+            // Append the value
+            string_multibuffer_append(errorParser->extraDetailsNamesValues,
+                                      data, dataLen, fit);
+            // If it didn't fit, remove this extra
+            if (!fit) {
+                errorParser->s3ErrorDetails.extraDetailsCount--;
+            }
+            return S3StatusOK;
+        }
+        // OK, must add another unknown error element, if it will fit.
+        if (errorParser->s3ErrorDetails.extraDetailsCount ==
+            sizeof(errorParser->extraDetails)) {
+            // Won't fit.  Ignore this one.
+            return S3StatusOK;
+        }
+        // Copy in the name and value
+        char *name = string_multibuffer_current
+            (errorParser->extraDetailsNamesValues);
+        int nameLen = strlen(elementName);
+        string_multibuffer_add(errorParser->extraDetailsNamesValues,
+                               elementName, nameLen, fit);
+        if (!fit) {
+            // Name didn't fit; ignore this one.
+            return S3StatusOK;
+        }
+        char *value = string_multibuffer_current
+            (errorParser->extraDetailsNamesValues);
+        string_multibuffer_add(errorParser->extraDetailsNamesValues,
+                               data, dataLen, fit);
+        if (!fit) {
+            // Value didn't fit; ignore this one.
+            return S3StatusOK;
+        }
+        S3NameValue *nv = 
+            &(errorParser->extraDetails
+              [errorParser->s3ErrorDetails.extraDetailsCount++]);
+        nv->name = name;
+        nv->value = value;
+    }
+
+    return S3StatusOK;
+}
+
+
+void error_parser_initialize(ErrorParser *errorParser)
+{
+    errorParser->s3ErrorDetails.message = 0;
+    errorParser->s3ErrorDetails.resource = 0;
+    errorParser->s3ErrorDetails.furtherDetails = 0;
+    errorParser->s3ErrorDetails.extraDetailsCount = 0;
+    errorParser->s3ErrorDetails.extraDetails = errorParser->extraDetails;
+    errorParser->errorXmlParserInitialized = 0;
+    string_buffer_initialize(errorParser->code);
+    string_buffer_initialize(errorParser->message);
+    string_buffer_initialize(errorParser->resource);
+    string_buffer_initialize(errorParser->furtherDetails);
+    string_multibuffer_initialize(errorParser->extraDetailsNamesValues);
+}
+
+
+S3Status error_parser_add(ErrorParser *errorParser, char *buffer,
+                          int bufferSize)
+{
+    if (!errorParser->errorXmlParserInitialized) {
+        simplexml_initialize(&(errorParser->errorXmlParser), &errorXmlCallback,
+                             errorParser);
+        errorParser->errorXmlParserInitialized = 1;
+    }
+
+    return simplexml_add(&(errorParser->errorXmlParser), buffer, bufferSize);
+}
+
+
+void error_parser_convert_status(ErrorParser *errorParser, S3Status *status)
+{
+    // Convert the error status string into a code
+    if (!errorParser->codeLen) {
+        return;
+    }
+
+#define HANDLE_CODE(name)                                       \
+    do {                                                        \
+        if (!strcmp(errorParser->code, #name)) {                \
+            *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);
+    *status = S3StatusErrorUnknown;
+
+ code_set:
+
+    return;
+}
+
+
+// Always call this
+void error_parser_deinitialize(ErrorParser *errorParser)
+{
+    if (errorParser->errorXmlParserInitialized) {
+        simplexml_deinitialize(&(errorParser->errorXmlParser));
+    }
+}