dpl_status_t dpl_s3_get_authorization_v2_params(const dpl_req_t *req, dpl_dict_t *query_params, struct tm UNUSED *tm) { dpl_status_t ret; char expires_str[128], resource_ue[DPL_URL_LENGTH(strlen(req->resource)) + 1]; snprintf(expires_str, sizeof(expires_str), "%ld", req->expires); if ('/' != req->resource[0]) { resource_ue[0] = '/'; dpl_url_encode_no_slashes(req->resource, resource_ue + 1); } else dpl_url_encode_no_slashes(req->resource, resource_ue); ret = dpl_dict_add(query_params, "AWSAccessKeyId", req->ctx->access_key, 0); if (ret != DPL_SUCCESS) return DPL_FAILURE; { char sign_str[1024]; u_int sign_len; char hmac_str[1024]; u_int hmac_len; char base64_str[1024]; u_int base64_len; char base64_ue_str[1024]; const char *method = dpl_method_str(req->method); ret = dpl_s3_make_signature_v2(req->ctx, method, req->bucket, resource_ue, NULL, expires_str, NULL, sign_str, sizeof (sign_str), &sign_len); if (ret != DPL_SUCCESS) return DPL_FAILURE; DPRINTF("%s\n", sign_str); hmac_len = dpl_hmac_sha1(req->ctx->secret_key, strlen(req->ctx->secret_key), sign_str, sign_len, hmac_str); base64_len = dpl_base64_encode((const u_char *) hmac_str, hmac_len, (u_char *) base64_str); base64_str[base64_len] = 0; dpl_url_encode(base64_str, base64_ue_str); ret = dpl_dict_add(query_params, "Signature", base64_ue_str, 0); if (ret != DPL_SUCCESS) return DPL_FAILURE; } ret = dpl_dict_add(query_params, "Expires", expires_str, 0); if (ret != DPL_SUCCESS) return DPL_FAILURE; return DPL_SUCCESS; }
dpl_status_t dpl_s3_add_authorization_v2_to_headers(const dpl_req_t *req, dpl_dict_t *headers, const dpl_dict_t UNUSED *query_params, struct tm UNUSED *tm) { int ret; const char *method = dpl_method_str(req->method); char resource_ue[DPL_URL_LENGTH(strlen(req->resource)) + 1]; char sign_str[1024]; u_int sign_len; char hmac_str[1024]; u_int hmac_len; char base64_str[1024]; u_int base64_len; char auth_str[1024]; char *date_str = NULL; //resource if ('/' != req->resource[0]) { resource_ue[0] = '/'; dpl_url_encode_no_slashes(req->resource, resource_ue + 1); } else dpl_url_encode_no_slashes(req->resource, resource_ue); date_str = dpl_dict_get_value(headers, "x-amz-date"); if (date_str == NULL) date_str = dpl_dict_get_value(headers, "Date"); ret = dpl_s3_make_signature_v2(req->ctx, method, req->bucket, resource_ue, req->subresource, date_str, headers, sign_str, sizeof (sign_str), &sign_len); if (DPL_SUCCESS != ret) return DPL_FAILURE; /* DPL_TRACE(req->ctx, DPL_TRACE_REQ, "stringtosign=%.*s", sign_len, sign_str); */ hmac_len = dpl_hmac_sha1(req->ctx->secret_key, strlen(req->ctx->secret_key), sign_str, sign_len, hmac_str); base64_len = dpl_base64_encode((const u_char *) hmac_str, hmac_len, (u_char *) base64_str); snprintf(auth_str, sizeof (auth_str), "AWS %s:%.*s", req->ctx->access_key, base64_len, base64_str); return dpl_dict_add(headers, "Authorization", auth_str, 0); }
static dpl_status_t create_canonical_request(const dpl_req_t *req, dpl_dict_t *headers, dpl_vec_t *canonical_headers, dpl_vec_t *canonical_params, char *p, unsigned int len) { // Method { const char *method = dpl_method_str(req->method); DPL_APPEND_STR(method); DPL_APPEND_STR("\n"); } // Resource if (req->resource != NULL) { char resource_ue[DPL_URL_LENGTH(strlen(req->resource)) + 1]; if (req->resource[0] != '/') DPL_APPEND_STR("/"); dpl_url_encode_no_slashes(req->resource, resource_ue); DPL_APPEND_STR(resource_ue); } DPL_APPEND_STR("\n"); // Query params { int item; for (item = 0; item < canonical_params->n_items; item++) { dpl_dict_var_t *param = (dpl_dict_var_t *) dpl_vec_get(canonical_params, item); if (param == NULL) continue; if (item > 0) DPL_APPEND_STR("&"); DPL_APPEND_STR(param->key); DPL_APPEND_STR("="); DPL_APPEND_STR(dpl_sbuf_get_str(param->val->string)); } DPL_APPEND_STR("\n"); } // Headers if (canonical_headers != NULL) { int item; char *c; dpl_dict_var_t *header; for (item = 0; item < canonical_headers->n_items; item++) { header = (dpl_dict_var_t *) dpl_vec_get(canonical_headers, item); if (header == NULL) continue; for (c = header->key; *c != '\0'; c++) DPL_APPEND_CHAR(tolower(*c)); DPL_APPEND_STR(":"); DPL_APPEND_STR(dpl_sbuf_get_str(header->val->string)); DPL_APPEND_STR("\n"); } DPL_APPEND_STR("\n"); for (item = 0; item < canonical_headers->n_items; item++) { header = (dpl_dict_var_t *) dpl_vec_get(canonical_headers, item); if (header == NULL) continue; if (item > 0) DPL_APPEND_STR(";"); for (c = header->key; *c != '\0'; c++) DPL_APPEND_CHAR(tolower(*c)); } DPL_APPEND_STR("\n"); } else { DPL_APPEND_STR("host:"); DPL_APPEND_STR(req->host); DPL_APPEND_STR("\n\n"); DPL_APPEND_STR("host\n"); } // Hashed payload if (headers != NULL) { char *value = dpl_dict_get_value(headers, "x-amz-content-sha256"); if (value != NULL) DPL_APPEND_STR(value); } else DPL_APPEND_STR("UNSIGNED-PAYLOAD"); return DPL_SUCCESS; }
/** * build headers from request * * @param req * @param headersp * * @return */ dpl_status_t dpl_s3_req_build(const dpl_req_t *req, dpl_s3_req_mask_t req_mask, dpl_dict_t **headersp) { dpl_dict_t *headers = NULL; int ret, ret2; const char *method = dpl_method_str(req->method); char resource_ue[DPL_URL_LENGTH(strlen(req->resource) + (req->subresource ? strlen(req->subresource) : 0)) + 1]; DPL_TRACE(req->ctx, DPL_TRACE_REQ, "req_build method=%s bucket=%s resource=%s subresource=%s", method, req->bucket, req->resource, req->subresource); //resource if ('/' != req->resource[0]) { resource_ue[0] = '/'; dpl_url_encode(req->resource, resource_ue + 1); } else { resource_ue[0] = '/'; //some servers do not like encoded slash dpl_url_encode(req->resource + 1, resource_ue + 1); } // Append subresource if (req->subresource) { dpl_url_encode("?", resource_ue + strlen(resource_ue)); dpl_url_encode(req->subresource, resource_ue + strlen(resource_ue)); } headers = dpl_dict_new(13); if (NULL == headers) { ret = DPL_ENOMEM; goto end; } /* * per method headers */ if (DPL_METHOD_GET == req->method || DPL_METHOD_HEAD == req->method) { if (req->range_enabled) { ret2 = dpl_add_range_to_headers(&req->range, headers); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } ret2 = add_conditions_to_headers(&req->condition, headers, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } else if (DPL_METHOD_PUT == req->method || DPL_METHOD_POST == req->method) { char buf[64]; if (NULL != req->cache_control) { ret2 = dpl_dict_add(headers, "Cache-Control", req->cache_control, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (NULL != req->content_disposition) { ret2 = dpl_dict_add(headers, "Content-Disposition", req->content_disposition, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (NULL != req->content_encoding) { ret2 = dpl_dict_add(headers, "Content-Encoding", req->content_encoding, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (req->behavior_flags & DPL_BEHAVIOR_MD5) { MD5_CTX ctx; u_char digest[MD5_DIGEST_LENGTH]; char b64_digest[DPL_BASE64_LENGTH(MD5_DIGEST_LENGTH) + 1]; u_int b64_digest_len; if (!req->data_enabled) { ret = DPL_EINVAL; goto end; } MD5_Init(&ctx); MD5_Update(&ctx, req->data_buf, req->data_len); MD5_Final(digest, &ctx); b64_digest_len = dpl_base64_encode(digest, MD5_DIGEST_LENGTH, (u_char *) b64_digest); b64_digest[b64_digest_len] = 0; ret2 = dpl_dict_add(headers, "Content-MD5", b64_digest, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (req->data_enabled) { snprintf(buf, sizeof (buf), "%u", req->data_len); ret2 = dpl_dict_add(headers, "Content-Length", buf, 0); if (DPL_SUCCESS != ret2) { ret = DPL_ENOMEM; goto end; } } if (NULL != req->content_type) { ret2 = dpl_dict_add(headers, "Content-Type", req->content_type, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (req->behavior_flags & DPL_BEHAVIOR_EXPECT) { ret2 = dpl_dict_add(headers, "Expect", "100-continue", 0); if (DPL_SUCCESS != ret2) { ret = DPL_ENOMEM; goto end; } } if (DPL_CANNED_ACL_UNDEF != req->canned_acl) { char *str; str = dpl_canned_acl_str(req->canned_acl); if (NULL == str) { ret = DPL_FAILURE; goto end; } ret2 = dpl_dict_add(headers, "x-amz-acl", str, 0); if (DPL_SUCCESS != ret2) { ret = DPL_ENOMEM; goto end; } } ret2 = add_metadata_to_headers(req->metadata, headers); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (DPL_STORAGE_CLASS_UNDEF != req->storage_class) { char *str; str = dpl_storage_class_str(req->storage_class); if (NULL == str) { ret = DPL_FAILURE; goto end; } ret2 = dpl_dict_add(headers, "x-amz-storage-class", str, 0); if (DPL_SUCCESS != ret2) { ret = DPL_ENOMEM; goto end; } } /* * copy */ if (req_mask & DPL_S3_REQ_COPY) { ret2 = add_source_to_headers(req, headers); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (DPL_COPY_DIRECTIVE_UNDEF != req->copy_directive) { char *str; switch (req->copy_directive) { case DPL_COPY_DIRECTIVE_UNDEF: case DPL_COPY_DIRECTIVE_COPY: case DPL_COPY_DIRECTIVE_LINK: case DPL_COPY_DIRECTIVE_SYMLINK: case DPL_COPY_DIRECTIVE_MOVE: case DPL_COPY_DIRECTIVE_MKDENT: case DPL_COPY_DIRECTIVE_RMDENT: case DPL_COPY_DIRECTIVE_MVDENT: ret = DPL_ENOTSUPP; goto end; case DPL_COPY_DIRECTIVE_METADATA_REPLACE: str = "REPLACE"; break ; } ret2 = dpl_dict_add(headers, "x-amz-metadata-directive", str, 0); if (DPL_SUCCESS != ret2) { ret = DPL_ENOMEM; goto end; } } ret2 = add_conditions_to_headers(&req->copy_source_condition, headers, 1); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } } else if (DPL_METHOD_DELETE == req->method) { //XXX todo x-amz-mfa } else { ret = DPL_EINVAL; goto end; } /* * common headers */ if (req->behavior_flags & DPL_BEHAVIOR_KEEP_ALIVE) { ret2 = dpl_dict_add(headers, "Connection", "Keep-Alive", 0); if (DPL_SUCCESS != ret2) { ret = DPL_ENOMEM; goto end; } } ret2 = add_date_to_headers(headers); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (NULL != headersp) { *headersp = headers; headers = NULL; //consume it } ret = DPL_SUCCESS; end: if (NULL != headers) dpl_dict_free(headers); return ret; }
/** * generate HTTP request * * @param req * @param headers * @param query_params * @param buf * @param len * @param lenp * * @return */ dpl_status_t dpl_req_gen_http_request(dpl_ctx_t *ctx, dpl_req_t *req, const dpl_dict_t *headers, const dpl_dict_t *query_params, char *buf, int len, unsigned int *lenp) { int ret; char *p; char *method = dpl_method_str(req->method); char *resource_ue = NULL; DPL_TRACE(req->ctx, DPL_TRACE_REQ, "req_gen_http_request resource=%s", req->resource); p = buf; //resource if (NULL != req->resource) { resource_ue = malloc(DPL_URL_LENGTH(strlen(req->resource)) + 3); if (resource_ue == NULL) { ret = DPL_ENOMEM; goto end; } if (ctx->url_encoding) { if (ctx->encode_slashes) { resource_ue[0] = '/'; if (*req->resource != '/') dpl_url_encode(req->resource, resource_ue + 1); else dpl_url_encode(req->resource + 1, resource_ue + 1); } else { if (*req->resource != '/') { resource_ue[0] = '/'; dpl_url_encode_no_slashes(req->resource, resource_ue + 1); } else dpl_url_encode_no_slashes(req->resource, resource_ue); } } else { if (*req->resource != '/') { resource_ue[0] = '/'; strcpy(resource_ue + 1, req->resource); } else strcpy(resource_ue, req->resource); } } //method DPL_APPEND_STR(method); DPL_APPEND_STR(" "); if (resource_ue != NULL) DPL_APPEND_STR(resource_ue); //subresource and query params if (NULL != req->subresource || NULL != query_params) DPL_APPEND_STR("?"); if (NULL != req->subresource) DPL_APPEND_STR(req->subresource); if (NULL != query_params) { int bucket; dpl_dict_var_t *var; int amp = 0; if (NULL != req->subresource) amp = 1; for (bucket = 0;bucket < query_params->n_buckets;bucket++) { for (var = query_params->buckets[bucket];var;var = var->prev) { if (amp) DPL_APPEND_STR("&"); DPL_APPEND_STR(var->key); DPL_APPEND_STR("="); assert(var->val->type == DPL_VALUE_STRING); DPL_APPEND_STR(dpl_sbuf_get_str(var->val->string)); amp = 1; } } } DPL_APPEND_STR(" "); //version DPL_APPEND_STR("HTTP/1.1"); DPL_APPEND_STR("\r\n"); //headers if (NULL != headers) { int bucket; dpl_dict_var_t *var; for (bucket = 0;bucket < headers->n_buckets;bucket++) { for (var = headers->buckets[bucket];var;var = var->prev) { assert(var->val->type == DPL_VALUE_STRING); DPL_TRACE(req->ctx, DPL_TRACE_REQ, "header='%s' value='%s'", var->key, dpl_sbuf_get_str(var->val->string)); DPL_APPEND_STR(var->key); DPL_APPEND_STR(": "); DPL_APPEND_STR(dpl_sbuf_get_str(var->val->string)); DPL_APPEND_STR("\r\n"); } } } //final crlf managed by caller if (NULL != lenp) *lenp = (p - buf); ret = DPL_SUCCESS; end: if (NULL != resource_ue) free(resource_ue); return ret; }
/** * build headers from request * * @param req * @param headersp * * @return */ dpl_status_t dpl_cdmi_req_build(const dpl_req_t *req, dpl_dict_t **headersp, char **body_strp, int *body_lenp) { dpl_dict_t *headers = NULL; int ret, ret2; char *method = dpl_method_str(req->method); json_object *body_obj = NULL; char *body_str = NULL; int body_len = 0; char buf[256]; DPL_TRACE(req->ctx, DPL_TRACE_REQ, "req_build method=%s bucket=%s resource=%s subresource=%s", method, req->bucket, req->resource, req->subresource); headers = dpl_dict_new(13); if (NULL == headers) { ret = DPL_ENOMEM; goto end; } /* * per method headers */ if (DPL_METHOD_GET == req->method) { //XXX ranges, conditions switch (req->object_type) { case DPL_FTYPE_UNDEF: //do nothing break ; case DPL_FTYPE_ANY: ret2 = dpl_dict_add(headers, "Accept", DPL_CDMI_CONTENT_TYPE_ANY, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } break ; case DPL_FTYPE_REG: ret2 = dpl_dict_add(headers, "Accept", DPL_CDMI_CONTENT_TYPE_OBJECT, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } break ; case DPL_FTYPE_DIR: ret2 = dpl_dict_add(headers, "Accept", DPL_CDMI_CONTENT_TYPE_CONTAINER, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } break ; case DPL_FTYPE_CAP: ret2 = dpl_dict_add(headers, "Accept", DPL_CDMI_CONTENT_TYPE_CAPABILITY, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } break ; } } else if (DPL_METHOD_PUT == req->method || DPL_METHOD_POST == req->method) { body_obj = json_object_new_object(); if (NULL == body_obj) { ret = DPL_ENOMEM; goto end; } if (NULL != req->cache_control) { ret2 = dpl_dict_add(headers, "Cache-Control", req->cache_control, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (NULL != req->content_disposition) { ret2 = dpl_dict_add(headers, "Content-Disposition", req->content_disposition, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (NULL != req->content_encoding) { ret2 = dpl_dict_add(headers, "Content-Encoding", req->content_encoding, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (!(req->behavior_flags & DPL_BEHAVIOR_HTTP_COMPAT)) { ret2 = add_metadata_to_json_body(req->metadata, body_obj); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (NULL != req->chunk) { ret2 = add_data_to_json_body(req->chunk, body_obj); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } pthread_mutex_lock(&req->ctx->lock); body_str = (char *) json_object_to_json_string(body_obj); pthread_mutex_unlock(&req->ctx->lock); if (NULL == body_str) { ret = DPL_ENOMEM; goto end; } body_len = strlen(body_str); snprintf(buf, sizeof (buf), "%u", body_len); ret2 = dpl_dict_add(headers, "Content-Length", buf, 0); if (DPL_SUCCESS != ret2) { ret = DPL_ENOMEM; goto end; } } else { snprintf(buf, sizeof (buf), "%u", req->chunk->len); ret2 = dpl_dict_add(headers, "Content-Length", buf, 0); if (DPL_SUCCESS != ret2) { ret = DPL_ENOMEM; goto end; } } if (req->behavior_flags & DPL_BEHAVIOR_EXPECT) { ret2 = dpl_dict_add(headers, "Expect", "100-continue", 0); if (DPL_SUCCESS != ret2) { ret = DPL_ENOMEM; goto end; } } switch (req->object_type) { case DPL_FTYPE_UNDEF: //do nothing break ; case DPL_FTYPE_ANY: //error ? break ; case DPL_FTYPE_REG: ret2 = dpl_dict_add(headers, "Content-Type", DPL_CDMI_CONTENT_TYPE_OBJECT, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } break ; case DPL_FTYPE_DIR: ret2 = dpl_dict_add(headers, "Content-Type", DPL_CDMI_CONTENT_TYPE_CONTAINER, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } break ; case DPL_FTYPE_CAP: ret2 = dpl_dict_add(headers, "Content-Type", DPL_CDMI_CONTENT_TYPE_CAPABILITY, 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } break ; } } else if (DPL_METHOD_DELETE == req->method) { } else { ret = DPL_EINVAL; goto end; } /* * common headers */ if (!(req->behavior_flags & DPL_BEHAVIOR_HTTP_COMPAT)) { ret2 = dpl_dict_add(headers, "X-CDMI-Specification-Version", "1.0.1", 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (req->behavior_flags & DPL_BEHAVIOR_VIRTUAL_HOSTING) { char host[1024]; snprintf(host, sizeof (host), "%s.%s", req->bucket, req->ctx->host); ret2 = dpl_dict_add(headers, "Host", host, 0); if (DPL_SUCCESS != ret2) { ret = DPL_ENOMEM; goto end; } } else { ret2 = dpl_dict_add(headers, "Host", req->ctx->host, 0); if (DPL_SUCCESS != ret2) { ret = DPL_ENOMEM; goto end; } } if (req->behavior_flags & DPL_BEHAVIOR_KEEP_ALIVE) { ret2 = dpl_dict_add(headers, "Connection", "keep-alive", 0); if (DPL_SUCCESS != ret2) { ret = DPL_ENOMEM; goto end; } } ret2 = add_authorization_to_headers(req, headers); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (NULL != body_strp) { if (NULL == body_str) { *body_strp = NULL; } else { *body_strp = strdup(body_str); if (NULL == body_strp) { ret = DPL_ENOMEM; goto end; } } } if (NULL != body_lenp) *body_lenp = body_len; if (NULL != headersp) { *headersp = headers; headers = NULL; //consume it } ret = DPL_SUCCESS; end: if (NULL != body_obj) json_object_put(body_obj); if (NULL != headers) dpl_dict_free(headers); return ret; }