/** * check for Location header * * @param headers_returned * * @return the location * @return NULL if not found */ char * dpl_location(dpl_dict_t *headers_returned) { dpl_status_t ret; dpl_dict_var_t *var; ret = dpl_dict_get_lowered(headers_returned, "Location", &var); if (DPL_SUCCESS == ret) { assert(DPL_VALUE_STRING == var->val->type); return dpl_sbuf_get_str(var->val->string); } else { return NULL; } }
/** * check for Connection header * * @param headers_returned * * @return 1 if found * @return 0 if not found */ int dpl_connection_close(dpl_dict_t *headers_returned) { dpl_dict_var_t *var; int ret; if (NULL == headers_returned) return 1; //assume close ret = dpl_dict_get_lowered(headers_returned, "Connection", &var); if (DPL_SUCCESS != ret) { return 0; } if (NULL != var) { assert(var->val->type == DPL_VALUE_STRING); if (!strcasecmp(dpl_sbuf_get_str(var->val->string), "close")) return 1; } return 0; }
dpl_status_t dpl_cdmi_get(dpl_ctx_t *ctx, const char *bucket, const char *resource, const char *subresource, const dpl_option_t *option, dpl_ftype_t object_type, const dpl_condition_t *condition, const dpl_range_t *range, char **data_bufp, unsigned int *data_lenp, dpl_dict_t **metadatap, dpl_sysmd_t *sysmdp, char **locationp) { int ret, ret2; dpl_conn_t *conn = NULL; char header[dpl_header_size]; u_int header_len; struct iovec iov[10]; int n_iov = 0; int connection_close = 0; char *data_buf = NULL; u_int data_len; dpl_dict_t *headers_request = NULL; dpl_dict_t *headers_reply = NULL; dpl_req_t *req = NULL; int raw = 0; dpl_value_t *val = NULL; dpl_dict_var_t *var = NULL; dpl_dict_var_t *encoding = NULL; int value_len; int orig_len; char *orig_buf = NULL; dpl_cdmi_req_mask_t req_mask = 0u; char *location; DPL_TRACE(ctx, DPL_TRACE_BACKEND, ""); if (option) { if (option->mask & DPL_OPTION_HTTP_COMPAT) req_mask |= DPL_CDMI_REQ_HTTP_COMPAT; if (option->mask & DPL_OPTION_RAW) raw = 1; } req = dpl_req_new(ctx); if (NULL == req) { ret = DPL_ENOMEM; goto end; } dpl_req_set_method(req, DPL_METHOD_GET); if (NULL != bucket) { ret2 = dpl_req_set_bucket(req, bucket); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } ret2 = dpl_cdmi_req_set_resource(req, resource); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (NULL == subresource) { if (DPL_FTYPE_REG == object_type) { subresource = "valuetransferencoding"; } } if (NULL != subresource) { ret2 = dpl_req_set_subresource(req, subresource); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (NULL != condition) { dpl_req_set_condition(req, condition); } if (range) { ret2 = dpl_cdmi_req_add_range(req, req_mask, range); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } dpl_req_set_object_type(req, object_type); //build request ret2 = dpl_cdmi_req_build(req, 0, &headers_request, NULL, NULL); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } //contact default host dpl_req_rm_behavior(req, DPL_BEHAVIOR_VIRTUAL_HOSTING); ret2 = dpl_try_connect(ctx, req, &conn); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } ret2 = dpl_add_host_to_headers(req, headers_request); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } ret2 = dpl_req_gen_http_request(ctx, req, headers_request, NULL, header, sizeof (header), &header_len); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } iov[n_iov].iov_base = header; iov[n_iov].iov_len = header_len; n_iov++; //final crlf iov[n_iov].iov_base = "\r\n"; iov[n_iov].iov_len = 2; n_iov++; ret2 = dpl_conn_writev_all(conn, iov, n_iov, conn->ctx->write_timeout); if (DPL_SUCCESS != ret2) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "writev failed"); connection_close = 1; ret = ret2; goto end; } if (option && option->mask & DPL_OPTION_NOALLOC) { data_buf = *data_bufp; data_len = *data_lenp; } ret2 = dpl_read_http_reply_ext(conn, 1, (option && option->mask & DPL_OPTION_NOALLOC) ? 1 : 0, &data_buf, &data_len, &headers_reply, &connection_close); if (DPL_SUCCESS != ret2) { if (DPL_EREDIRECT == ret2) { if (NULL != locationp) { location = dpl_location(headers_reply); if (NULL == location) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "missing \"Location\" header in redirect HTTP response"); connection_close = 1; ret = DPL_FAILURE; goto end; } *locationp = strdup(location); } } ret = ret2; goto end; } if (req_mask & DPL_CDMI_REQ_HTTP_COMPAT) { //metadata are in headers ret2 = dpl_cdmi_get_metadata_from_headers(headers_reply, metadatap, sysmdp); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } else { if (!raw) { char *tmp; //extract data+metadata from json ret2 = dpl_cdmi_parse_json_buffer(ctx, data_buf, data_len, &val); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (DPL_VALUE_SUBDICT != val->type) { ret = DPL_EINVAL; goto end; } ret2 = dpl_cdmi_get_metadata_from_values(val->subdict, metadatap, sysmdp); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } //find the value object ret2 = dpl_dict_get_lowered(val->subdict, "value", &var); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (DPL_VALUE_STRING != var->val->type) { ret = DPL_EINVAL; goto end; } ret2 = dpl_dict_get_lowered(val->subdict, "valuetransferencoding", &encoding); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (DPL_VALUE_STRING != encoding->val->type) { ret = DPL_EINVAL; goto end; } value_len = var->val->string->len; if (0 == strcmp(dpl_sbuf_get_str(encoding->val->string), "base64")) { orig_len = DPL_BASE64_ORIG_LENGTH(value_len); orig_buf = malloc(orig_len); if (NULL == orig_buf) { ret = DPL_ENOMEM; goto end; } orig_len = dpl_base64_decode((u_char *) dpl_sbuf_get_str(var->val->string), value_len, (u_char *) orig_buf); //swap pointers tmp = data_buf; data_buf = orig_buf; orig_buf = tmp; data_len = orig_len; } else if (0 == strcmp(dpl_sbuf_get_str(encoding->val->string), "utf-8")) { orig_buf = data_buf; orig_len = data_len; data_buf = malloc(value_len + 1); if (NULL == data_buf) { ret = DPL_ENOMEM; goto end; } memcpy(data_buf, dpl_sbuf_get_str(var->val->string), value_len); data_buf[value_len] = '\0'; data_len = value_len; } else { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "unknown \"valuetransferencoding\" received: \"%s\"", encoding->val->string); ret = DPL_EINVAL; goto end; } } } if (NULL != data_bufp) { *data_bufp = data_buf; data_buf = NULL; //consume it } if (NULL != data_lenp) *data_lenp = data_len; ret = DPL_SUCCESS; end: if (NULL != orig_buf) free(orig_buf); if (NULL != val) dpl_value_free(val); if ((option && !(option->mask & DPL_OPTION_NOALLOC)) && NULL != data_buf) free(data_buf); if (NULL != conn) { if (1 == connection_close) dpl_conn_terminate(conn); else dpl_conn_release(conn); } if (NULL != headers_reply) dpl_dict_free(headers_reply); if (NULL != headers_request) dpl_dict_free(headers_request); if (NULL != req) dpl_req_free(req); DPL_TRACE(ctx, DPL_TRACE_BACKEND, "ret=%d", ret); return ret; }
dpl_status_t dpl_cdmi_put_internal(dpl_ctx_t *ctx, int post, const char *bucket, const char *resource, const char *subresource, const dpl_option_t *option, dpl_ftype_t object_type, const dpl_condition_t *condition, const dpl_range_t *range, const dpl_dict_t *metadata, const dpl_sysmd_t *sysmd, const char *data_buf, unsigned int data_len, const dpl_dict_t *query_params, dpl_sysmd_t *returned_sysmdp, char **locationp) { int ret, ret2; dpl_conn_t *conn = NULL; char header[dpl_header_size]; u_int header_len; struct iovec iov[10]; int n_iov = 0; int connection_close = 0; dpl_dict_t *headers_request = NULL; dpl_dict_t *headers_reply = NULL; dpl_req_t *req = NULL; char *body_str = NULL; int body_len = 0; char *data_buf_returned = NULL; u_int data_len_returned; dpl_value_t *val = NULL; dpl_cdmi_req_mask_t req_mask = 0u; DPL_TRACE(ctx, DPL_TRACE_BACKEND, ""); if (option) { if (option->mask & DPL_OPTION_HTTP_COMPAT) req_mask |= DPL_CDMI_REQ_HTTP_COMPAT; } req = dpl_req_new(ctx); if (NULL == req) { ret = DPL_ENOMEM; goto end; } if (post) dpl_req_set_method(req, DPL_METHOD_POST); else dpl_req_set_method(req, DPL_METHOD_PUT); ret2 = dpl_cdmi_req_set_resource(req, resource); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (NULL != subresource) { ret2 = dpl_req_set_subresource(req, subresource); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (NULL != condition) { dpl_req_set_condition(req, condition); } if (range) { ret2 = dpl_cdmi_req_add_range(req, req_mask, range); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } dpl_req_set_object_type(req, object_type); dpl_req_set_data(req, data_buf, data_len); dpl_req_add_behavior(req, DPL_BEHAVIOR_MD5); if (NULL != sysmd) { ret2 = dpl_cdmi_add_sysmd_to_req(sysmd, req); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (NULL != metadata) { ret2 = dpl_cdmi_req_add_metadata(req, metadata, option ? option->mask & DPL_OPTION_APPEND_METADATA : 0); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } //build request ret2 = dpl_cdmi_req_build(req, 0, &headers_request, &body_str, &body_len); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } //contact default host dpl_req_rm_behavior(req, DPL_BEHAVIOR_VIRTUAL_HOSTING); ret2 = dpl_try_connect(ctx, req, &conn); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } ret2 = dpl_add_host_to_headers(req, headers_request); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } ret2 = dpl_req_gen_http_request(ctx, req, headers_request, NULL, header, sizeof (header), &header_len); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } iov[n_iov].iov_base = header; iov[n_iov].iov_len = header_len; n_iov++; //final crlf iov[n_iov].iov_base = "\r\n"; iov[n_iov].iov_len = 2; n_iov++; //buffer iov[n_iov].iov_base = body_str; iov[n_iov].iov_len = body_len; n_iov++; ret2 = dpl_conn_writev_all(conn, iov, n_iov, conn->ctx->write_timeout); if (DPL_SUCCESS != ret2) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "writev failed"); connection_close = 1; ret = ret2; goto end; } ret2 = dpl_read_http_reply(conn, 1, &data_buf_returned, &data_len_returned, &headers_reply, &connection_close); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (post) { if (req_mask & DPL_CDMI_REQ_HTTP_COMPAT) { ret2 = dpl_cdmi_get_metadata_from_headers(headers_reply, NULL, returned_sysmdp); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } else { ret2 = dpl_cdmi_parse_json_buffer(ctx, data_buf_returned, data_len_returned, &val); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (DPL_VALUE_SUBDICT != val->type) { ret = DPL_EINVAL; goto end; } ret2 = dpl_cdmi_get_metadata_from_values(val->subdict, NULL, returned_sysmdp); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } } if (NULL != returned_sysmdp) { dpl_dict_var_t *var; int base_path_len = strlen(ctx->base_path); //location contains the path to new location ret2 = dpl_dict_get_lowered(headers_reply, "location", &var); if (DPL_SUCCESS != ret2) { ret = ret2; goto end; } if (DPL_VALUE_STRING != var->val->type) { ret = DPL_EINVAL; goto end; } //remove the base_path from the answer if (strncmp(dpl_sbuf_get_str(var->val->string), ctx->base_path, base_path_len)) { ret = DPL_EINVAL; goto end; } returned_sysmdp->mask |= DPL_SYSMD_MASK_PATH; strncpy(returned_sysmdp->path, dpl_sbuf_get_str(var->val->string) + base_path_len, DPL_MAXPATHLEN); } } ret = DPL_SUCCESS; end: if (NULL != val) dpl_value_free(val); if (NULL != data_buf_returned) free(data_buf_returned); if (NULL != body_str) free(body_str); if (NULL != conn) { if (1 == connection_close) dpl_conn_terminate(conn); else dpl_conn_release(conn); } if (NULL != headers_reply) dpl_dict_free(headers_reply); if (NULL != headers_request) dpl_dict_free(headers_request); if (NULL != req) dpl_req_free(req); DPL_TRACE(ctx, DPL_TRACE_BACKEND, "ret=%d", ret); return ret; }
dpl_status_t dpl_s3_stream_multipart_put(dpl_ctx_t *ctx, const char *bucket, const char *resource, const char *uploadid, unsigned int partnb, char *buf, unsigned int len, const char **etagp) { dpl_status_t ret; dpl_conn_t *conn = NULL; char header[dpl_header_size]; u_int header_len; struct iovec iov[10]; int n_iov = 0; int connection_close = 0; dpl_dict_t *headers_request = NULL; dpl_dict_t *headers_reply = NULL; dpl_s3_req_mask_t req_mask = 0u; dpl_req_t *req = NULL; char subresource[ 11 /* for 'partNumber=' */ + 18 /* max len for %lu */ + 10 /* for 'uploadId=' */ + strlen(uploadid)]; snprintf(subresource, sizeof(subresource), "partNumber=%u&uploadId=%s", partnb, uploadid); req = dpl_req_new(ctx); if (NULL == req) { ret = DPL_ENOMEM; goto end; } dpl_req_set_method(req, DPL_METHOD_PUT); if (NULL == bucket) { ret = DPL_EINVAL; goto end; } ret = dpl_req_set_bucket(req, bucket); if (DPL_SUCCESS != ret) goto end; ret = dpl_req_set_resource(req, resource); if (DPL_SUCCESS != ret) goto end; ret = dpl_req_set_subresource(req, subresource); if (DPL_SUCCESS != ret) goto end; dpl_req_set_data(req, buf, len); dpl_req_add_behavior(req, DPL_BEHAVIOR_MD5); ret = dpl_s3_req_build(req, req_mask, &headers_request); if (DPL_SUCCESS != ret) goto end; ret = dpl_try_connect(ctx, req, &conn); if (DPL_SUCCESS != ret) goto end; ret = dpl_add_host_to_headers(req, headers_request); if (DPL_SUCCESS != ret) goto end; ret = dpl_s3_add_authorization_to_headers(req, headers_request, NULL, NULL); if (DPL_SUCCESS != ret) goto end; ret = dpl_req_gen_http_request(ctx, req, headers_request, NULL, header, sizeof (header), &header_len); if (DPL_SUCCESS != ret) goto end; iov[n_iov].iov_base = header; iov[n_iov].iov_len = header_len; n_iov++; //final crlf iov[n_iov].iov_base = "\r\n"; iov[n_iov].iov_len = 2; n_iov++; //buffer iov[n_iov].iov_base = (void *)buf; iov[n_iov].iov_len = len; n_iov++; ret = dpl_conn_writev_all(conn, iov, n_iov, conn->ctx->write_timeout); if (DPL_SUCCESS != ret) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "writev failed"); connection_close = 1; goto end; } ret = dpl_read_http_reply(conn, 1, NULL, NULL, &headers_reply, &connection_close); if (DPL_SUCCESS != ret) goto end; if (etagp) { /* * Etag of the part is returned as a header, as a string value. * Thus, it should be surrounded by double-quotes that we need * to remove */ dpl_dict_var_t *var = NULL; const char *ro_etag = NULL; const char *start_etag = NULL; const char *end_etag = NULL; ret = dpl_dict_get_lowered(headers_reply, "Etag", &var); if (ret != DPL_SUCCESS || var == NULL) { ret = DPL_FAILURE; goto end; } assert(var->val->type == DPL_VALUE_STRING); ro_etag = dpl_sbuf_get_str(var->val->string); start_etag = strchr(ro_etag, '"'); if (start_etag == NULL) { start_etag = ro_etag; end_etag = start_etag + strlen(start_etag); } else { start_etag += 1; // go after the " char end_etag = strchr(start_etag, '"'); } *etagp = strndup(start_etag, end_etag - start_etag); if (*etagp == NULL) { ret = DPL_ENOMEM; goto end; } } ret = DPL_SUCCESS; end: if (NULL != conn) { if (1 == connection_close) dpl_conn_terminate(conn); else dpl_conn_release(conn); } if (NULL != headers_reply) dpl_dict_free(headers_reply); if (NULL != headers_request) dpl_dict_free(headers_request); if (NULL != req) dpl_req_free(req); return ret; }
END_TEST /* * Test the "lowered" feature, which is almost but not quite * the same as case insensitivity. */ START_TEST(lowered_test) { dpl_dict_t *dict; dpl_status_t r; const char *s; dpl_dict_var_t *var; const char value[] = "World"; const char value2[] = "Mondo"; const char value3[] = "Monde"; dict = dpl_dict_new(13); dpl_assert_ptr_not_null(dict); /* Add a value, lowered */ r = dpl_dict_add(dict, "Hello", value, /*lowered*/1); dpl_assert_int_eq(DPL_SUCCESS, r); dpl_assert_int_eq(1, dpl_dict_count(dict)); /* The actual key used is internally lowercased, so * doing a normal get on the key originally given * should fail */ dpl_assert_str_eq(NULL, dpl_dict_get_value(dict, "Hello")); /* Likewise, doing a normal get on a lowercase version * of the original key should succeed */ dpl_assert_str_eq(value, dpl_dict_get_value(dict, "hello")); /* dpl_dict_get_lowered internally lowercases the key it's * given, so it can be used with keys of any casing */ var = BADPOINTER; r = dpl_dict_get_lowered(dict, "hello", &var); dpl_assert_int_eq(DPL_SUCCESS, r); dpl_assert_ptr_not_null(var); dpl_assert_ptr_ne(var, BADPOINTER); dpl_assert_str_eq(value, dpl_sbuf_get_str(var->val->string)); var = BADPOINTER; r = dpl_dict_get_lowered(dict, "Hello", &var); dpl_assert_int_eq(DPL_SUCCESS, r); dpl_assert_ptr_not_null(var); dpl_assert_ptr_ne(var, BADPOINTER); dpl_assert_str_eq(value, dpl_sbuf_get_str(var->val->string)); var = BADPOINTER; r = dpl_dict_get_lowered(dict, "HELLO", &var); dpl_assert_int_eq(DPL_SUCCESS, r); dpl_assert_ptr_not_null(var); dpl_assert_ptr_ne(var, BADPOINTER); dpl_assert_str_eq(value, dpl_sbuf_get_str(var->val->string)); var = BADPOINTER; r = dpl_dict_get_lowered(dict, "hElLo", &var); dpl_assert_int_eq(DPL_SUCCESS, r); dpl_assert_ptr_not_null(var); dpl_assert_ptr_ne(var, BADPOINTER); dpl_assert_str_eq(value, dpl_sbuf_get_str(var->val->string)); /* check that dpl_dict_get_lowered() will report as missing * some keys that we know not to be present */ var = BADPOINTER; r = dpl_dict_get_lowered(dict, "HellonEarth", &var); dpl_assert_int_eq(DPL_ENOENT, r); /* the value of `var' on failure is not documented */ var = BADPOINTER; r = dpl_dict_get_lowered(dict, "Hell", &var); dpl_assert_int_eq(DPL_ENOENT, r); /* the value of `var' on failure is not documented */ var = BADPOINTER; r = dpl_dict_get_lowered(dict, "daffyduck", &var); dpl_assert_int_eq(DPL_ENOENT, r); /* the value of `var' on failure is not documented */ /* Verify that inserting another key which maps to the * same lowercased string, replaces the first key */ r = dpl_dict_add(dict, "hello", value2, /*lowered*/1); dpl_assert_int_eq(DPL_SUCCESS, r); dpl_assert_int_eq(1, dpl_dict_count(dict)); dpl_assert_str_eq(value2, dpl_dict_get_value(dict, "hello")); r = dpl_dict_add(dict, "hELLo", value3, /*lowered*/1); dpl_assert_int_eq(DPL_SUCCESS, r); dpl_assert_int_eq(1, dpl_dict_count(dict)); dpl_assert_str_eq(value3, dpl_dict_get_value(dict, "hello")); dpl_dict_free(dict); }