--- /dev/null
+/** **************************************************************************
+ * response_headers_handler.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 <ctype.h>
+#include <string.h>
+#include "response_headers_handler.h"
+
+
+void response_headers_handler_initialize(ResponseHeadersHandler *handler)
+{
+ handler->responseProperties.requestId = 0;
+ handler->responseProperties.requestId2 = 0;
+ handler->responseProperties.contentType = 0;
+ handler->responseProperties.contentLength = 0;
+ handler->responseProperties.server = 0;
+ handler->responseProperties.eTag = 0;
+ handler->responseProperties.lastModified = -1;
+ handler->responseProperties.metaDataCount = 0;
+ handler->responseProperties.metaData = 0;
+ handler->done = 0;
+ string_multibuffer_initialize(handler->responsePropertyStrings);
+ string_multibuffer_initialize(handler->responseMetaDataStrings);
+}
+
+
+void response_headers_handler_add(ResponseHeadersHandler *handler,
+ char *header, int len)
+{
+ S3ResponseProperties *responseProperties = &(handler->responseProperties);
+ char *end = &(header[len]);
+
+ // Curl might call back the header function after the body has been
+ // received, for 'chunked encoded' contents. We don't handle this as of
+ // yet, and it's not clear that it would ever be useful.
+ if (handler->done) {
+ return;
+ }
+
+ // If we've already filled up the response headers, ignore this data.
+ // This sucks, but it shouldn't happen - S3 should not be sending back
+ // really long headers.
+ if (handler->responsePropertyStringsSize ==
+ (sizeof(handler->responsePropertyStrings) - 1)) {
+ return;
+ }
+
+ // It should not be possible to have a header line less than 3 long
+ if (len < 3) {
+ return;
+ }
+
+ // Skip whitespace at beginning of header; there never should be any,
+ // but just to be safe
+ while (is_blank(*header)) {
+ header++;
+ }
+
+ // The header must end in \r\n, so skip back over it, and also over any
+ // trailing whitespace
+ end -= 3;
+ while ((end > header) && is_blank(*end)) {
+ end--;
+ }
+ if (!is_blank(*end)) {
+ end++;
+ }
+
+ if (end == header) {
+ // totally bogus
+ return;
+ }
+
+ *end = 0;
+
+ // Find the colon to split the header up
+ char *c = header;
+ while (*c && (*c != ':')) {
+ c++;
+ }
+
+ int namelen = c - header;
+
+ // Now walk c past the colon
+ c++;
+ // Now skip whitespace to the beginning of the value
+ while (is_blank(*c)) {
+ c++;
+ }
+
+ int valuelen = (end - c) + 1, fit;
+
+ if (!strncmp(header, "x-amz-request-id", namelen)) {
+ responseProperties->requestId =
+ string_multibuffer_current(handler->responsePropertyStrings);
+ string_multibuffer_add(handler->responsePropertyStrings, c,
+ valuelen, fit);
+ }
+ else if (!strncmp(header, "x-amz-id-2", namelen)) {
+ responseProperties->requestId2 =
+ string_multibuffer_current(handler->responsePropertyStrings);
+ string_multibuffer_add(handler->responsePropertyStrings, c,
+ valuelen, fit);
+ }
+ else if (!strncmp(header, "Content-Type", namelen)) {
+ responseProperties->contentType =
+ string_multibuffer_current(handler->responsePropertyStrings);
+ string_multibuffer_add(handler->responsePropertyStrings, c,
+ valuelen, fit);
+ }
+ else if (!strncmp(header, "Content-Length", namelen)) {
+ handler->responseProperties.contentLength = 0;
+ while (*c) {
+ handler->responseProperties.contentLength *= 10;
+ handler->responseProperties.contentLength += (*c++ - '0');
+ }
+ }
+ else if (!strncmp(header, "Server", namelen)) {
+ responseProperties->server =
+ string_multibuffer_current(handler->responsePropertyStrings);
+ string_multibuffer_add(handler->responsePropertyStrings, c,
+ valuelen, fit);
+ }
+ else if (!strncmp(header, "ETag", namelen)) {
+ responseProperties->eTag =
+ string_multibuffer_current(handler->responsePropertyStrings);
+ string_multibuffer_add(handler->responsePropertyStrings, c,
+ valuelen, fit);
+ }
+ else if (!strncmp(header, S3_METADATA_HEADER_NAME_PREFIX,
+ sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1)) {
+ // Make sure there is room for another x-amz-meta header
+ if (handler->responseProperties.metaDataCount ==
+ sizeof(handler->responseMetaData)) {
+ return;
+ }
+ // Copy the name in
+ char *metaName = &(header[sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1]);
+ int metaNameLen =
+ (namelen - (sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1));
+ char *copiedName =
+ string_multibuffer_current(handler->responseMetaDataStrings);
+ string_multibuffer_add(handler->responseMetaDataStrings, metaName,
+ metaNameLen, fit);
+ if (!fit) {
+ return;
+ }
+
+ // Copy the value in
+ char *copiedValue =
+ string_multibuffer_current(handler->responseMetaDataStrings);
+ string_multibuffer_add(handler->responseMetaDataStrings,
+ c, valuelen, fit);
+ if (!fit) {
+ return;
+ }
+
+ if (!handler->responseProperties.metaDataCount) {
+ handler->responseProperties.metaData =
+ handler->responseMetaData;
+ }
+
+ S3NameValue *metaHeader =
+ &(handler->responseMetaData
+ [handler->responseProperties.metaDataCount++]);
+ metaHeader->name = copiedName;
+ metaHeader->value = copiedValue;
+ }
+}
+
+
+void response_headers_handler_done(ResponseHeadersHandler *handler, CURL *curl)
+{
+ // Now get the last modification time from curl, since it's easiest to let
+ // curl parse it
+ time_t lastModified;
+ if (curl_easy_getinfo
+ (curl, CURLINFO_FILETIME, &lastModified) == CURLE_OK) {
+ handler->responseProperties.lastModified = lastModified;
+ }
+
+ handler->done = 1;
+}