]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
urldata: let the HTTP method be in the set.* struct
authorDaniel Stenberg <daniel@haxx.se>
Mon, 1 Jun 2020 20:58:46 +0000 (22:58 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 2 Jun 2020 14:30:36 +0000 (16:30 +0200)
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

12 files changed:
lib/http.c
lib/http2.c
lib/mqtt.c
lib/rtsp.c
lib/setopt.c
lib/transfer.c
lib/url.c
lib/urldata.h
lib/vquic/ngtcp2.c
lib/vquic/quiche.c
tests/data/Makefile.inc
tests/data/test1633 [new file with mode: 0644]

index 0c3df4c507b71c3575ea25f500ad176dcf0de7d2..a0d3eca24fe032b4b47d6bd2afcf9d8c5477aca0 100644 (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 */
index 7d56e2280f1e696f71fd1703e9287acf1c6f753c..61990019e79b14db9a8d77d35084d12f7a1f48cd 100644 (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:
index 43a3b6e532cfd9e128e44bffa80a4cf545eaa2aa..d09aab4eefed5195aba320aa3b4c950016d43641 100644 (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);
index 9c86b6171df411ef45b9b0326231785768a94756..2a9c683c3efa130c11177e9c7d753170eb1adcd4 100644 (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;
     }
   }
index fc914aa09e1a777628b677beb6bb960c388e0a23..90edf6aa7a0092963e0d6684194876b755a1446a 100644 (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;
index 319744985bb9aca09921ea79e0e9c67be4f8850b..133a4783c6741926ad605f974e293a2b95295772 100644 (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");
index adc9767dbe76bfd7727241d66c532f905ba649fd..524d968c2f8c76a29ad19bb99f8f0792a4362682 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -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 */
index db6af9d10b6d987308f3d89168afc14741703a59..d3cc5356ef4a4e8bac152d13f04449ee2115ab1a 100644 (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 */
index 40bc0f3f0b0e3c7f25f14f4e74564e0559f370b8..eaff638b435554ff177dcc797ee55ff4c43fc1ee 100644 (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:
index 83815e037d21e192368b6c2f1c574de149d558f1..f93e95ee196dbdcd9087c27936a97bb7e483bb14 100644 (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:
index 0633ccb2fe39a62184972233d8fba8b396e91248..7a048f01ac91240714e13c16d6b866549d2dd6be 100644 (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 \
 \
diff --git a/tests/data/test1633 b/tests/data/test1633
new file mode 100644 (file)
index 0000000..5d29ef1
--- /dev/null
@@ -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\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+Content-Length: 3\r
+Content-Type: application/x-www-form-urlencoded\r
+\r
+mooGET /16330002 HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+\r
+POST /1633 HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+Content-Length: 3\r
+Content-Type: application/x-www-form-urlencoded\r
+\r
+mooGET /16330002 HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+\r
+</protocol>
+</verify>
+</testcase>