+
+
+static size_t
+s3_internal_write_func(void *ptr, size_t size, size_t nmemb, void * stream)
+{
+ S3InternalData *data = (S3InternalData *) stream;
+ size_t bytes_saved;
+
+ if (!data->headers_done)
+ return size*nmemb;
+
+ /* call write on internal buffer (if not full) */
+ if (data->int_write_done) {
+ bytes_saved = 0;
+ } else {
+ bytes_saved = s3_buffer_write_func(ptr, size, nmemb, &data->resp_buf);
+ if (!bytes_saved) {
+ data->int_write_done = TRUE;
+ }
+ }
+ /* call write on user buffer */
+ if (data->write_func) {
+ return data->write_func(ptr, size, nmemb, data->write_data);
+ } else {
+ return bytes_saved;
+ }
+}
+
+static void
+s3_internal_reset_func(void * stream)
+{
+ S3InternalData *data = (S3InternalData *) stream;
+
+ s3_buffer_reset_func(&data->resp_buf);
+ data->headers_done = FALSE;
+ data->int_write_done = FALSE;
+ data->etag = NULL;
+ if (data->reset_func) {
+ data->reset_func(data->write_data);
+ }
+}
+
+static size_t
+s3_internal_header_func(void *ptr, size_t size, size_t nmemb, void * stream)
+{
+ static const char *final_header = "\r\n";
+ time_t remote_time_in_sec,local_time;
+ char *header;
+ regmatch_t pmatch[2];
+ S3InternalData *data = (S3InternalData *) stream;
+
+ header = g_strndup((gchar *) ptr, (gsize) size*nmemb);
+
+ if (header[strlen(header)-1] == '\n')
+ header[strlen(header)-1] = '\0';
+ if (header[strlen(header)-1] == '\r')
+ header[strlen(header)-1] = '\0';
+ if (!s3_regexec_wrap(&etag_regex, header, 2, pmatch, 0))
+ data->etag = find_regex_substring(header, pmatch[1]);
+ if (!s3_regexec_wrap(&x_auth_token_regex, header, 2, pmatch, 0))
+ data->hdl->x_auth_token = find_regex_substring(header, pmatch[1]);
+
+ if (!s3_regexec_wrap(&x_storage_url_regex, header, 2, pmatch, 0))
+ data->hdl->x_storage_url = find_regex_substring(header, pmatch[1]);
+
+ if (!s3_regexec_wrap(&content_type_regex, header, 2, pmatch, 0))
+ data->hdl->content_type = find_regex_substring(header, pmatch[1]);
+
+ if (strlen(header) == 0)
+ data->headers_done = TRUE;
+ if (g_str_equal(final_header, header))
+ data->headers_done = TRUE;
+ if (g_str_equal("\n", header))
+ data->headers_done = TRUE;
+
+ /* If date header is found */
+ if (!s3_regexec_wrap(&date_sync_regex, header, 2, pmatch, 0)){
+ char *date = find_regex_substring(header, pmatch[1]);
+
+ /* Remote time is always in GMT: RFC 2616 */
+ /* both curl_getdate and time operate in UTC, so no timezone math is necessary */
+ if ( (remote_time_in_sec = curl_getdate(date, NULL)) < 0 ){
+ g_debug("Error: Conversion of remote time to seconds failed.");
+ data->hdl->time_offset_with_s3 = 0;
+ }else{
+ local_time = time(NULL);
+ /* Offset time */
+ data->hdl->time_offset_with_s3 = remote_time_in_sec - local_time;
+
+ if (data->hdl->verbose)
+ g_debug("Time Offset (remote - local) :%ld",(long)data->hdl->time_offset_with_s3);
+ }
+
+ g_free(date);
+ }
+
+ g_free(header);
+ return size*nmemb;
+}
+
+static gboolean
+compile_regexes(void)
+{
+#ifdef HAVE_REGEX_H
+
+ /* using POSIX regular expressions */
+ struct {const char * str; int flags; regex_t *regex;} regexes[] = {
+ {"<Code>[[:space:]]*([^<]*)[[:space:]]*</Code>", REG_EXTENDED | REG_ICASE, &error_name_regex},
+ {"^ETag:[[:space:]]*\"([^\"]+)\"[[:space:]]*$", REG_EXTENDED | REG_ICASE | REG_NEWLINE, &etag_regex},
+ {"^X-Auth-Token:[[:space:]]*([^ ]+)[[:space:]]*$", REG_EXTENDED | REG_ICASE | REG_NEWLINE, &x_auth_token_regex},
+ {"^X-Storage-Url:[[:space:]]*([^ ]+)[[:space:]]*$", REG_EXTENDED | REG_ICASE | REG_NEWLINE, &x_storage_url_regex},
+ {"^Content-Type:[[:space:]]*([^ ;]+).*$", REG_EXTENDED | REG_ICASE | REG_NEWLINE, &content_type_regex},
+ {"<Message>[[:space:]]*([^<]*)[[:space:]]*</Message>", REG_EXTENDED | REG_ICASE, &message_regex},
+ {"^[a-z0-9](-*[a-z0-9]){2,62}$", REG_EXTENDED | REG_NOSUB, &subdomain_regex},
+ {"(/>)|(>([^<]*)</LocationConstraint>)", REG_EXTENDED | REG_ICASE, &location_con_regex},
+ {"^Date:(.*)\r",REG_EXTENDED | REG_ICASE | REG_NEWLINE, &date_sync_regex},
+ {"\"access_token\" : \"([^\"]*)\",", REG_EXTENDED | REG_ICASE | REG_NEWLINE, &access_token_regex},
+ {"\"expires_in\" : (.*)", REG_EXTENDED | REG_ICASE | REG_NEWLINE, &expires_in_regex},
+ {"\"details\": \"([^\"]*)\",", REG_EXTENDED | REG_ICASE | REG_NEWLINE, &details_regex},
+ {"\"code\": (.*),", REG_EXTENDED | REG_ICASE | REG_NEWLINE, &code_regex},
+ {NULL, 0, NULL}
+ };
+ char regmessage[1024];
+ int i;
+ int reg_result;
+
+ for (i = 0; regexes[i].str; i++) {
+ reg_result = regcomp(regexes[i].regex, regexes[i].str, regexes[i].flags);
+ if (reg_result != 0) {
+ regerror(reg_result, regexes[i].regex, regmessage, sizeof(regmessage));
+ g_error(_("Regex error: %s"), regmessage);
+ return FALSE;
+ }
+ }
+#else /* ! HAVE_REGEX_H */
+ /* using PCRE via GLib */
+ struct {const char * str; int flags; regex_t *regex;} regexes[] = {
+ {"<Code>\\s*([^<]*)\\s*</Code>",
+ G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
+ &error_name_regex},
+ {"^ETag:\\s*\"([^\"]+)\"\\s*$",
+ G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
+ &etag_regex},
+ {"^X-Auth-Token:\\s*([^ ]+)\\s*$",
+ G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
+ &x_auth_token_regex},
+ {"^X-Storage-Url:\\s*([^ ]+)\\s*$",
+ G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
+ &x_storage_url_regex},
+ {"^Content-Type:\\s*([^ ]+)\\s*$",
+ G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
+ &content_type_regex},
+ {"<Message>\\s*([^<]*)\\s*</Message>",
+ G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
+ &message_regex},
+ {"^[a-z0-9]((-*[a-z0-9])|(\\.[a-z0-9])){2,62}$",
+ G_REGEX_OPTIMIZE | G_REGEX_NO_AUTO_CAPTURE,
+ &subdomain_regex},
+ {"(/>)|(>([^<]*)</LocationConstraint>)",
+ G_REGEX_CASELESS,
+ &location_con_regex},
+ {"^Date:(.*)\\r",
+ G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
+ &date_sync_regex},
+ {"\"access_token\" : \"([^\"]*)\"",
+ G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
+ &access_token_regex},
+ {"\"expires_n\" : (.*)",
+ G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
+ &expires_in_regex},
+ {"\"details\" : \"([^\"]*)\"",
+ G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
+ &details_regex},
+ {"\"code\" : (.*)",
+ G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
+ &code_regex},
+ {NULL, 0, NULL}
+ };
+ int i;
+ GError *err = NULL;
+
+ for (i = 0; regexes[i].str; i++) {
+ *(regexes[i].regex) = g_regex_new(regexes[i].str, regexes[i].flags, 0, &err);
+ if (err) {
+ g_error(_("Regex error: %s"), err->message);
+ g_error_free(err);
+ return FALSE;
+ }
+ }
+#endif
+ return TRUE;
+}