1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-23 08:38:49 -05:00

urldata: let the HTTP method be in the set.* struct

When the method is updated inside libcurl we must still not change the
method as set by the user as then repeated transfers with that same
handle might not execute the same operation anymore!

This fixes the libcurl part of #5462

Test 1633 added to verify.

Closes #5499
This commit is contained in:
Daniel Stenberg 2020-06-01 22:58:46 +02:00
parent cba70628ae
commit 9c845be279
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
12 changed files with 154 additions and 60 deletions

View File

@ -431,7 +431,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
skip this rewinding stuff */
return CURLE_OK;
switch(data->set.httpreq) {
switch(data->state.httpreq) {
case HTTPREQ_GET:
case HTTPREQ_HEAD:
return CURLE_OK;
@ -452,7 +452,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
}
else {
/* figure out how much data we are expected to send */
switch(data->set.httpreq) {
switch(data->state.httpreq) {
case HTTPREQ_POST:
case HTTPREQ_PUT:
if(data->state.infilesize != -1)
@ -594,8 +594,8 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
#endif
if(pickhost || pickproxy) {
if((data->set.httpreq != HTTPREQ_GET) &&
(data->set.httpreq != HTTPREQ_HEAD) &&
if((data->state.httpreq != HTTPREQ_GET) &&
(data->state.httpreq != HTTPREQ_HEAD) &&
!conn->bits.rewindaftersend) {
result = http_perhapsrewind(conn);
if(result)
@ -616,8 +616,8 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
authentication is not "done" yet and
no authentication seems to be required and
we didn't try HEAD or GET */
if((data->set.httpreq != HTTPREQ_GET) &&
(data->set.httpreq != HTTPREQ_HEAD)) {
if((data->state.httpreq != HTTPREQ_GET) &&
(data->state.httpreq != HTTPREQ_HEAD)) {
data->req.newurl = strdup(data->change.url); /* clone URL */
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
@ -1774,11 +1774,11 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
header as that will produce *two* in the same request! */
checkprefix("Host:", compare))
;
else if(data->set.httpreq == HTTPREQ_POST_FORM &&
else if(data->state.httpreq == HTTPREQ_POST_FORM &&
/* this header (extended by formdata.c) is sent later */
checkprefix("Content-Type:", compare))
;
else if(data->set.httpreq == HTTPREQ_POST_MIME &&
else if(data->state.httpreq == HTTPREQ_POST_MIME &&
/* this header is sent later */
checkprefix("Content-Type:", compare))
;
@ -1915,7 +1915,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
const char *te = ""; /* transfer-encoding */
const char *ptr;
const char *request;
Curl_HttpReq httpreq = data->set.httpreq;
Curl_HttpReq httpreq = data->state.httpreq;
#if !defined(CURL_DISABLE_COOKIES)
char *addcookies = NULL;
#endif
@ -3320,7 +3320,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if((k->size == -1) && !k->chunk && !conn->bits.close &&
(conn->httpversion == 11) &&
!(conn->handler->protocol & CURLPROTO_RTSP) &&
data->set.httpreq != HTTPREQ_HEAD) {
data->state.httpreq != HTTPREQ_HEAD) {
/* On HTTP 1.1, when connection is not to get closed, but no
Content-Length nor Transfer-Encoding chunked have been
received, according to RFC2616 section 4.4 point 5, we
@ -3415,7 +3415,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* continue sending even if it gets discarded
*/
switch(data->set.httpreq) {
switch(data->state.httpreq) {
case HTTPREQ_PUT:
case HTTPREQ_POST:
case HTTPREQ_POST_FORM:
@ -3671,7 +3671,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* depending on how authentication is working. Other codes
* are definitely errors, so give up here.
*/
if(data->state.resume_from && data->set.httpreq == HTTPREQ_GET &&
if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
k->httpcode == 416) {
/* "Requested Range Not Satisfiable", just proceed and
pretend this is no error */

View File

@ -2031,7 +2031,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
h2_pri_spec(conn->data, &pri_spec);
switch(conn->data->set.httpreq) {
switch(conn->data->state.httpreq) {
case HTTPREQ_POST:
case HTTPREQ_POST_FORM:
case HTTPREQ_POST_MIME:

View File

@ -591,7 +591,7 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
if(result)
break;
if(conn->data->set.httpreq == HTTPREQ_POST) {
if(conn->data->state.httpreq == HTTPREQ_POST) {
result = mqtt_publish(conn);
if(!result) {
result = mqtt_disconnect(conn);

View File

@ -498,14 +498,14 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(data->set.upload) {
putsize = data->state.infilesize;
data->set.httpreq = HTTPREQ_PUT;
data->state.httpreq = HTTPREQ_PUT;
}
else {
postsize = (data->state.infilesize != -1)?
data->state.infilesize:
(data->set.postfields? (curl_off_t)strlen(data->set.postfields):0);
data->set.httpreq = HTTPREQ_POST;
data->state.httpreq = HTTPREQ_POST;
}
if(putsize > 0 || postsize > 0) {
@ -543,7 +543,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
}
else if(rtspreq == RTSPREQ_GET_PARAMETER) {
/* Check for an empty GET_PARAMETER (heartbeat) request */
data->set.httpreq = HTTPREQ_HEAD;
data->state.httpreq = HTTPREQ_HEAD;
data->set.opt_no_body = TRUE;
}
}

View File

@ -271,6 +271,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Do not include the body part in the output data stream.
*/
data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE;
if(data->set.opt_no_body)
/* in HTTP lingo, no body means using the HEAD request... */
data->set.method = HTTPREQ_HEAD;
break;
case CURLOPT_FAILONERROR:
/*
@ -292,13 +295,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE;
if(data->set.upload) {
/* If this is HTTP, PUT is what's needed to "upload" */
data->set.httpreq = HTTPREQ_PUT;
data->set.method = HTTPREQ_PUT;
data->set.opt_no_body = FALSE; /* this is implied */
}
else
/* In HTTP, the opposite of upload is GET (unless NOBODY is true as
then this can be changed to HEAD later on) */
data->set.httpreq = HTTPREQ_GET;
data->set.method = HTTPREQ_GET;
break;
case CURLOPT_REQUEST_TARGET:
result = Curl_setstropt(&data->set.str[STRING_TARGET],
@ -516,11 +519,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
CURLOPT_POSTFIELDS isn't used and the POST data is read off the
callback! */
if(va_arg(param, long)) {
data->set.httpreq = HTTPREQ_POST;
data->set.method = HTTPREQ_POST;
data->set.opt_no_body = FALSE; /* this is implied */
}
else
data->set.httpreq = HTTPREQ_GET;
data->set.method = HTTPREQ_GET;
break;
case CURLOPT_COPYPOSTFIELDS:
@ -567,7 +570,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
}
data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
data->set.httpreq = HTTPREQ_POST;
data->set.method = HTTPREQ_POST;
break;
case CURLOPT_POSTFIELDS:
@ -577,7 +580,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.postfields = va_arg(param, void *);
/* Release old copied data. */
(void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
data->set.httpreq = HTTPREQ_POST;
data->set.method = HTTPREQ_POST;
break;
case CURLOPT_POSTFIELDSIZE:
@ -623,7 +626,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Set to make us do HTTP POST
*/
data->set.httppost = va_arg(param, struct curl_httppost *);
data->set.httpreq = HTTPREQ_POST_FORM;
data->set.method = HTTPREQ_POST_FORM;
data->set.opt_no_body = FALSE; /* this is implied */
break;
#endif /* CURL_DISABLE_HTTP */
@ -635,7 +638,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = Curl_mime_set_subparts(&data->set.mimepost,
va_arg(param, curl_mime *), FALSE);
if(!result) {
data->set.httpreq = HTTPREQ_POST_MIME;
data->set.method = HTTPREQ_POST_MIME;
data->set.opt_no_body = FALSE; /* this is implied */
}
break;
@ -830,7 +833,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Set to force us do HTTP GET
*/
if(va_arg(param, long)) {
data->set.httpreq = HTTPREQ_GET;
data->set.method = HTTPREQ_GET;
data->set.upload = FALSE; /* switch off upload */
data->set.opt_no_body = FALSE; /* this is implied */
}
@ -940,7 +943,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
va_arg(param, char *));
/* we don't set
data->set.httpreq = HTTPREQ_CUSTOM;
data->set.method = HTTPREQ_CUSTOM;
here, we continue as if we were using the already set type
and this just changes the actual request keyword */
break;

View File

@ -433,8 +433,8 @@ CURLcode Curl_readrewind(struct connectdata *conn)
}
if(data->set.postfields)
; /* do nothing */
else if(data->set.httpreq == HTTPREQ_POST_MIME ||
data->set.httpreq == HTTPREQ_POST_FORM) {
else if(data->state.httpreq == HTTPREQ_POST_MIME ||
data->state.httpreq == HTTPREQ_POST_FORM) {
if(Curl_mime_rewind(mimepart)) {
failf(data, "Cannot rewind mime/post data");
return CURLE_SEND_FAIL_REWIND;
@ -719,7 +719,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
infof(data, "Ignoring the response-body\n");
}
if(data->state.resume_from && !k->content_range &&
(data->set.httpreq == HTTPREQ_GET) &&
(data->state.httpreq == HTTPREQ_GET) &&
!k->ignorebody) {
if(k->size == data->state.resume_from) {
@ -1449,6 +1449,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
}
}
data->state.httpreq = data->set.method;
data->change.url = data->set.str[STRING_SET_URL];
/* Init the SSL session ID cache here. We do it here since we want to do it
@ -1469,10 +1470,10 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
data->state.authproxy.want = data->set.proxyauth;
Curl_safefree(data->info.wouldredirect);
if(data->set.httpreq == HTTPREQ_PUT)
if(data->state.httpreq == HTTPREQ_PUT)
data->state.infilesize = data->set.filesize;
else if((data->set.httpreq != HTTPREQ_GET) &&
(data->set.httpreq != HTTPREQ_HEAD)) {
else if((data->state.httpreq != HTTPREQ_GET) &&
(data->state.httpreq != HTTPREQ_HEAD)) {
data->state.infilesize = data->set.postfieldsize;
if(data->set.postfields && (data->state.infilesize == -1))
data->state.infilesize = (curl_off_t)strlen(data->set.postfields);
@ -1683,12 +1684,12 @@ CURLcode Curl_follow(struct Curl_easy *data,
* This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and
* can be overridden with CURLOPT_POSTREDIR.
*/
if((data->set.httpreq == HTTPREQ_POST
|| data->set.httpreq == HTTPREQ_POST_FORM
|| data->set.httpreq == HTTPREQ_POST_MIME)
if((data->state.httpreq == HTTPREQ_POST
|| data->state.httpreq == HTTPREQ_POST_FORM
|| data->state.httpreq == HTTPREQ_POST_MIME)
&& !(data->set.keep_post & CURL_REDIR_POST_301)) {
infof(data, "Switch from POST to GET\n");
data->set.httpreq = HTTPREQ_GET;
data->state.httpreq = HTTPREQ_GET;
}
break;
case 302: /* Found */
@ -1708,12 +1709,12 @@ CURLcode Curl_follow(struct Curl_easy *data,
* This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and
* can be overridden with CURLOPT_POSTREDIR.
*/
if((data->set.httpreq == HTTPREQ_POST
|| data->set.httpreq == HTTPREQ_POST_FORM
|| data->set.httpreq == HTTPREQ_POST_MIME)
if((data->state.httpreq == HTTPREQ_POST
|| data->state.httpreq == HTTPREQ_POST_FORM
|| data->state.httpreq == HTTPREQ_POST_MIME)
&& !(data->set.keep_post & CURL_REDIR_POST_302)) {
infof(data, "Switch from POST to GET\n");
data->set.httpreq = HTTPREQ_GET;
data->state.httpreq = HTTPREQ_GET;
}
break;
@ -1723,12 +1724,12 @@ CURLcode Curl_follow(struct Curl_easy *data,
* method is POST and the user specified to keep it as POST.
* https://github.com/curl/curl/issues/5237#issuecomment-614641049
*/
if(data->set.httpreq != HTTPREQ_GET &&
((data->set.httpreq != HTTPREQ_POST &&
data->set.httpreq != HTTPREQ_POST_FORM &&
data->set.httpreq != HTTPREQ_POST_MIME) ||
if(data->state.httpreq != HTTPREQ_GET &&
((data->state.httpreq != HTTPREQ_POST &&
data->state.httpreq != HTTPREQ_POST_FORM &&
data->state.httpreq != HTTPREQ_POST_MIME) ||
!(data->set.keep_post & CURL_REDIR_POST_303))) {
data->set.httpreq = HTTPREQ_GET;
data->state.httpreq = HTTPREQ_GET;
data->set.upload = false;
infof(data, "Switch to %s\n",
data->set.opt_no_body?"HEAD":"GET");

View File

@ -462,7 +462,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->postfieldsize = -1; /* unknown size */
set->maxredirs = -1; /* allow any amount by default */
set->httpreq = HTTPREQ_GET; /* Default HTTP request */
set->method = HTTPREQ_GET; /* Default HTTP request */
set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
#ifndef CURL_DISABLE_FTP
set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
@ -3992,17 +3992,9 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
data->state.done = FALSE; /* *_done() is not called yet */
data->state.expect100header = FALSE;
if(data->set.opt_no_body)
/* in HTTP lingo, no body means using the HEAD request... */
data->set.httpreq = HTTPREQ_HEAD;
else if(HTTPREQ_HEAD == data->set.httpreq)
/* ... but if unset there really is no perfect method that is the
"opposite" of HEAD but in reality most people probably think GET
then. The important thing is that we can't let it remain HEAD if the
opt_no_body is set FALSE since then we'll behave wrong when getting
HTTP. */
data->set.httpreq = HTTPREQ_GET;
data->state.httpreq = HTTPREQ_HEAD;
k->start = Curl_now(); /* start time */
k->now = k->start; /* current time is now */

View File

@ -1390,6 +1390,7 @@ struct UrlState {
int stream_weight;
CURLU *uh; /* URL handle for the current parsed URL */
struct urlpieces up;
Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */
#ifndef CURL_DISABLE_HTTP
size_t trailers_bytes_sent;
struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
@ -1678,7 +1679,7 @@ struct UserDefined {
the hostname and port to connect to */
curl_TimeCond timecondition; /* kind of time/date comparison */
time_t timevalue; /* what time to compare with */
Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */
Curl_HttpReq method; /* what kind of HTTP request (if any) is this */
long httpversion; /* when non-zero, a specific HTTP version requested to
be used in the library's request(s) */
struct ssl_config_data ssl; /* user defined SSL stuff */

View File

@ -1558,7 +1558,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
}
}
switch(data->set.httpreq) {
switch(data->state.httpreq) {
case HTTPREQ_POST:
case HTTPREQ_POST_FORM:
case HTTPREQ_POST_MIME:

View File

@ -734,7 +734,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
}
}
switch(data->set.httpreq) {
switch(data->state.httpreq) {
case HTTPREQ_POST:
case HTTPREQ_POST_FORM:
case HTTPREQ_POST_MIME:

View File

@ -196,7 +196,7 @@ test1608 test1609 test1610 test1611 test1612 \
\
test1620 test1621 \
\
test1630 test1631 test1632 \
test1630 test1631 test1632 test1633 \
\
test1650 test1651 test1652 test1653 test1654 test1655 \
\

97
tests/data/test1633 Normal file
View File

@ -0,0 +1,97 @@
<testcase>
<info>
<keywords>
HTTP
HTTP GET
</keywords>
</info>
#
# Server-side
<reply>
<data>
HTTP/1.1 301 OK
Accept-Ranges: bytes
Content-Length: 0
Connection: close
Location: /16330002
</data>
<data2>
HTTP/1.1 429 too many requests
Retry-After: 1
Content-Length: 0
Connection: close
</data2>
<datacheck>
HTTP/1.1 301 OK
Accept-Ranges: bytes
Content-Length: 0
Connection: close
Location: /16330002
HTTP/1.1 429 too many requests
Retry-After: 1
Content-Length: 0
Connection: close
HTTP/1.1 301 OK
Accept-Ranges: bytes
Content-Length: 0
Connection: close
Location: /16330002
HTTP/1.1 429 too many requests
Retry-After: 1
Content-Length: 0
Connection: close
</datacheck>
</reply>
#
# Client-side
<client>
<server>
http
</server>
<name>
HTTP GET
</name>
<command>
http://%HOSTIP:%HTTPPORT/1633 -d moo --retry 1 -L
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<strip>
^User-Agent:.*
</strip>
<protocol>
POST /1633 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
Content-Length: 3
Content-Type: application/x-www-form-urlencoded
mooGET /16330002 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
POST /1633 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
Content-Length: 3
Content-Type: application/x-www-form-urlencoded
mooGET /16330002 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
</protocol>
</verify>
</testcase>