1 /** **************************************************************************
2 * response_headers_handler.c
4 * Copyright 2008 Bryan Ischo <bryan@ischo.com>
6 * This file is part of libs3.
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.
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.
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
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/>.
25 ************************************************************************** **/
29 #include "response_headers_handler.h"
32 void response_headers_handler_initialize(ResponseHeadersHandler *handler)
34 handler->responseProperties.requestId = 0;
35 handler->responseProperties.requestId2 = 0;
36 handler->responseProperties.contentType = 0;
37 handler->responseProperties.contentLength = 0;
38 handler->responseProperties.server = 0;
39 handler->responseProperties.eTag = 0;
40 handler->responseProperties.lastModified = -1;
41 handler->responseProperties.metaDataCount = 0;
42 handler->responseProperties.metaData = 0;
44 string_multibuffer_initialize(handler->responsePropertyStrings);
45 string_multibuffer_initialize(handler->responseMetaDataStrings);
49 void response_headers_handler_add(ResponseHeadersHandler *handler,
50 char *header, int len)
52 S3ResponseProperties *responseProperties = &(handler->responseProperties);
53 char *end = &(header[len]);
55 // Curl might call back the header function after the body has been
56 // received, for 'chunked encoded' contents. We don't handle this as of
57 // yet, and it's not clear that it would ever be useful.
62 // If we've already filled up the response headers, ignore this data.
63 // This sucks, but it shouldn't happen - S3 should not be sending back
64 // really long headers.
65 if (handler->responsePropertyStringsSize ==
66 (sizeof(handler->responsePropertyStrings) - 1)) {
70 // It should not be possible to have a header line less than 3 long
75 // Skip whitespace at beginning of header; there never should be any,
76 // but just to be safe
77 while (is_blank(*header)) {
81 // The header must end in \r\n, so skip back over it, and also over any
82 // trailing whitespace
84 while ((end > header) && is_blank(*end)) {
87 if (!is_blank(*end)) {
98 // Find the colon to split the header up
100 while (*c && (*c != ':')) {
104 int namelen = c - header;
106 // Now walk c past the colon
108 // Now skip whitespace to the beginning of the value
109 while (is_blank(*c)) {
113 int valuelen = (end - c) + 1, fit;
115 if (!strncmp(header, "x-amz-request-id", namelen)) {
116 responseProperties->requestId =
117 string_multibuffer_current(handler->responsePropertyStrings);
118 string_multibuffer_add(handler->responsePropertyStrings, c,
121 else if (!strncmp(header, "x-amz-id-2", namelen)) {
122 responseProperties->requestId2 =
123 string_multibuffer_current(handler->responsePropertyStrings);
124 string_multibuffer_add(handler->responsePropertyStrings, c,
127 else if (!strncmp(header, "Content-Type", namelen)) {
128 responseProperties->contentType =
129 string_multibuffer_current(handler->responsePropertyStrings);
130 string_multibuffer_add(handler->responsePropertyStrings, c,
133 else if (!strncmp(header, "Content-Length", namelen)) {
134 handler->responseProperties.contentLength = 0;
136 handler->responseProperties.contentLength *= 10;
137 handler->responseProperties.contentLength += (*c++ - '0');
140 else if (!strncmp(header, "Server", namelen)) {
141 responseProperties->server =
142 string_multibuffer_current(handler->responsePropertyStrings);
143 string_multibuffer_add(handler->responsePropertyStrings, c,
146 else if (!strncmp(header, "ETag", namelen)) {
147 responseProperties->eTag =
148 string_multibuffer_current(handler->responsePropertyStrings);
149 string_multibuffer_add(handler->responsePropertyStrings, c,
152 else if (!strncmp(header, S3_METADATA_HEADER_NAME_PREFIX,
153 sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1)) {
154 // Make sure there is room for another x-amz-meta header
155 if (handler->responseProperties.metaDataCount ==
156 sizeof(handler->responseMetaData)) {
160 char *metaName = &(header[sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1]);
162 (namelen - (sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1));
164 string_multibuffer_current(handler->responseMetaDataStrings);
165 string_multibuffer_add(handler->responseMetaDataStrings, metaName,
173 string_multibuffer_current(handler->responseMetaDataStrings);
174 string_multibuffer_add(handler->responseMetaDataStrings,
180 if (!handler->responseProperties.metaDataCount) {
181 handler->responseProperties.metaData =
182 handler->responseMetaData;
185 S3NameValue *metaHeader =
186 &(handler->responseMetaData
187 [handler->responseProperties.metaDataCount++]);
188 metaHeader->name = copiedName;
189 metaHeader->value = copiedValue;
194 void response_headers_handler_done(ResponseHeadersHandler *handler, CURL *curl)
196 // Now get the last modification time from curl, since it's easiest to let
199 if (curl_easy_getinfo
200 (curl, CURLINFO_FILETIME, &lastModified) == CURLE_OK) {
201 handler->responseProperties.lastModified = lastModified;