1
0
mirror of https://github.com/moparisthebest/curl synced 2024-11-15 22:15:13 -05:00

http: make adding a blank header thread-safe

Previously the function would edit the provided header in-place when a
semicolon is used to signify an empty header. This made it impossible to
use the same set of custom headers in multiple threads simultaneously.

This approach now makes a local copy when it needs to edit the string.

Reported-by: d912e3 on github
Fixes #3578
Closes #3579
This commit is contained in:
Daniel Stenberg 2019-02-18 08:14:52 +01:00
parent 5908e900be
commit 942eb09e8a
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2

View File

@ -1790,9 +1790,16 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
} }
else { else {
if(*(--ptr) == ';') { if(*(--ptr) == ';') {
/* send no-value custom header if terminated by semicolon */ /* copy the source */
*ptr = ':'; semicolonp = strdup(headers->data);
semicolonp = ptr; if(!semicolonp) {
Curl_add_buffer_free(&req_buffer);
return CURLE_OUT_OF_MEMORY;
}
/* put a colon where the semicolon is */
semicolonp[ptr - headers->data] = ':';
/* point at the colon */
optr = &semicolonp [ptr - headers->data];
} }
} }
ptr = optr; ptr = optr;
@ -1808,36 +1815,37 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
if(*ptr || semicolonp) { if(*ptr || semicolonp) {
/* only send this if the contents was non-blank or done special */ /* only send this if the contents was non-blank or done special */
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
char *compare = semicolonp ? semicolonp : headers->data;
if(conn->allocptr.host && if(conn->allocptr.host &&
/* a Host: header was sent already, don't pass on any custom Host: /* a Host: header was sent already, don't pass on any custom Host:
header as that will produce *two* in the same request! */ header as that will produce *two* in the same request! */
checkprefix("Host:", headers->data)) checkprefix("Host:", compare))
; ;
else if(data->set.httpreq == HTTPREQ_POST_FORM && else if(data->set.httpreq == HTTPREQ_POST_FORM &&
/* this header (extended by formdata.c) is sent later */ /* this header (extended by formdata.c) is sent later */
checkprefix("Content-Type:", headers->data)) checkprefix("Content-Type:", compare))
; ;
else if(data->set.httpreq == HTTPREQ_POST_MIME && else if(data->set.httpreq == HTTPREQ_POST_MIME &&
/* this header is sent later */ /* this header is sent later */
checkprefix("Content-Type:", headers->data)) checkprefix("Content-Type:", compare))
; ;
else if(conn->bits.authneg && else if(conn->bits.authneg &&
/* while doing auth neg, don't allow the custom length since /* while doing auth neg, don't allow the custom length since
we will force length zero then */ we will force length zero then */
checkprefix("Content-Length:", headers->data)) checkprefix("Content-Length:", compare))
; ;
else if(conn->allocptr.te && else if(conn->allocptr.te &&
/* when asking for Transfer-Encoding, don't pass on a custom /* when asking for Transfer-Encoding, don't pass on a custom
Connection: */ Connection: */
checkprefix("Connection:", headers->data)) checkprefix("Connection:", compare))
; ;
else if((conn->httpversion == 20) && else if((conn->httpversion == 20) &&
checkprefix("Transfer-Encoding:", headers->data)) checkprefix("Transfer-Encoding:", compare))
/* HTTP/2 doesn't support chunked requests */ /* HTTP/2 doesn't support chunked requests */
; ;
else if((checkprefix("Authorization:", headers->data) || else if((checkprefix("Authorization:", compare) ||
checkprefix("Cookie:", headers->data)) && checkprefix("Cookie:", compare)) &&
/* be careful of sending this potentially sensitive header to /* be careful of sending this potentially sensitive header to
other hosts */ other hosts */
(data->state.this_is_a_follow && (data->state.this_is_a_follow &&
@ -1846,10 +1854,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
!strcasecompare(data->state.first_host, conn->host.name))) !strcasecompare(data->state.first_host, conn->host.name)))
; ;
else { else {
result = Curl_add_bufferf(&req_buffer, "%s\r\n", headers->data); result = Curl_add_bufferf(&req_buffer, "%s\r\n", compare);
} }
if(semicolonp) if(semicolonp)
*semicolonp = ';'; /* put back the semicolon */ free(semicolonp);
if(result) if(result)
return result; return result;
} }