mirror of
https://github.com/curl/curl.git
synced 2025-02-17 14:59:45 +08:00
aws_sigv4: fix header computation
Handle canonical headers and signed headers creation as explained here: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html The algo tells that signed and canonical must contain at last host and x-amz-date. So we check whatever thoses are present in the curl http headers list. If they are, we use the one enter by curl user, otherwise we generate them. then we to lower, and remove space from each http headers plus host and x-amz-date, then sort them all by alphabetical order. This patch also fix a bug with host header, which was ignoring the port. Closes #7966
This commit is contained in:
parent
3c0050d13e
commit
29c4aa00a1
@ -44,6 +44,8 @@
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#include "slist.h"
|
||||
|
||||
#define HMAC_SHA256(k, kl, d, dl, o) \
|
||||
do { \
|
||||
ret = Curl_hmacit(Curl_HMAC_SHA256, \
|
||||
@ -51,49 +53,240 @@
|
||||
(unsigned int)kl, \
|
||||
(unsigned char *)d, \
|
||||
(unsigned int)dl, o); \
|
||||
if(ret != CURLE_OK) { \
|
||||
if(ret) { \
|
||||
goto fail; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define TIMESTAMP_SIZE 17
|
||||
|
||||
static void sha256_to_hex(char *dst, unsigned char *sha, size_t dst_l)
|
||||
{
|
||||
int i;
|
||||
|
||||
DEBUGASSERT(dst_l >= 65);
|
||||
for(i = 0; i < 32; ++i) {
|
||||
curl_msnprintf(dst + (i * 2), dst_l - (i * 2), "%02x", sha[i]);
|
||||
msnprintf(dst + (i * 2), dst_l - (i * 2), "%02x", sha[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static char *find_date_hdr(struct Curl_easy *data, const char *sig_hdr)
|
||||
{
|
||||
char *tmp = Curl_checkheaders(data, sig_hdr, strlen(sig_hdr));
|
||||
|
||||
if(tmp)
|
||||
return tmp;
|
||||
return Curl_checkheaders(data, STRCONST("Date"));
|
||||
}
|
||||
|
||||
/* remove whitespace, and lowercase all headers */
|
||||
static void trim_headers(struct curl_slist *head)
|
||||
{
|
||||
struct curl_slist *l;
|
||||
for(l = head; l; l = l->next) {
|
||||
char *value; /* to read from */
|
||||
char *store;
|
||||
size_t colon = strcspn(l->data, ":");
|
||||
Curl_strntolower(l->data, l->data, colon);
|
||||
|
||||
value = &l->data[colon];
|
||||
if(!*value)
|
||||
continue;
|
||||
++value;
|
||||
store = value;
|
||||
|
||||
/* skip leading whitespace */
|
||||
while(*value && ISBLANK(*value))
|
||||
value++;
|
||||
|
||||
while(*value) {
|
||||
int space = 0;
|
||||
while(*value && ISBLANK(*value)) {
|
||||
value++;
|
||||
space++;
|
||||
}
|
||||
if(space) {
|
||||
/* replace any number of consecutive whitespace with a single space,
|
||||
unless at the end of the string, then nothing */
|
||||
if(*value)
|
||||
*store++ = ' ';
|
||||
}
|
||||
else
|
||||
*store++ = *value++;
|
||||
}
|
||||
*store = 0; /* null terminate */
|
||||
}
|
||||
}
|
||||
|
||||
/* maximum lenth for the aws sivg4 parts */
|
||||
#define MAX_SIGV4_LEN 64
|
||||
#define MAX_SIGV4_LEN_TXT "64"
|
||||
|
||||
#define DATE_HDR_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Date"))
|
||||
|
||||
/* FQDN + host: */
|
||||
#define FULL_HOST_LEN (255 + sizeof("host:"))
|
||||
|
||||
/* string been x-PROVIDER-date:TIMESTAMP, I need +1 for ':' */
|
||||
#define DATE_FULL_HDR_LEN (DATE_HDR_KEY_LEN + TIMESTAMP_SIZE + 1)
|
||||
|
||||
/* timestamp should point to a buffer of at last TIMESTAMP_SIZE bytes */
|
||||
static CURLcode make_headers(struct Curl_easy *data,
|
||||
const char *hostname,
|
||||
char *timestamp,
|
||||
char *provider1,
|
||||
char **date_header,
|
||||
struct dynbuf *canonical_headers,
|
||||
struct dynbuf *signed_headers)
|
||||
{
|
||||
char date_hdr_key[DATE_HDR_KEY_LEN];
|
||||
char date_full_hdr[DATE_FULL_HDR_LEN];
|
||||
struct curl_slist *head = NULL;
|
||||
struct curl_slist *tmp_head = NULL;
|
||||
CURLcode ret = CURLE_OUT_OF_MEMORY;
|
||||
struct curl_slist *l;
|
||||
int again = 1;
|
||||
|
||||
/* provider1 mid */
|
||||
Curl_strntolower(provider1, provider1, strlen(provider1));
|
||||
provider1[0] = Curl_raw_toupper(provider1[0]);
|
||||
|
||||
msnprintf(date_hdr_key, DATE_HDR_KEY_LEN, "X-%s-Date", provider1);
|
||||
|
||||
/* provider1 lowercase */
|
||||
Curl_strntolower(provider1, provider1, 1); /* first byte only */
|
||||
msnprintf(date_full_hdr, DATE_FULL_HDR_LEN,
|
||||
"x-%s-date:%s", provider1, timestamp);
|
||||
|
||||
if(Curl_checkheaders(data, STRCONST("Host"))) {
|
||||
head = NULL;
|
||||
}
|
||||
else {
|
||||
char full_host[FULL_HOST_LEN];
|
||||
|
||||
if(data->state.aptr.host) {
|
||||
size_t pos;
|
||||
|
||||
if(strlen(data->state.aptr.host) > FULL_HOST_LEN) {
|
||||
ret = CURLE_URL_MALFORMAT;
|
||||
goto fail;
|
||||
}
|
||||
strcpy(full_host, data->state.aptr.host);
|
||||
/* remove /r/n as the separator for canonical request must be '\n' */
|
||||
pos = strcspn(full_host, "\n\r");
|
||||
full_host[pos] = 0;
|
||||
}
|
||||
else {
|
||||
if(strlen(hostname) > FULL_HOST_LEN) {
|
||||
ret = CURLE_URL_MALFORMAT;
|
||||
goto fail;
|
||||
}
|
||||
msnprintf(full_host, FULL_HOST_LEN, "host:%s", hostname);
|
||||
}
|
||||
|
||||
head = curl_slist_append(NULL, full_host);
|
||||
if(!head)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
for(l = data->set.headers; l; l = l->next) {
|
||||
tmp_head = curl_slist_append(head, l->data);
|
||||
if(!tmp_head)
|
||||
goto fail;
|
||||
head = tmp_head;
|
||||
}
|
||||
|
||||
trim_headers(head);
|
||||
|
||||
*date_header = find_date_hdr(data, date_hdr_key);
|
||||
if(!*date_header) {
|
||||
tmp_head = curl_slist_append(head, date_full_hdr);
|
||||
if(!tmp_head)
|
||||
goto fail;
|
||||
head = tmp_head;
|
||||
*date_header = curl_maprintf("%s: %s", date_hdr_key, timestamp);
|
||||
}
|
||||
else {
|
||||
char *value;
|
||||
|
||||
*date_header = strdup(*date_header);
|
||||
if(!*date_header)
|
||||
goto fail;
|
||||
|
||||
value = strchr(*date_header, ':');
|
||||
if(!value)
|
||||
goto fail;
|
||||
++value;
|
||||
while(ISBLANK(*value))
|
||||
++value;
|
||||
strncpy(timestamp, value, TIMESTAMP_SIZE - 1);
|
||||
timestamp[TIMESTAMP_SIZE - 1] = 0;
|
||||
}
|
||||
|
||||
/* alpha-sort in a case sensitive manner */
|
||||
do {
|
||||
again = 0;
|
||||
for(l = head; l; l = l->next) {
|
||||
struct curl_slist *next = l->next;
|
||||
|
||||
if(next && strcmp(l->data, next->data) > 0) {
|
||||
char *tmp = l->data;
|
||||
|
||||
l->data = next->data;
|
||||
next->data = tmp;
|
||||
again = 1;
|
||||
}
|
||||
}
|
||||
} while(again);
|
||||
|
||||
for(l = head; l; l = l->next) {
|
||||
char *tmp;
|
||||
|
||||
if(Curl_dyn_add(canonical_headers, l->data))
|
||||
goto fail;
|
||||
if(Curl_dyn_add(canonical_headers, "\n"))
|
||||
goto fail;
|
||||
|
||||
tmp = strchr(l->data, ':');
|
||||
if(tmp)
|
||||
*tmp = 0;
|
||||
|
||||
if(l != head) {
|
||||
if(Curl_dyn_add(signed_headers, ";"))
|
||||
goto fail;
|
||||
}
|
||||
if(Curl_dyn_add(signed_headers, l->data))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = CURLE_OK;
|
||||
fail:
|
||||
curl_slist_free_all(head);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
|
||||
{
|
||||
CURLcode ret = CURLE_OUT_OF_MEMORY;
|
||||
struct connectdata *conn = data->conn;
|
||||
size_t len;
|
||||
const char *tmp0;
|
||||
const char *tmp1;
|
||||
char *provider0_low = NULL;
|
||||
char *provider0_up = NULL;
|
||||
char *provider1_low = NULL;
|
||||
char *provider1_mid = NULL;
|
||||
char *region = NULL;
|
||||
char *service = NULL;
|
||||
const char *arg;
|
||||
char provider0[MAX_SIGV4_LEN + 1]="";
|
||||
char provider1[MAX_SIGV4_LEN + 1]="";
|
||||
char region[MAX_SIGV4_LEN + 1]="";
|
||||
char service[MAX_SIGV4_LEN + 1]="";
|
||||
const char *hostname = conn->host.name;
|
||||
#ifdef DEBUGBUILD
|
||||
char *force_timestamp;
|
||||
#endif
|
||||
time_t clock;
|
||||
struct tm tm;
|
||||
char timestamp[17];
|
||||
char timestamp[TIMESTAMP_SIZE];
|
||||
char date[9];
|
||||
const char *content_type = Curl_checkheaders(data, STRCONST("Content-Type"));
|
||||
char *canonical_headers = NULL;
|
||||
char *signed_headers = NULL;
|
||||
Curl_HttpReq httpreq;
|
||||
const char *method;
|
||||
size_t post_data_len;
|
||||
const char *post_data = data->set.postfields ? data->set.postfields : "";
|
||||
struct dynbuf canonical_headers;
|
||||
struct dynbuf signed_headers;
|
||||
char *date_header = NULL;
|
||||
const char *post_data = data->set.postfields;
|
||||
size_t post_data_len = 0;
|
||||
unsigned char sha_hash[32];
|
||||
char sha_hex[65];
|
||||
char *canonical_request = NULL;
|
||||
@ -101,10 +294,9 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
|
||||
char *credential_scope = NULL;
|
||||
char *str_to_sign = NULL;
|
||||
const char *user = data->state.aptr.user ? data->state.aptr.user : "";
|
||||
const char *passwd = data->state.aptr.passwd ? data->state.aptr.passwd : "";
|
||||
char *secret = NULL;
|
||||
unsigned char tmp_sign0[32] = {0};
|
||||
unsigned char tmp_sign1[32] = {0};
|
||||
unsigned char sign0[32] = {0};
|
||||
unsigned char sign1[32] = {0};
|
||||
char *auth_headers = NULL;
|
||||
|
||||
DEBUGASSERT(!proxy);
|
||||
@ -115,6 +307,10 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* we init thoses buffers here, so goto fail will free initialized dynbuf */
|
||||
Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
|
||||
Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);
|
||||
|
||||
/*
|
||||
* Parameters parsing
|
||||
* Google and Outscale use the same OSC or GOOG,
|
||||
@ -122,223 +318,154 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
|
||||
* AWS is the default because most of non-amazon providers
|
||||
* are still using aws:amz as a prefix.
|
||||
*/
|
||||
tmp0 = data->set.str[STRING_AWS_SIGV4] ?
|
||||
arg = data->set.str[STRING_AWS_SIGV4] ?
|
||||
data->set.str[STRING_AWS_SIGV4] : "aws:amz";
|
||||
tmp1 = strchr(tmp0, ':');
|
||||
len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
|
||||
if(len < 1) {
|
||||
infof(data, "first provider can't be empty");
|
||||
|
||||
/* provider1[:provider2[:region[:service]]]
|
||||
|
||||
No string can be longer than N bytes of non-whitespace
|
||||
*/
|
||||
(void)sscanf(arg, "%" MAX_SIGV4_LEN_TXT "[^:]"
|
||||
":%" MAX_SIGV4_LEN_TXT "[^:]"
|
||||
":%" MAX_SIGV4_LEN_TXT "[^:]"
|
||||
":%" MAX_SIGV4_LEN_TXT "s",
|
||||
provider0, provider1, region, service);
|
||||
if(!provider0[0]) {
|
||||
failf(data, "first provider can't be empty");
|
||||
ret = CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
goto fail;
|
||||
}
|
||||
provider0_low = malloc(len + 1);
|
||||
provider0_up = malloc(len + 1);
|
||||
if(!provider0_low || !provider0_up) {
|
||||
goto fail;
|
||||
}
|
||||
Curl_strntolower(provider0_low, tmp0, len);
|
||||
provider0_low[len] = '\0';
|
||||
Curl_strntoupper(provider0_up, tmp0, len);
|
||||
provider0_up[len] = '\0';
|
||||
else if(!provider1[0])
|
||||
strcpy(provider1, provider0);
|
||||
|
||||
if(tmp1) {
|
||||
tmp0 = tmp1 + 1;
|
||||
tmp1 = strchr(tmp0, ':');
|
||||
len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
|
||||
if(len < 1) {
|
||||
infof(data, "second provider can't be empty");
|
||||
ret = CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
goto fail;
|
||||
}
|
||||
provider1_low = malloc(len + 1);
|
||||
provider1_mid = malloc(len + 1);
|
||||
if(!provider1_low || !provider1_mid) {
|
||||
goto fail;
|
||||
}
|
||||
Curl_strntolower(provider1_low, tmp0, len);
|
||||
provider1_low[len] = '\0';
|
||||
Curl_strntolower(provider1_mid, tmp0, len);
|
||||
provider1_mid[0] = Curl_raw_toupper(provider1_mid[0]);
|
||||
provider1_mid[len] = '\0';
|
||||
|
||||
if(tmp1) {
|
||||
tmp0 = tmp1 + 1;
|
||||
tmp1 = strchr(tmp0, ':');
|
||||
len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
|
||||
if(len < 1) {
|
||||
infof(data, "region can't be empty");
|
||||
ret = CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
goto fail;
|
||||
}
|
||||
region = Curl_memdup(tmp0, len + 1);
|
||||
if(!region) {
|
||||
goto fail;
|
||||
}
|
||||
region[len] = '\0';
|
||||
|
||||
if(tmp1) {
|
||||
tmp0 = tmp1 + 1;
|
||||
service = strdup(tmp0);
|
||||
if(!service) {
|
||||
goto fail;
|
||||
}
|
||||
if(strlen(service) < 1) {
|
||||
infof(data, "service can't be empty");
|
||||
ret = CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
provider1_low = Curl_memdup(provider0_low, len + 1);
|
||||
provider1_mid = Curl_memdup(provider0_low, len + 1);
|
||||
if(!provider1_low || !provider1_mid) {
|
||||
goto fail;
|
||||
}
|
||||
provider1_mid[0] = Curl_raw_toupper(provider1_mid[0]);
|
||||
}
|
||||
|
||||
if(!service) {
|
||||
tmp0 = hostname;
|
||||
tmp1 = strchr(tmp0, '.');
|
||||
if(!tmp1) {
|
||||
infof(data, "service missing in parameters or hostname");
|
||||
if(!service[0]) {
|
||||
char *hostdot = strchr(hostname, '.');
|
||||
if(!hostdot) {
|
||||
failf(data, "service missing in parameters and hostname");
|
||||
ret = CURLE_URL_MALFORMAT;
|
||||
goto fail;
|
||||
}
|
||||
len = tmp1 - tmp0;
|
||||
service = Curl_memdup(tmp0, len + 1);
|
||||
if(!service) {
|
||||
len = hostdot - hostname;
|
||||
if(len > MAX_SIGV4_LEN) {
|
||||
failf(data, "service too long in hostname");
|
||||
ret = CURLE_URL_MALFORMAT;
|
||||
goto fail;
|
||||
}
|
||||
strncpy(service, hostname, len);
|
||||
service[len] = '\0';
|
||||
|
||||
if(!region) {
|
||||
tmp0 = tmp1 + 1;
|
||||
tmp1 = strchr(tmp0, '.');
|
||||
if(!tmp1) {
|
||||
infof(data, "region missing in parameters or hostname");
|
||||
if(!region[0]) {
|
||||
const char *reg = hostdot + 1;
|
||||
const char *hostreg = strchr(reg, '.');
|
||||
if(!hostreg) {
|
||||
failf(data, "region missing in parameters and hostname");
|
||||
ret = CURLE_URL_MALFORMAT;
|
||||
goto fail;
|
||||
}
|
||||
len = tmp1 - tmp0;
|
||||
region = Curl_memdup(tmp0, len + 1);
|
||||
if(!region) {
|
||||
len = hostreg - reg;
|
||||
if(len > MAX_SIGV4_LEN) {
|
||||
failf(data, "region too long in hostname");
|
||||
ret = CURLE_URL_MALFORMAT;
|
||||
goto fail;
|
||||
}
|
||||
strncpy(region, reg, len);
|
||||
region[len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
force_timestamp = getenv("CURL_FORCETIME");
|
||||
if(force_timestamp)
|
||||
clock = 0;
|
||||
else
|
||||
time(&clock);
|
||||
{
|
||||
char *force_timestamp = getenv("CURL_FORCETIME");
|
||||
if(force_timestamp)
|
||||
clock = 0;
|
||||
else
|
||||
time(&clock);
|
||||
}
|
||||
#else
|
||||
time(&clock);
|
||||
#endif
|
||||
ret = Curl_gmtime(clock, &tm);
|
||||
if(ret != CURLE_OK) {
|
||||
if(ret) {
|
||||
goto fail;
|
||||
}
|
||||
if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) {
|
||||
ret = CURLE_OUT_OF_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = make_headers(data, hostname, timestamp, provider1,
|
||||
&date_header, &canonical_headers, &signed_headers);
|
||||
if(ret)
|
||||
goto fail;
|
||||
ret = CURLE_OUT_OF_MEMORY;
|
||||
|
||||
memcpy(date, timestamp, sizeof(date));
|
||||
date[sizeof(date) - 1] = 0;
|
||||
|
||||
if(content_type) {
|
||||
content_type = strchr(content_type, ':');
|
||||
if(!content_type) {
|
||||
ret = CURLE_FAILED_INIT;
|
||||
goto fail;
|
||||
}
|
||||
content_type++;
|
||||
/* Skip whitespace now */
|
||||
while(*content_type == ' ' || *content_type == '\t')
|
||||
++content_type;
|
||||
|
||||
canonical_headers = curl_maprintf("content-type:%s\n"
|
||||
"host:%s\n"
|
||||
"x-%s-date:%s\n",
|
||||
content_type,
|
||||
hostname,
|
||||
provider1_low, timestamp);
|
||||
signed_headers = curl_maprintf("content-type;host;x-%s-date",
|
||||
provider1_low);
|
||||
if(post_data) {
|
||||
if(data->set.postfieldsize < 0)
|
||||
post_data_len = strlen(post_data);
|
||||
else
|
||||
post_data_len = (size_t)data->set.postfieldsize;
|
||||
}
|
||||
else {
|
||||
canonical_headers = curl_maprintf("host:%s\n"
|
||||
"x-%s-date:%s\n",
|
||||
hostname,
|
||||
provider1_low, timestamp);
|
||||
signed_headers = curl_maprintf("host;x-%s-date", provider1_low);
|
||||
}
|
||||
|
||||
if(!canonical_headers || !signed_headers) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(data->set.postfieldsize < 0)
|
||||
post_data_len = strlen(post_data);
|
||||
else
|
||||
post_data_len = (size_t)data->set.postfieldsize;
|
||||
if(Curl_sha256it(sha_hash, (const unsigned char *) post_data,
|
||||
post_data_len)) {
|
||||
post_data_len))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
|
||||
|
||||
Curl_http_method(data, conn, &method, &httpreq);
|
||||
{
|
||||
Curl_HttpReq httpreq;
|
||||
const char *method;
|
||||
|
||||
canonical_request =
|
||||
curl_maprintf("%s\n" /* HTTPRequestMethod */
|
||||
"%s\n" /* CanonicalURI */
|
||||
"%s\n" /* CanonicalQueryString */
|
||||
"%s\n" /* CanonicalHeaders */
|
||||
"%s\n" /* SignedHeaders */
|
||||
"%s", /* HashedRequestPayload in hex */
|
||||
method,
|
||||
data->state.up.path,
|
||||
data->state.up.query ? data->state.up.query : "",
|
||||
canonical_headers,
|
||||
signed_headers,
|
||||
sha_hex);
|
||||
if(!canonical_request) {
|
||||
goto fail;
|
||||
Curl_http_method(data, conn, &method, &httpreq);
|
||||
|
||||
canonical_request =
|
||||
curl_maprintf("%s\n" /* HTTPRequestMethod */
|
||||
"%s\n" /* CanonicalURI */
|
||||
"%s\n" /* CanonicalQueryString */
|
||||
"%s\n" /* CanonicalHeaders */
|
||||
"%s\n" /* SignedHeaders */
|
||||
"%s", /* HashedRequestPayload in hex */
|
||||
method,
|
||||
data->state.up.path,
|
||||
data->state.up.query ? data->state.up.query : "",
|
||||
Curl_dyn_ptr(&canonical_headers),
|
||||
Curl_dyn_ptr(&signed_headers),
|
||||
sha_hex);
|
||||
if(!canonical_request)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
request_type = curl_maprintf("%s4_request", provider0_low);
|
||||
if(!request_type) {
|
||||
/* provider 0 lowercase */
|
||||
Curl_strntolower(provider0, provider0, strlen(provider0));
|
||||
request_type = curl_maprintf("%s4_request", provider0);
|
||||
if(!request_type)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
credential_scope = curl_maprintf("%s/%s/%s/%s",
|
||||
date, region, service, request_type);
|
||||
if(!credential_scope) {
|
||||
if(!credential_scope)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(Curl_sha256it(sha_hash, (unsigned char *) canonical_request,
|
||||
strlen(canonical_request))) {
|
||||
strlen(canonical_request)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
|
||||
|
||||
/* provider 0 uppercase */
|
||||
Curl_strntoupper(provider0, provider0, strlen(provider0));
|
||||
|
||||
/*
|
||||
* Google allow to use rsa key instead of HMAC, so this code might change
|
||||
* In the future, but for now we support only HMAC version
|
||||
* Google allows using RSA key instead of HMAC, so this code might change
|
||||
* in the future. For now we ony support HMAC.
|
||||
*/
|
||||
str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */
|
||||
"%s\n" /* RequestDateTime */
|
||||
"%s\n" /* CredentialScope */
|
||||
"%s", /* HashedCanonicalRequest in hex */
|
||||
provider0_up,
|
||||
provider0,
|
||||
timestamp,
|
||||
credential_scope,
|
||||
sha_hex);
|
||||
@ -346,36 +473,33 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
secret = curl_maprintf("%s4%s", provider0_up, passwd);
|
||||
if(!secret) {
|
||||
/* provider 0 uppercase */
|
||||
secret = curl_maprintf("%s4%s", provider0,
|
||||
data->state.aptr.passwd ?
|
||||
data->state.aptr.passwd : "");
|
||||
if(!secret)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
HMAC_SHA256(secret, strlen(secret),
|
||||
date, strlen(date), tmp_sign0);
|
||||
HMAC_SHA256(tmp_sign0, sizeof(tmp_sign0),
|
||||
region, strlen(region), tmp_sign1);
|
||||
HMAC_SHA256(tmp_sign1, sizeof(tmp_sign1),
|
||||
service, strlen(service), tmp_sign0);
|
||||
HMAC_SHA256(tmp_sign0, sizeof(tmp_sign0),
|
||||
request_type, strlen(request_type), tmp_sign1);
|
||||
HMAC_SHA256(tmp_sign1, sizeof(tmp_sign1),
|
||||
str_to_sign, strlen(str_to_sign), tmp_sign0);
|
||||
HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0);
|
||||
HMAC_SHA256(sign0, sizeof(sign0), region, strlen(region), sign1);
|
||||
HMAC_SHA256(sign1, sizeof(sign1), service, strlen(service), sign0);
|
||||
HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1);
|
||||
HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0);
|
||||
|
||||
sha256_to_hex(sha_hex, tmp_sign0, sizeof(sha_hex));
|
||||
sha256_to_hex(sha_hex, sign0, sizeof(sha_hex));
|
||||
|
||||
/* provider 0 uppercase */
|
||||
auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 "
|
||||
"Credential=%s/%s, "
|
||||
"SignedHeaders=%s, "
|
||||
"Signature=%s\r\n"
|
||||
"X-%s-Date: %s\r\n",
|
||||
provider0_up,
|
||||
"%s\r\n",
|
||||
provider0,
|
||||
user,
|
||||
credential_scope,
|
||||
signed_headers,
|
||||
Curl_dyn_ptr(&signed_headers),
|
||||
sha_hex,
|
||||
provider1_mid,
|
||||
timestamp);
|
||||
date_header);
|
||||
if(!auth_headers) {
|
||||
goto fail;
|
||||
}
|
||||
@ -386,19 +510,14 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
|
||||
ret = CURLE_OK;
|
||||
|
||||
fail:
|
||||
free(provider0_low);
|
||||
free(provider0_up);
|
||||
free(provider1_low);
|
||||
free(provider1_mid);
|
||||
free(region);
|
||||
free(service);
|
||||
free(canonical_headers);
|
||||
free(signed_headers);
|
||||
Curl_dyn_free(&canonical_headers);
|
||||
Curl_dyn_free(&signed_headers);
|
||||
free(canonical_request);
|
||||
free(request_type);
|
||||
free(credential_scope);
|
||||
free(str_to_sign);
|
||||
free(secret);
|
||||
free(date_header);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -225,6 +225,7 @@ test1916 test1917 test1918 test1919 \
|
||||
\
|
||||
test1933 test1934 test1935 test1936 test1937 test1938 test1939 test1940 \
|
||||
test1941 test1942 test1943 test1944 test1945 test1946 test1947 test1948 \
|
||||
test1955 \
|
||||
\
|
||||
test2000 test2001 test2002 test2003 test2004 \
|
||||
\
|
||||
|
@ -47,7 +47,7 @@ lib%TESTNUMBER
|
||||
</tool>
|
||||
|
||||
<command>
|
||||
http://xxx:yyy@%HOSTIP:%HTTPPORT/%TESTNUMBER/testapi/test
|
||||
http://xxx:yyy@127.0.0.1:9000/%TESTNUMBER/testapi/test 127.0.0.1:9000:%HOSTIP:%HTTPPORT
|
||||
</command>
|
||||
</client>
|
||||
|
||||
@ -60,8 +60,8 @@ http://xxx:yyy@%HOSTIP:%HTTPPORT/%TESTNUMBER/testapi/test
|
||||
</strip>
|
||||
<protocol>
|
||||
GET /%TESTNUMBER/testapi/test HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
Authorization: XXX4-HMAC-SHA256 Credential=xxx/19700101/0/127/xxx4_request, SignedHeaders=content-type;host;x-xxx-date, Signature=d2c2dff48c59ec49dc31ef94f18c5dc1ac3eae2a70d51633a4342dadc0683664
|
||||
Host: 127.0.0.1:9000
|
||||
Authorization: XXX4-HMAC-SHA256 Credential=xxx/19700101/0/127/xxx4_request, SignedHeaders=content-type;host;x-xxx-date, Signature=3d8e00a02e437211a596143dcd590fcc805b731365c68f7f48951ea6eda39c4f
|
||||
X-Xxx-Date: 19700101T000000Z
|
||||
|
||||
</protocol>
|
||||
|
@ -47,7 +47,7 @@ lib%TESTNUMBER
|
||||
</tool>
|
||||
|
||||
<command>
|
||||
http://%HOSTIP:%HTTPPORT/%TESTNUMBER/testapi/test
|
||||
http://127.0.0.1:9000/%TESTNUMBER/testapi/test 127.0.0.1:9000:%HOSTIP:%HTTPPORT
|
||||
</command>
|
||||
</client>
|
||||
|
||||
@ -60,8 +60,8 @@ http://%HOSTIP:%HTTPPORT/%TESTNUMBER/testapi/test
|
||||
</strip>
|
||||
<protocol>
|
||||
GET /%TESTNUMBER/testapi/test HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
Authorization: XXX4-HMAC-SHA256 Credential=xxx/19700101/0/127/xxx4_request, SignedHeaders=content-type;host;x-yyy-date, Signature=938937ca7da6bb3dbf15e30928265ec6f061532d035d2afda92fa7cb10feb196
|
||||
Host: 127.0.0.1:9000
|
||||
Authorization: XXX4-HMAC-SHA256 Credential=xxx/19700101/0/127/xxx4_request, SignedHeaders=content-type;host;x-yyy-date, Signature=cf8dc9a4af903a1a9bb1385d8e2366d780afb501e266436598438395e502d58c
|
||||
X-Yyy-Date: 19700101T000000Z
|
||||
|
||||
</protocol>
|
||||
|
@ -47,7 +47,7 @@ lib%TESTNUMBER
|
||||
</tool>
|
||||
|
||||
<command>
|
||||
http://%HOSTIP:%HTTPPORT/%TESTNUMBER/testapi/test
|
||||
http://127.0.0.1:9000/%TESTNUMBER/testapi/test 127.0.0.1:9000:%HOSTIP:%HTTPPORT
|
||||
</command>
|
||||
</client>
|
||||
|
||||
@ -60,8 +60,8 @@ http://%HOSTIP:%HTTPPORT/%TESTNUMBER/testapi/test
|
||||
</strip>
|
||||
<protocol>
|
||||
GET /%TESTNUMBER/testapi/test HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
Authorization: XXX4-HMAC-SHA256 Credential=xxx/19700101/rrr/127/xxx4_request, SignedHeaders=content-type;host;x-yyy-date, Signature=240750deb9263d4c8ece71c016f3919b56e518249390ef075740f94ef8df846f
|
||||
Host: 127.0.0.1:9000
|
||||
Authorization: XXX4-HMAC-SHA256 Credential=xxx/19700101/rrr/127/xxx4_request, SignedHeaders=content-type;host;x-yyy-date, Signature=a0b11b97b54689428d4188b788ed32865d607822d85d3e91cf06141f479dac0b
|
||||
X-Yyy-Date: 19700101T000000Z
|
||||
|
||||
</protocol>
|
||||
|
@ -47,7 +47,7 @@ lib%TESTNUMBER
|
||||
</tool>
|
||||
|
||||
<command>
|
||||
http://%HOSTIP:%HTTPPORT/%TESTNUMBER/testapi/test
|
||||
http://127.0.0.1:9000/%TESTNUMBER/testapi/test 127.0.0.1:9000:%HOSTIP:%HTTPPORT
|
||||
</command>
|
||||
</client>
|
||||
|
||||
@ -60,8 +60,8 @@ http://%HOSTIP:%HTTPPORT/%TESTNUMBER/testapi/test
|
||||
</strip>
|
||||
<protocol>
|
||||
GET /%TESTNUMBER/testapi/test HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
Authorization: XXX4-HMAC-SHA256 Credential=xxx/19700101/rrr/sss/xxx4_request, SignedHeaders=content-type;host;x-yyy-date, Signature=f32cf87977cea5d3274b524b53e5d28f4aac54c372f710ae0cc3a9ececaf169f
|
||||
Host: 127.0.0.1:9000
|
||||
Authorization: XXX4-HMAC-SHA256 Credential=xxx/19700101/rrr/sss/xxx4_request, SignedHeaders=content-type;host;x-yyy-date, Signature=026b713d76b0789bd224c5e41322f74eed088f8a22fd15183ca68376c575c5b0
|
||||
X-Yyy-Date: 19700101T000000Z
|
||||
|
||||
</protocol>
|
||||
|
@ -48,7 +48,7 @@ lib%TESTNUMBER
|
||||
</tool>
|
||||
|
||||
<command>
|
||||
http://%HOSTIP:%HTTPPORT/%TESTNUMBER/testapi/test
|
||||
http://127.0.0.1:9000/%TESTNUMBER/testapi/test 127.0.0.1:9000:%HOSTIP:%HTTPPORT
|
||||
</command>
|
||||
</client>
|
||||
|
||||
@ -61,8 +61,8 @@ http://%HOSTIP:%HTTPPORT/%TESTNUMBER/testapi/test
|
||||
</strip>
|
||||
<protocol nonewline="yes">
|
||||
POST /%TESTNUMBER/testapi/test HTTP/1.1
|
||||
Host: %HOSTIP:%HTTPPORT
|
||||
Authorization: PROVIDER14-HMAC-SHA256 Credential=keyId/19700101/region/service/provider14_request, SignedHeaders=content-type;host;x-provider2-date, Signature=391e410177d0e9ee80728082446ef69d6b29157fe71f8b4805fce7c186fd956d
|
||||
Host: 127.0.0.1:9000
|
||||
Authorization: PROVIDER14-HMAC-SHA256 Credential=keyId/19700101/region/service/provider14_request, SignedHeaders=content-type;host;x-provider2-date, Signature=4928ccf97a9e71fe27f91db5a3b3c943b6080d25e6f4df8593d4c38e7d1e849b
|
||||
X-Provider2-Date: 19700101T000000Z
|
||||
Content-Length: 8
|
||||
|
||||
|
Binary file not shown.
75
tests/data/test1955
Normal file
75
tests/data/test1955
Normal file
@ -0,0 +1,75 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
# Server-side
|
||||
<reply>
|
||||
<data nocheck="yes">
|
||||
HTTP/1.1 302 OK
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Server: test-server/fake
|
||||
Content-Type: text/html
|
||||
Content-Length: 0
|
||||
Location: /%TESTNUMBER0002
|
||||
|
||||
</data>
|
||||
<data2>
|
||||
HTTP/1.1 200 OK
|
||||
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||
Server: test-server/fake
|
||||
Content-Type: text/html
|
||||
Content-Length: 0
|
||||
|
||||
</data2>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
# this relies on the debug feature which allow to set the time
|
||||
<features>
|
||||
SSL
|
||||
debug
|
||||
crypto
|
||||
</features>
|
||||
<setenv>
|
||||
CURL_FORCEHOST=1
|
||||
</setenv>
|
||||
|
||||
<name>
|
||||
HTTP AWS_SIGV4 with X-Xxx-Content-Sha256
|
||||
</name>
|
||||
<tool>
|
||||
lib%TESTNUMBER
|
||||
</tool>
|
||||
|
||||
<command>
|
||||
http://exam.ple.com:9000/%TESTNUMBER/testapi/test exam.ple.com:9000:%HOSTIP:%HTTPPORT
|
||||
</command>
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<strip>
|
||||
^User-Agent:.*
|
||||
^Content-Type:.*
|
||||
^Accept:.*
|
||||
</strip>
|
||||
<protocol>
|
||||
GET /%TESTNUMBER/testapi/test HTTP/1.1
|
||||
Host: exam.ple.com:9000
|
||||
Authorization: XXX4-HMAC-SHA256 Credential=xxx/19700101/ple/exam/xxx4_request, SignedHeaders=content-type;host;tesmixcase;test0;test1;test2;test_space;x-xxx-date, Signature=819251feec8de52dfaa992320241f23d27cefa979c93e039ae7df03ac486ed16
|
||||
X-Xxx-Date: 19700101T000000Z
|
||||
test2: 1234
|
||||
test_space: t s m end
|
||||
tesMixCase: MixCase
|
||||
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
@ -64,7 +64,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
|
||||
lib1905 lib1906 lib1907 lib1908 lib1910 lib1911 lib1912 lib1913 \
|
||||
lib1915 lib1916 lib1917 lib1918 lib1919 \
|
||||
lib1933 lib1934 lib1935 lib1936 lib1937 lib1938 lib1939 lib1940 \
|
||||
lib1945 lib1946 lib1947 lib1948 \
|
||||
lib1945 lib1946 lib1947 lib1948 lib1955 \
|
||||
lib2301 lib2302 \
|
||||
lib3010 lib3025 lib3026 lib3027
|
||||
|
||||
@ -757,6 +757,10 @@ lib1948_SOURCES = lib1948.c $(SUPPORTFILES)
|
||||
lib1948_LDADD = $(TESTUTIL_LIBS)
|
||||
lib1948_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
lib1955_SOURCES = lib1955.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||
lib1955_LDADD = $(TESTUTIL_LIBS)
|
||||
lib1955_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
lib2301_SOURCES = lib2301.c $(SUPPORTFILES)
|
||||
lib2301_LDADD = $(TESTUTIL_LIBS)
|
||||
|
||||
|
@ -29,6 +29,7 @@ int test(char *URL)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res = TEST_ERR_MAJOR_BAD;
|
||||
struct curl_slist *connect_to = NULL;
|
||||
struct curl_slist *list = NULL;
|
||||
|
||||
if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
|
||||
@ -47,6 +48,10 @@ int test(char *URL)
|
||||
test_setopt(curl, CURLOPT_AWS_SIGV4, "xxx");
|
||||
test_setopt(curl, CURLOPT_HEADER, 0L);
|
||||
test_setopt(curl, CURLOPT_URL, URL);
|
||||
if(libtest_arg2) {
|
||||
connect_to = curl_slist_append(connect_to, libtest_arg2);
|
||||
}
|
||||
test_setopt(curl, CURLOPT_CONNECT_TO, connect_to);
|
||||
list = curl_slist_append(list, "Content-Type: application/json");
|
||||
test_setopt(curl, CURLOPT_HTTPHEADER, list);
|
||||
|
||||
@ -54,6 +59,7 @@ int test(char *URL)
|
||||
|
||||
test_cleanup:
|
||||
|
||||
curl_slist_free_all(connect_to);
|
||||
curl_slist_free_all(list);
|
||||
curl_easy_cleanup(curl);
|
||||
curl_global_cleanup();
|
||||
|
@ -29,6 +29,7 @@ int test(char *URL)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res = TEST_ERR_MAJOR_BAD;
|
||||
struct curl_slist *connect_to = NULL;
|
||||
struct curl_slist *list = NULL;
|
||||
|
||||
if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
|
||||
@ -48,6 +49,10 @@ int test(char *URL)
|
||||
test_setopt(curl, CURLOPT_USERPWD, "xxx:yyy");
|
||||
test_setopt(curl, CURLOPT_HEADER, 0L);
|
||||
test_setopt(curl, CURLOPT_URL, URL);
|
||||
if(libtest_arg2) {
|
||||
connect_to = curl_slist_append(connect_to, libtest_arg2);
|
||||
}
|
||||
test_setopt(curl, CURLOPT_CONNECT_TO, connect_to);
|
||||
list = curl_slist_append(list, "Content-Type: application/json");
|
||||
test_setopt(curl, CURLOPT_HTTPHEADER, list);
|
||||
|
||||
@ -55,6 +60,7 @@ int test(char *URL)
|
||||
|
||||
test_cleanup:
|
||||
|
||||
curl_slist_free_all(connect_to);
|
||||
curl_slist_free_all(list);
|
||||
curl_easy_cleanup(curl);
|
||||
curl_global_cleanup();
|
||||
|
@ -29,6 +29,7 @@ int test(char *URL)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res = TEST_ERR_MAJOR_BAD;
|
||||
struct curl_slist *connect_to = NULL;
|
||||
struct curl_slist *list = NULL;
|
||||
|
||||
if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
|
||||
@ -48,6 +49,10 @@ int test(char *URL)
|
||||
test_setopt(curl, CURLOPT_USERPWD, "xxx:yyy");
|
||||
test_setopt(curl, CURLOPT_HEADER, 0L);
|
||||
test_setopt(curl, CURLOPT_URL, URL);
|
||||
if(libtest_arg2) {
|
||||
connect_to = curl_slist_append(connect_to, libtest_arg2);
|
||||
}
|
||||
test_setopt(curl, CURLOPT_CONNECT_TO, connect_to);
|
||||
list = curl_slist_append(list, "Content-Type: application/json");
|
||||
test_setopt(curl, CURLOPT_HTTPHEADER, list);
|
||||
|
||||
@ -55,6 +60,7 @@ int test(char *URL)
|
||||
|
||||
test_cleanup:
|
||||
|
||||
curl_slist_free_all(connect_to);
|
||||
curl_slist_free_all(list);
|
||||
curl_easy_cleanup(curl);
|
||||
curl_global_cleanup();
|
||||
|
@ -29,6 +29,7 @@ int test(char *URL)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res = TEST_ERR_MAJOR_BAD;
|
||||
struct curl_slist *connect_to = NULL;
|
||||
struct curl_slist *list = NULL;
|
||||
|
||||
if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
|
||||
@ -48,6 +49,10 @@ int test(char *URL)
|
||||
test_setopt(curl, CURLOPT_USERPWD, "xxx:yyy");
|
||||
test_setopt(curl, CURLOPT_HEADER, 0L);
|
||||
test_setopt(curl, CURLOPT_URL, URL);
|
||||
if(libtest_arg2) {
|
||||
connect_to = curl_slist_append(connect_to, libtest_arg2);
|
||||
}
|
||||
test_setopt(curl, CURLOPT_CONNECT_TO, connect_to);
|
||||
list = curl_slist_append(list, "Content-Type: application/json");
|
||||
test_setopt(curl, CURLOPT_HTTPHEADER, list);
|
||||
|
||||
@ -55,6 +60,7 @@ int test(char *URL)
|
||||
|
||||
test_cleanup:
|
||||
|
||||
curl_slist_free_all(connect_to);
|
||||
curl_slist_free_all(list);
|
||||
curl_easy_cleanup(curl);
|
||||
curl_global_cleanup();
|
||||
|
@ -30,6 +30,7 @@ int test(char *URL)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res = TEST_ERR_MAJOR_BAD;
|
||||
struct curl_slist *connect_to = NULL;
|
||||
struct curl_slist *list = NULL;
|
||||
|
||||
if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
|
||||
@ -50,6 +51,10 @@ int test(char *URL)
|
||||
test_setopt(curl, CURLOPT_USERPWD, "keyId:SecretKey");
|
||||
test_setopt(curl, CURLOPT_HEADER, 0L);
|
||||
test_setopt(curl, CURLOPT_URL, URL);
|
||||
if(libtest_arg2) {
|
||||
connect_to = curl_slist_append(connect_to, libtest_arg2);
|
||||
}
|
||||
test_setopt(curl, CURLOPT_CONNECT_TO, connect_to);
|
||||
list = curl_slist_append(list, "Content-Type: application/json");
|
||||
test_setopt(curl, CURLOPT_HTTPHEADER, list);
|
||||
test_setopt(curl, CURLOPT_POSTFIELDS, "postData");
|
||||
@ -58,6 +63,7 @@ int test(char *URL)
|
||||
|
||||
test_cleanup:
|
||||
|
||||
curl_slist_free_all(connect_to);
|
||||
curl_slist_free_all(list);
|
||||
curl_easy_cleanup(curl);
|
||||
curl_global_cleanup();
|
||||
|
@ -30,6 +30,7 @@ int test(char *URL)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res = TEST_ERR_MAJOR_BAD;
|
||||
struct curl_slist *connect_to = NULL;
|
||||
struct curl_slist *list = NULL;
|
||||
unsigned char data[] = {0x70, 0x6f, 0x73, 0x74, 0, 0x44, 0x61, 0x74, 0x61};
|
||||
|
||||
@ -51,6 +52,10 @@ int test(char *URL)
|
||||
test_setopt(curl, CURLOPT_USERPWD, "keyId:SecretKey");
|
||||
test_setopt(curl, CURLOPT_HEADER, 0L);
|
||||
test_setopt(curl, CURLOPT_URL, URL);
|
||||
if(libtest_arg2) {
|
||||
connect_to = curl_slist_append(connect_to, libtest_arg2);
|
||||
}
|
||||
test_setopt(curl, CURLOPT_CONNECT_TO, connect_to);
|
||||
list = curl_slist_append(list, "Content-Type: application/json");
|
||||
test_setopt(curl, CURLOPT_HTTPHEADER, list);
|
||||
test_setopt(curl, CURLOPT_POSTFIELDS, data);
|
||||
@ -60,6 +65,7 @@ int test(char *URL)
|
||||
|
||||
test_cleanup:
|
||||
|
||||
curl_slist_free_all(connect_to);
|
||||
curl_slist_free_all(list);
|
||||
curl_easy_cleanup(curl);
|
||||
curl_global_cleanup();
|
||||
|
76
tests/libtest/lib1955.c
Normal file
76
tests/libtest/lib1955.c
Normal file
@ -0,0 +1,76 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "test.h"
|
||||
|
||||
#include "memdebug.h"
|
||||
|
||||
int test(char *URL)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res = TEST_ERR_MAJOR_BAD;
|
||||
struct curl_slist *list = NULL;
|
||||
struct curl_slist *connect_to = NULL;
|
||||
|
||||
if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
|
||||
fprintf(stderr, "curl_global_init() failed\n");
|
||||
return TEST_ERR_MAJOR_BAD;
|
||||
}
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(!curl) {
|
||||
fprintf(stderr, "curl_easy_init() failed\n");
|
||||
curl_global_cleanup();
|
||||
return TEST_ERR_MAJOR_BAD;
|
||||
}
|
||||
|
||||
test_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||
test_setopt(curl, CURLOPT_AWS_SIGV4, "xxx");
|
||||
test_setopt(curl, CURLOPT_USERPWD, "xxx");
|
||||
test_setopt(curl, CURLOPT_HEADER, 0L);
|
||||
test_setopt(curl, CURLOPT_URL, URL);
|
||||
list = curl_slist_append(list, "test2: 1234");
|
||||
if(!list)
|
||||
goto test_cleanup;
|
||||
if(libtest_arg2) {
|
||||
connect_to = curl_slist_append(connect_to, libtest_arg2);
|
||||
}
|
||||
test_setopt(curl, CURLOPT_CONNECT_TO, connect_to);
|
||||
curl_slist_append(list, "Content-Type: application/json");
|
||||
curl_slist_append(list, "test1:");
|
||||
curl_slist_append(list, "test0");
|
||||
curl_slist_append(list, "test_space: t\ts m\t end ");
|
||||
curl_slist_append(list, "tesMixCase: MixCase");
|
||||
test_setopt(curl, CURLOPT_HTTPHEADER, list);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
test_cleanup:
|
||||
|
||||
curl_slist_free_all(connect_to);
|
||||
curl_slist_free_all(list);
|
||||
curl_easy_cleanup(curl);
|
||||
curl_global_cleanup();
|
||||
|
||||
return res;
|
||||
}
|
Loading…
Reference in New Issue
Block a user