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:
parent
5908e900be
commit
942eb09e8a
34
lib/http.c
34
lib/http.c
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user