STSStatus request_get(RequestParams* params, Request** requestReturn) { Request* request; STSStatus status; if (!(request = (Request*)malloc(sizeof(Request)))) { return STSStatusOutOfMemory; } request->headers = 0; if (!(request->curl = curl_easy_init())) { return STSStatusFailedToInitRequest; } if (STSStatusOK != (status = compose_uri(request->uri, sizeof(request->uri), &(params->commonContext)))) { curl_easy_cleanup(request->curl); free(request); return status; } if (STSStatusOK != (status = setup_curl(request, params))) { curl_easy_cleanup(request->curl); free(request); return status; } *requestReturn = request; return status; }
static S3Status request_get(const RequestParams *params, const RequestComputedValues *values, Request **reqReturn) { Request *request = 0; // Try to get one from the request stack. We hold the lock for the // shortest time possible here. pthread_mutex_lock(&requestStackMutexG); if (requestStackCountG) { request = requestStackG[--requestStackCountG]; } pthread_mutex_unlock(&requestStackMutexG); // If we got one, deinitialize it for re-use if (request) { request_deinitialize(request); } // Else there wasn't one available in the request stack, so create one else { if (!(request = (Request *) malloc(sizeof(Request)))) { return S3StatusOutOfMemory; } if (!(request->curl = curl_easy_init())) { free(request); return S3StatusFailedToInitializeRequest; } } // Initialize the request request->prev = 0; request->next = 0; // Request status is initialized to no error, will be updated whenever // an error occurs request->status = S3StatusOK; S3Status status; // Start out with no headers request->headers = 0; // Compute the URL if ((status = compose_uri (request->uri, sizeof(request->uri), &(params->bucketContext), values->urlEncodedKey, params->subResource, params->queryParams)) != S3StatusOK) { curl_easy_cleanup(request->curl); free(request); return status; } // Set all of the curl handle options if ((status = setup_curl(request, params, values)) != S3StatusOK) { curl_easy_cleanup(request->curl); free(request); return status; } request->propertiesCallback = params->propertiesCallback; request->toS3Callback = params->toS3Callback; request->toS3CallbackBytesRemaining = params->toS3CallbackTotalSize; request->fromS3Callback = params->fromS3Callback; request->completeCallback = params->completeCallback; request->callbackData = params->callbackData; response_headers_handler_initialize(&(request->responseHeadersHandler)); request->propertiesCallbackMade = 0; error_parser_initialize(&(request->errorParser)); *reqReturn = request; return S3StatusOK; }
S3Status S3_generate_authenticated_query_string (char *buffer, const S3BucketContext *bucketContext, const char *key, int64_t expires, const char *resource) { #define MAX_EXPIRES (((int64_t) 1 << 31) - 1) // S3 seems to only accept expiration dates up to the number of seconds // representably by a signed 32-bit integer if (expires < 0) { expires = MAX_EXPIRES; } else if (expires > MAX_EXPIRES) { expires = MAX_EXPIRES; } // xxx todo: rework this so that it can be incorporated into shared code // with request_perform(). It's really unfortunate that this code is not // shared with request_perform(). // URL encode the key char urlEncodedKey[S3_MAX_KEY_SIZE * 3]; if (key) { urlEncode(urlEncodedKey, key, strlen(key)); } else { urlEncodedKey[0] = 0; } // Compute canonicalized resource char canonicalizedResource[MAX_CANONICALIZED_RESOURCE_SIZE]; canonicalize_resource(bucketContext->bucketName, resource, urlEncodedKey, canonicalizedResource); // We allow for: // 17 bytes for HTTP-Verb + \n // 1 byte for empty Content-MD5 + \n // 1 byte for empty Content-Type + \n // 20 bytes for Expires + \n // 0 bytes for CanonicalizedAmzHeaders // CanonicalizedResource char signbuf[17 + 1 + 1 + 1 + 20 + sizeof(canonicalizedResource) + 1]; int len = 0; #define signbuf_append(format, ...) \ len += snprintf(&(signbuf[len]), sizeof(signbuf) - len, \ format, __VA_ARGS__) signbuf_append("%s\n", "GET"); // HTTP-Verb signbuf_append("%s\n", ""); // Content-MD5 signbuf_append("%s\n", ""); // Content-Type signbuf_append("%llu\n", (unsigned long long) expires); signbuf_append("%s", canonicalizedResource); // Generate an HMAC-SHA-1 of the signbuf unsigned char hmac[20]; HMAC_SHA1(hmac, (unsigned char *) bucketContext->secretAccessKey, strlen(bucketContext->secretAccessKey), (unsigned char *) signbuf, len); // Now base-64 encode the results char b64[((20 + 1) * 4) / 3]; int b64Len = base64Encode(hmac, 20, b64); // Now urlEncode that char signature[sizeof(b64) * 3]; urlEncode(signature, b64, b64Len); // Finally, compose the uri, with params: // ?AWSAccessKeyId=xxx[&Expires=]&Signature=xxx char queryParams[sizeof("AWSAccessKeyId=") + 20 + sizeof("&Expires=") + 20 + sizeof("&Signature=") + sizeof(signature) + 1]; sprintf(queryParams, "AWSAccessKeyId=%s&Expires=%ld&Signature=%s", bucketContext->accessKeyId, (long) expires, signature); return compose_uri(buffer, S3_MAX_AUTHENTICATED_QUERY_STRING_SIZE, bucketContext, urlEncodedKey, resource, queryParams); }