Unverified Commit cf91707a authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

CURLOPT_FOLLOWLOCATION: add a CURLFOLLOW_NO_CUSTOMREQUEST bit

With this change, the argument passed to the CURLOPT_FOLLOWLOCATION
option is treated as a bitmask instead of just a long. If the new
CURLFOLLOW_NO_CUSTOMREQUEST bit is set in the bitmask, it means that
libcurl will NOT allow a custom method override the HTTP request method
after a redirect is followed. As is otherwise the default behavior (that
surprises many users).

This change is forward compatible because CURLOPT_FOLLOWLOCATION has
been documented to accept the exact value of '1' to enable redirect
following and therefore the other bits were left unused and
undefined. We now add value to another bit. Starting in 7.66.0, the
value 1 and the first bit still enables plain redirect following but the
second bit adds more meaning.

This change is backward compatible in the following way: setting the
CURLFOLLOW_NO_CUSTOMREQUEST bit in a program that still uses an older
libcurl installation at run-tim will have no effect. This is because
older libcurl code checked if the value was non-zero and then enabled
redirect following. Of course older libcurl will always let the set
CURLOPT_CUSTOMREQUEST string override the method, disregarding what the
HTTP response code suggests.

Test 1563 added to verify the functionality.
parent 8581e192
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
.\" *                            | (__| |_| |  _ <| |___
.\" *                             \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" * Copyright (C) 1998 - 2019, 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
@@ -58,6 +58,12 @@ possibly confuse the remote server badly. Use \fICURLOPT_POST(3)\fP and
to replace or extend the set of headers sent by libcurl. Use
\fICURLOPT_HTTP_VERSION(3)\fP to change HTTP version.

If this option used together with \fICURLOPT_FOLLOWLOCATION(3)\fP, the custom
set method will by default override the method libcurl could otherwise change
to. Starting in libcurl 7.66.0, you can fine-tune that decision by using the
\fICURLFOLLOW_IGNORE_CUSTOM\fP bit to \fICURLOPT_FOLLOWLOCATION(3)\fP to make
redirects ignore the custom method.

.IP FTP
Instead of LIST and NLST when performing FTP directory listings.
.IP IMAP
+12 −4
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
.\" *                            | (__| |_| |  _ <| |___
.\" *                             \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" * Copyright (C) 1998 - 2019, 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
@@ -28,9 +28,15 @@ CURLOPT_FOLLOWLOCATION \- follow HTTP 3xx redirects

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FOLLOWLOCATION, long enable);
.SH DESCRIPTION
A long parameter set to 1 tells the library to follow any Location: header
that the server sends as part of an HTTP header in a 3xx response. The
Location: header can specify a relative or an absolute URL to follow.
The long parameter \fIenable\fP set to 1 tells the library to follow any
Location: header that the server sends as part of an HTTP header in a 3xx
response. The Location: header can specify a relative or an absolute URL to
follow.

\fIenable\fP is a bitmask. If you set the \fICURLFOLLOW_NO_CUSTOMREQUEST\fP
bit, it will tell libcurl that the method set with
\fICURLOPT_CUSTOMREQUEST(3)\fP will not be used after a redirect if the HTTP
response says so.

libcurl will issue another request for the new URL and follow new Location:
headers all the way until no more such headers are returned.
@@ -72,6 +78,8 @@ if(curl) {
.fi
.SH AVAILABILITY
Along with HTTP

CURLFOLLOW_NO_CUSTOMREQEUST was added in 7.66.0
.SH RETURN VALUE
Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
.SH "SEE ALSO"
+2 −0
Original line number Diff line number Diff line
@@ -168,6 +168,8 @@ CURLFINFOFLAG_KNOWN_PERM 7.21.0
CURLFINFOFLAG_KNOWN_SIZE        7.21.0
CURLFINFOFLAG_KNOWN_TIME        7.21.0
CURLFINFOFLAG_KNOWN_UID         7.21.0
CURLFOLLOW_ENABLE               7.66.0
CURLFOLLOW_NO_CUSTOMREQUEST     7.66.0
CURLFORM_ARRAY                  7.9.1         7.56.0
CURLFORM_ARRAY_END              7.9.1         7.9.5       7.9.6
CURLFORM_ARRAY_START            7.9.1         7.9.5       7.9.6
+7 −0
Original line number Diff line number Diff line
@@ -165,6 +165,13 @@ typedef enum {
#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL
#define CURLSSLBACKEND_DARWINSSL CURLSSLBACKEND_SECURETRANSPORT

/* bits for the CURLOPT_FOLLOWLOCATION option */
#define CURLFOLLOW_ENABLE (1<<0) /* generic follow redirects */

/* Follow redirects, and don't use the custom method for anything but the
   initial request if the response code says so. */
#define CURLFOLLOW_NO_CUSTOMREQUEST (1<<1)

struct curl_httppost {
  struct curl_httppost *next;       /* next entry in the list */
  char *name;                       /* pointer to allocated name */
+4 −2
Original line number Diff line number Diff line
@@ -2044,8 +2044,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
    httpreq = HTTPREQ_PUT;
  }

  /* Now set the 'request' pointer to the proper request string */
  if(data->set.str[STRING_CUSTOMREQUEST])
  /* Now set the 'request' pointer to the proper request string if
     it isn't a redirect with redirect_clears_method set */
  if(data->set.str[STRING_CUSTOMREQUEST] &&
     (!data->state.this_is_a_follow || !data->set.redirect_clears_method))
    request = data->set.str[STRING_CUSTOMREQUEST];
  else {
    if(data->set.opt_no_body)
Loading