bool reachedmax = FALSE;
char *follow_url = NULL;
CURLUcode uc;
+ CURLcode rewind_result;
+ bool switch_to_get = FALSE;
DEBUGASSERT(type != FOLLOW_NONE);
data->state.url = follow_url;
data->state.url_alloc = TRUE;
- Curl_req_soft_reset(&data->req, data);
+ rewind_result = Curl_req_soft_reset(&data->req, data);
infof(data, "Issue another request to this URL: '%s'", data->state.url);
if((data->set.http_follow_mode == CURLFOLLOW_FIRSTONLY) &&
data->set.str[STRING_CUSTOMREQUEST] &&
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))
+ && !(data->set.keep_post & CURL_REDIR_POST_301)) {
http_switch_to_get(data, 301);
+ switch_to_get = TRUE;
+ }
break;
case 302: /* Found */
/* (quote from RFC7231, section 6.4.3)
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))
+ && !(data->set.keep_post & CURL_REDIR_POST_302)) {
http_switch_to_get(data, 302);
+ switch_to_get = TRUE;
+ }
break;
case 303: /* See Other */
((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.keep_post & CURL_REDIR_POST_303))) {
http_switch_to_get(data, 303);
+ switch_to_get = TRUE;
+ }
break;
case 304: /* Not Modified */
/* 304 means we did a conditional request and it was "Not modified".
*/
break;
}
+
+ /* When rewind of upload data failed and we are not switching to GET,
+ * we need to fail the follow, as we cannot send the data again. */
+ if(rewind_result && !switch_to_get)
+ return rewind_result;
+
Curl_pgrsTime(data, TIMER_REDIRECT);
Curl_pgrsResetTransferSizes(data);
curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, (long)(128 * 1024));
+ curl_easy_setopt(hnd, CURLOPT_FOLLOWLOCATION, CURLFOLLOW_OBEYCODE);
curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, my_write_cb);
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, t);
if(use_earlydata)
{
#ifndef _MSC_VER
CURLM *multi_handle;
- struct CURLMsg *m;
CURLSH *share;
const char *url;
const char *method = "PUT";
do {
int still_running; /* keep number of running handles */
CURLMcode mc = curl_multi_perform(multi_handle, &still_running);
+ struct CURLMsg *m;
if(still_running) {
/* wait for activity, timeout or "nothing" */
curl_multi_remove_handle(multi_handle, e);
t = get_transfer_for_easy(e);
if(t) {
+ long res_status;
+ curl_easy_getinfo(e, CURLINFO_RESPONSE_CODE, &res_status);
t->done = 1;
- fprintf(stderr, "[t-%d] FINISHED\n", t->idx);
+ fprintf(stderr, "[t-%d] FINISHED, result=%d, response=%ld\n",
+ t->idx, m->data.result, res_status);
if(use_earlydata) {
curl_off_t sent;
curl_easy_getinfo(e, CURLINFO_EARLYDATA_SENT_T, &sent);
extra_args=['--trace-config', 'all'])
r.check_stats(count=count, http_status=413, exitcode=0)
+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
+ @pytest.mark.parametrize("httpcode", [301, 302, 307, 308])
+ def test_07_44_put_redir(self, env: Env, httpd, nghttpx, proto, httpcode):
+ if proto == 'h3' and not env.have_h3():
+ pytest.skip("h3 not supported")
+ count = 1
+ upload_size = 128*1024
+ url = f'https://localhost:{env.https_port}/curltest/put-redir-{httpcode}'
+ client = LocalClient(name='hx-upload', env=env)
+ if not client.exists():
+ pytest.skip(f'example client not built: {client.name}')
+ r = client.run(args=[
+ '-n', f'{count}', '-l', '-S', f'{upload_size}', '-V', proto, url
+ ])
+ r.check_exit_code(0)
+ results = [int(m.group(1)) for line in r.trace_lines
+ if (m := re.match(r'.* FINISHED, result=(\d+), response=(\d+)', line))]
+ httpcodes = [int(m.group(2)) for line in r.trace_lines
+ if (m := re.match(r'.* FINISHED, result=(\d+), response=(\d+)', line))]
+ if httpcode == 308:
+ assert results[0] == 65, f'{r}' # could not rewind input
+ else:
+ assert httpcodes[0] == httpcode, f'{r}'
+
# speed limited on put handler
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
def test_07_50_put_speed_limit(self, env: Env, httpd, nghttpx, proto):
' SetEnv force-response-1.0 1',
' </Location>',
' SetEnvIf Request_URI "/shutdown_unclean" ssl-unclean=1',
+ ' RewriteEngine on',
+ ' RewriteRule "^/curltest/put-redir-301$" "/curltest/put" [R=301]',
+ ' RewriteRule "^/curltest/put-redir-302$" "/curltest/put" [R=302]',
+ ' RewriteRule "^/curltest/put-redir-307$" "/curltest/put" [R=307]',
+ ' RewriteRule "^/curltest/put-redir-308$" "/curltest/put" [R=308]',
])
if self._auth_digest:
lines.extend([