fail-with-body.md \
fail.md \
false-start.md \
+ follow.md \
form-escape.md \
form-string.md \
form.md \
--- /dev/null
+---
+c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+SPDX-License-Identifier: curl
+Long: follow
+Help: Follow redirects per spec
+Category: http
+Added: 8.16.0
+Multi: boolean
+See-also:
+ - request
+ - location
+Example:
+ - -X POST --follow $URL
+---
+
+# `--follow`
+
+Instructs curl to follow HTTP redirects and to do the custom request method
+set with --request when following redirects as the HTTP specification says.
+
+The method string set with --request is used in subsequent requests for the
+status codes 307 or 308, but may be reset to GET for 301, 302 and 303.
+
+This is subtly different than --location, as that option always set the custom
+method in all subsequent requests independent of response code.
Multi: boolean
See-also:
- user
+ - follow
Example:
- --location-trusted -u user:password $URL
- --location-trusted -H "Cookie: session=abc" $URL
See-also:
- resolve
- alt-svc
+ - follow
Example:
- -L $URL
---
--range (-r) 4.0
--rate 7.84.0
--raw 7.16.2
+--follow 8.16.0
--referer (-e) 4.0
--remote-header-name (-J) 7.20.0
--remote-name (-O) 4.0
{
long postRedir = 0;
- my_setopt_long(curl, CURLOPT_FOLLOWLOCATION,
- config->followlocation);
+ my_setopt_long(curl, CURLOPT_FOLLOWLOCATION, config->followlocation);
my_setopt_long(curl, CURLOPT_UNRESTRICTED_AUTH,
config->unrestricted_auth);
my_setopt_str(curl, CURLOPT_AWS_SIGV4, config->aws_sigv4);
long happy_eyeballs_timeout_ms; /* happy eyeballs timeout in milliseconds.
0 is valid. default: CURL_HET_DEFAULT. */
unsigned long timecond;
+ long followlocation; /* follow http redirects mode */
HttpReq httpreq;
long proxyver; /* set to CURLPROXY_HTTP* define */
long ftp_ssl_ccc_mode;
BIT(show_headers); /* show headers to data output */
BIT(no_body); /* do not get the body */
BIT(dirlistonly); /* only get the FTP dir list */
- BIT(followlocation); /* follow http redirects */
BIT(unrestricted_auth); /* Continue to send authentication (user+password)
when following redirects, even when hostname
changed */
{"fail-early", ARG_BOOL, ' ', C_FAIL_EARLY},
{"fail-with-body", ARG_BOOL, ' ', C_FAIL_WITH_BODY},
{"false-start", ARG_BOOL, ' ', C_FALSE_START},
+ {"follow", ARG_BOOL, ' ', C_FOLLOW},
{"form", ARG_STRG, 'F', C_FORM},
{"form-escape", ARG_BOOL, ' ', C_FORM_ESCAPE},
{"form-string", ARG_STRG, ' ', C_FORM_STRING},
case C_LIST_ONLY: /* --list-only */
config->dirlistonly = toggle; /* only list the names of the FTP dir */
break;
- case C_LOCATION_TRUSTED: /* --location-trusted */
- config->unrestricted_auth = toggle;
- FALLTHROUGH();
- case C_LOCATION: /* --location */
- config->followlocation = toggle; /* Follow Location: HTTP headers */
- break;
case C_MANUAL: /* --manual */
if(toggle) /* --no-manual shows no manual... */
return PARAM_MANUAL_REQUESTED;
case C_MPTCP: /* --mptcp */
config->mptcp = toggle;
break;
+ case C_LOCATION_TRUSTED: /* --location-trusted */
+ config->unrestricted_auth = toggle;
+ FALLTHROUGH();
+ case C_LOCATION: /* --location */
+ if(config->followlocation == CURLFOLLOW_OBEYCODE)
+ warnf(global, "--location overrides --follow");
+ config->followlocation = toggle ? CURLFOLLOW_ALL : 0;
+ break;
+ case C_FOLLOW: /* --follow */
+ if(config->followlocation == CURLFOLLOW_ALL)
+ warnf(global, "--follow overrides --location");
+ config->followlocation = toggle ? CURLFOLLOW_OBEYCODE : 0;
+ break;
default:
return PARAM_OPTION_UNKNOWN;
}
C_FAIL_EARLY,
C_FAIL_WITH_BODY,
C_FALSE_START,
+ C_FOLLOW,
C_FORM,
C_FORM_ESCAPE,
C_FORM_STRING,
{" --false-start",
"Enable TLS False Start",
CURLHELP_DEPRECATED},
+ {" --follow",
+ "Follow redirects per spec",
+ CURLHELP_HTTP},
{"-F, --form <name=content>",
"Specify multipart MIME data",
CURLHELP_HTTP | CURLHELP_UPLOAD | CURLHELP_POST | CURLHELP_IMAP |
NVEND,
};
+const struct NameValue setopt_nv_CURLOPT_FOLLOWLOCATION[] = {
+ NV(0L),
+ NV(CURLFOLLOW_ALL),
+ NV(CURLFOLLOW_OBEYCODE),
+ NV(CURLFOLLOW_FIRSTONLY),
+ NVEND,
+};
+
/* These options have non-zero default values. */
static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = {
NV1(CURLOPT_SSL_VERIFYPEER, 1),
extern const struct NameValue setopt_nv_CURLUSESSL[];
extern const struct NameValueUnsigned setopt_nv_CURLSSLOPT[];
extern const struct NameValue setopt_nv_CURL_NETRC[];
+extern const struct NameValue setopt_nv_CURLOPT_FOLLOWLOCATION[];
extern const struct NameValueUnsigned setopt_nv_CURLAUTH[];
extern const struct NameValueUnsigned setopt_nv_CURLHSTS[];
test745 test746 test747 test748 test749 test750 test751 test752 test753 \
test754 test755 test756 test757 \
test780 test781 test782 test783 test784 test785 test786 test787 test788 \
-test789 test790 test791 test792 test793 \
+test789 test790 test791 test792 test793 test794 test796 test797 \
\
test799 test800 test801 test802 test803 test804 test805 test806 test807 \
test808 test809 test810 test811 test812 test813 test814 test815 test816 \
--- /dev/null
+<testcase>
+<info>
+<keywords>
+--follow
+--location
+</keywords>
+</info>
+#
+# Server-side
+<reply>
+<data crlf="yes">
+HTTP/1.1 302 OK
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Location: %TESTNUMBER0001
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+
+-foo-
+</data>
+<data1 crlf="yes">
+HTTP/1.1 200 OK
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+
+-bar-
+</data1>
+<datacheck crlf="yes">
+HTTP/1.1 302 OK
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Location: %TESTNUMBER0001
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+
+HTTP/1.1 200 OK
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+
+-bar-
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+<features>
+http
+</features>
+
+<name>
+--follow + --location with custom POST method, 302 => GET
+</name>
+<command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --no-progress-meter -X IGLOO -d moo --location --follow
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol nonewline="yes" crlf="yes">
+IGLOO /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Content-Length: 3
+Content-Type: application/x-www-form-urlencoded
+
+mooGET /%TESTNUMBER0001 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+
+</protocol>
+<stderr mode="text">
+Warning: --follow overrides --location
+</stderr>
+</verify>
+</testcase>
--- /dev/null
+<testcase>
+<info>
+<keywords>
+--follow
+--location
+</keywords>
+</info>
+#
+# Server-side
+<reply>
+<data crlf="yes">
+HTTP/1.1 302 OK
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Location: %TESTNUMBER0001
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+
+-foo-
+</data>
+<data1 crlf="yes">
+HTTP/1.1 200 OK
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+
+-bar-
+</data1>
+<datacheck crlf="yes">
+HTTP/1.1 302 OK
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Location: %TESTNUMBER0001
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+
+HTTP/1.1 200 OK
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+
+-bar-
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+<features>
+http
+</features>
+
+<name>
+--follow with custom POST method, 302 => GET
+</name>
+<command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -X IGLOO -d moo --follow
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol nonewline="yes" crlf="yes">
+IGLOO /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Content-Length: 3
+Content-Type: application/x-www-form-urlencoded
+
+mooGET /%TESTNUMBER0001 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+
+</protocol>
+</verify>
+</testcase>
--- /dev/null
+<testcase>
+<info>
+<keywords>
+--follow
+--location
+</keywords>
+</info>
+#
+# Server-side
+<reply>
+<data crlf="yes">
+HTTP/1.1 308 OK
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Location: %TESTNUMBER0001
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+
+-foo-
+</data>
+<data1 crlf="yes">
+HTTP/1.1 200 OK
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+
+-bar-
+</data1>
+<datacheck crlf="yes">
+HTTP/1.1 308 OK
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Location: %TESTNUMBER0001
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+
+HTTP/1.1 200 OK
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+
+-bar-
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+<features>
+http
+</features>
+
+<name>
+--follow with custom POST method, 308 => custom
+</name>
+<command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -X IGLOO -d moo --follow
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol nonewline="yes" crlf="yes">
+IGLOO /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Content-Length: 3
+Content-Type: application/x-www-form-urlencoded
+
+mooIGLOO /%TESTNUMBER0001 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Content-Length: 3
+Content-Type: application/x-www-form-urlencoded
+
+moo
+</protocol>
+</verify>
+</testcase>