Include libs3 sources in the BlueSky tree.
[bluesky.git] / libs3-1.4 / src / response_headers_handler.c
diff --git a/libs3-1.4/src/response_headers_handler.c b/libs3-1.4/src/response_headers_handler.c
new file mode 100644 (file)
index 0000000..e506ea4
--- /dev/null
@@ -0,0 +1,205 @@
+/** **************************************************************************
+ * 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;
+}