baa206ea4d091c1b7b1989451637a64d54d86612
[bluesky.git] / libs3-1.4 / src / error_parser.c
1 /** **************************************************************************
2  * error_parser.c
3  * 
4  * Copyright 2008 Bryan Ischo <bryan@ischo.com>
5  * 
6  * This file is part of libs3.
7  * 
8  * libs3 is free software: you can redistribute it and/or modify it under the
9  * terms of the GNU General Public License as published by the Free Software
10  * Foundation, version 3 of the License.
11  *
12  * In addition, as a special exception, the copyright holders give
13  * permission to link the code of this library and its programs with the
14  * OpenSSL library, and distribute linked combinations including the two.
15  *
16  * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY
17  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19  * details.
20  *
21  * You should have received a copy of the GNU General Public License version 3
22  * along with libs3, in a file named COPYING.  If not, see
23  * <http://www.gnu.org/licenses/>.
24  *
25  ************************************************************************** **/
26
27 #include <string.h>
28 #include "error_parser.h"
29
30
31 static S3Status errorXmlCallback(const char *elementPath, const char *data,
32                                  int dataLen, void *callbackData)
33 {
34     // We ignore end of element callbacks because we don't care about them
35     if (!data) {
36         return S3StatusOK;
37     }
38
39     ErrorParser *errorParser = (ErrorParser *) callbackData;
40
41     int fit;
42
43     if (!strcmp(elementPath, "Error")) {
44         // Ignore, this is the Error element itself, we only care about subs
45     }
46     else if (!strcmp(elementPath, "Error/Code")) {
47         string_buffer_append(errorParser->code, data, dataLen, fit);
48     }
49     else if (!strcmp(elementPath, "Error/Message")) {
50         string_buffer_append(errorParser->message, data, dataLen, fit);
51         errorParser->s3ErrorDetails.message = errorParser->message;
52     }
53     else if (!strcmp(elementPath, "Error/Resource")) {
54         string_buffer_append(errorParser->resource, data, dataLen, fit);
55         errorParser->s3ErrorDetails.resource = errorParser->resource;
56     }
57     else if (!strcmp(elementPath, "Error/FurtherDetails")) {
58         string_buffer_append(errorParser->furtherDetails, data, dataLen, fit);
59         errorParser->s3ErrorDetails.furtherDetails = 
60             errorParser->furtherDetails;
61     }
62     else {
63         if (strncmp(elementPath, "Error/", sizeof("Error/") - 1)) {
64             // If for some weird reason it's not within the Error element,
65             // ignore it
66             return S3StatusOK;
67         }
68         // It's an unknown error element.  See if it matches the most
69         // recent error element.
70         const char *elementName = &(elementPath[sizeof("Error/") - 1]);
71         if (errorParser->s3ErrorDetails.extraDetailsCount && 
72             !strcmp(elementName, errorParser->s3ErrorDetails.extraDetails
73                     [errorParser->s3ErrorDetails.extraDetailsCount - 1].name)) {
74             // Append the value
75             string_multibuffer_append(errorParser->extraDetailsNamesValues,
76                                       data, dataLen, fit);
77             // If it didn't fit, remove this extra
78             if (!fit) {
79                 errorParser->s3ErrorDetails.extraDetailsCount--;
80             }
81             return S3StatusOK;
82         }
83         // OK, must add another unknown error element, if it will fit.
84         if (errorParser->s3ErrorDetails.extraDetailsCount ==
85             sizeof(errorParser->extraDetails)) {
86             // Won't fit.  Ignore this one.
87             return S3StatusOK;
88         }
89         // Copy in the name and value
90         char *name = string_multibuffer_current
91             (errorParser->extraDetailsNamesValues);
92         int nameLen = strlen(elementName);
93         string_multibuffer_add(errorParser->extraDetailsNamesValues,
94                                elementName, nameLen, fit);
95         if (!fit) {
96             // Name didn't fit; ignore this one.
97             return S3StatusOK;
98         }
99         char *value = string_multibuffer_current
100             (errorParser->extraDetailsNamesValues);
101         string_multibuffer_add(errorParser->extraDetailsNamesValues,
102                                data, dataLen, fit);
103         if (!fit) {
104             // Value didn't fit; ignore this one.
105             return S3StatusOK;
106         }
107         S3NameValue *nv = 
108             &(errorParser->extraDetails
109               [errorParser->s3ErrorDetails.extraDetailsCount++]);
110         nv->name = name;
111         nv->value = value;
112     }
113
114     return S3StatusOK;
115 }
116
117
118 void error_parser_initialize(ErrorParser *errorParser)
119 {
120     errorParser->s3ErrorDetails.message = 0;
121     errorParser->s3ErrorDetails.resource = 0;
122     errorParser->s3ErrorDetails.furtherDetails = 0;
123     errorParser->s3ErrorDetails.extraDetailsCount = 0;
124     errorParser->s3ErrorDetails.extraDetails = errorParser->extraDetails;
125     errorParser->errorXmlParserInitialized = 0;
126     string_buffer_initialize(errorParser->code);
127     string_buffer_initialize(errorParser->message);
128     string_buffer_initialize(errorParser->resource);
129     string_buffer_initialize(errorParser->furtherDetails);
130     string_multibuffer_initialize(errorParser->extraDetailsNamesValues);
131 }
132
133
134 S3Status error_parser_add(ErrorParser *errorParser, char *buffer,
135                           int bufferSize)
136 {
137     if (!errorParser->errorXmlParserInitialized) {
138         simplexml_initialize(&(errorParser->errorXmlParser), &errorXmlCallback,
139                              errorParser);
140         errorParser->errorXmlParserInitialized = 1;
141     }
142
143     return simplexml_add(&(errorParser->errorXmlParser), buffer, bufferSize);
144 }
145
146
147 void error_parser_convert_status(ErrorParser *errorParser, S3Status *status)
148 {
149     // Convert the error status string into a code
150     if (!errorParser->codeLen) {
151         return;
152     }
153
154 #define HANDLE_CODE(name)                                       \
155     do {                                                        \
156         if (!strcmp(errorParser->code, #name)) {                \
157             *status = S3StatusError##name;                      \
158             goto code_set;                                      \
159         }                                                       \
160     } while (0)
161     
162     HANDLE_CODE(AccessDenied);
163     HANDLE_CODE(AccountProblem);
164     HANDLE_CODE(AmbiguousGrantByEmailAddress);
165     HANDLE_CODE(BadDigest);
166     HANDLE_CODE(BucketAlreadyExists);
167     HANDLE_CODE(BucketAlreadyOwnedByYou);
168     HANDLE_CODE(BucketNotEmpty);
169     HANDLE_CODE(CredentialsNotSupported);
170     HANDLE_CODE(CrossLocationLoggingProhibited);
171     HANDLE_CODE(EntityTooSmall);
172     HANDLE_CODE(EntityTooLarge);
173     HANDLE_CODE(ExpiredToken);
174     HANDLE_CODE(IncompleteBody);
175     HANDLE_CODE(IncorrectNumberOfFilesInPostRequest);
176     HANDLE_CODE(InlineDataTooLarge);
177     HANDLE_CODE(InternalError);
178     HANDLE_CODE(InvalidAccessKeyId);
179     HANDLE_CODE(InvalidAddressingHeader);
180     HANDLE_CODE(InvalidArgument);
181     HANDLE_CODE(InvalidBucketName);
182     HANDLE_CODE(InvalidDigest);
183     HANDLE_CODE(InvalidLocationConstraint);
184     HANDLE_CODE(InvalidPayer);
185     HANDLE_CODE(InvalidPolicyDocument);
186     HANDLE_CODE(InvalidRange);
187     HANDLE_CODE(InvalidSecurity);
188     HANDLE_CODE(InvalidSOAPRequest);
189     HANDLE_CODE(InvalidStorageClass);
190     HANDLE_CODE(InvalidTargetBucketForLogging);
191     HANDLE_CODE(InvalidToken);
192     HANDLE_CODE(InvalidURI);
193     HANDLE_CODE(KeyTooLong);
194     HANDLE_CODE(MalformedACLError);
195     HANDLE_CODE(MalformedXML);
196     HANDLE_CODE(MaxMessageLengthExceeded);
197     HANDLE_CODE(MaxPostPreDataLengthExceededError);
198     HANDLE_CODE(MetadataTooLarge);
199     HANDLE_CODE(MethodNotAllowed);
200     HANDLE_CODE(MissingAttachment);
201     HANDLE_CODE(MissingContentLength);
202     HANDLE_CODE(MissingSecurityElement);
203     HANDLE_CODE(MissingSecurityHeader);
204     HANDLE_CODE(NoLoggingStatusForKey);
205     HANDLE_CODE(NoSuchBucket);
206     HANDLE_CODE(NoSuchKey);
207     HANDLE_CODE(NotImplemented);
208     HANDLE_CODE(NotSignedUp);
209     HANDLE_CODE(OperationAborted);
210     HANDLE_CODE(PermanentRedirect);
211     HANDLE_CODE(PreconditionFailed);
212     HANDLE_CODE(Redirect);
213     HANDLE_CODE(RequestIsNotMultiPartContent);
214     HANDLE_CODE(RequestTimeout);
215     HANDLE_CODE(RequestTimeTooSkewed);
216     HANDLE_CODE(RequestTorrentOfBucketError);
217     HANDLE_CODE(SignatureDoesNotMatch);
218     HANDLE_CODE(SlowDown);
219     HANDLE_CODE(TemporaryRedirect);
220     HANDLE_CODE(TokenRefreshRequired);
221     HANDLE_CODE(TooManyBuckets);
222     HANDLE_CODE(UnexpectedContent);
223     HANDLE_CODE(UnresolvableGrantByEmailAddress);
224     HANDLE_CODE(UserKeyMustBeSpecified);
225     *status = S3StatusErrorUnknown;
226
227  code_set:
228
229     return;
230 }
231
232
233 // Always call this
234 void error_parser_deinitialize(ErrorParser *errorParser)
235 {
236     if (errorParser->errorXmlParserInitialized) {
237         simplexml_deinitialize(&(errorParser->errorXmlParser));
238     }
239 }