/src/PROJ/curl/lib/transfer.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*************************************************************************** |
2 | | * _ _ ____ _ |
3 | | * Project ___| | | | _ \| | |
4 | | * / __| | | | |_) | | |
5 | | * | (__| |_| | _ <| |___ |
6 | | * \___|\___/|_| \_\_____| |
7 | | * |
8 | | * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. |
9 | | * |
10 | | * This software is licensed as described in the file COPYING, which |
11 | | * you should have received as part of this distribution. The terms |
12 | | * are also available at https://curl.se/docs/copyright.html. |
13 | | * |
14 | | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
15 | | * copies of the Software, and permit persons to whom the Software is |
16 | | * furnished to do so, under the terms of the COPYING file. |
17 | | * |
18 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
19 | | * KIND, either express or implied. |
20 | | * |
21 | | * SPDX-License-Identifier: curl |
22 | | * |
23 | | ***************************************************************************/ |
24 | | |
25 | | #include "curl_setup.h" |
26 | | #include "strtoofft.h" |
27 | | |
28 | | #ifdef HAVE_NETINET_IN_H |
29 | | #include <netinet/in.h> |
30 | | #endif |
31 | | #ifdef HAVE_NETDB_H |
32 | | #include <netdb.h> |
33 | | #endif |
34 | | #ifdef HAVE_ARPA_INET_H |
35 | | #include <arpa/inet.h> |
36 | | #endif |
37 | | #ifdef HAVE_NET_IF_H |
38 | | #include <net/if.h> |
39 | | #endif |
40 | | #ifdef HAVE_SYS_IOCTL_H |
41 | | #include <sys/ioctl.h> |
42 | | #endif |
43 | | #include <signal.h> |
44 | | |
45 | | #ifdef HAVE_SYS_PARAM_H |
46 | | #include <sys/param.h> |
47 | | #endif |
48 | | |
49 | | #ifdef HAVE_SYS_SELECT_H |
50 | | #include <sys/select.h> |
51 | | #elif defined(HAVE_UNISTD_H) |
52 | | #include <unistd.h> |
53 | | #endif |
54 | | |
55 | | #ifndef HAVE_SOCKET |
56 | | #error "We can't compile without socket() support!" |
57 | | #endif |
58 | | |
59 | | #include "urldata.h" |
60 | | #include <curl/curl.h> |
61 | | #include "netrc.h" |
62 | | |
63 | | #include "content_encoding.h" |
64 | | #include "hostip.h" |
65 | | #include "cfilters.h" |
66 | | #include "transfer.h" |
67 | | #include "sendf.h" |
68 | | #include "speedcheck.h" |
69 | | #include "progress.h" |
70 | | #include "http.h" |
71 | | #include "url.h" |
72 | | #include "getinfo.h" |
73 | | #include "vtls/vtls.h" |
74 | | #include "vquic/vquic.h" |
75 | | #include "select.h" |
76 | | #include "multiif.h" |
77 | | #include "connect.h" |
78 | | #include "http2.h" |
79 | | #include "mime.h" |
80 | | #include "strcase.h" |
81 | | #include "urlapi-int.h" |
82 | | #include "hsts.h" |
83 | | #include "setopt.h" |
84 | | #include "headers.h" |
85 | | |
86 | | /* The last 3 #include files should be in this order */ |
87 | | #include "curl_printf.h" |
88 | | #include "curl_memory.h" |
89 | | #include "memdebug.h" |
90 | | |
91 | | #if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ |
92 | | !defined(CURL_DISABLE_IMAP) |
93 | | /* |
94 | | * checkheaders() checks the linked list of custom headers for a |
95 | | * particular header (prefix). Provide the prefix without colon! |
96 | | * |
97 | | * Returns a pointer to the first matching header or NULL if none matched. |
98 | | */ |
99 | | char *Curl_checkheaders(const struct Curl_easy *data, |
100 | | const char *thisheader, |
101 | | const size_t thislen) |
102 | 0 | { |
103 | 0 | struct curl_slist *head; |
104 | 0 | DEBUGASSERT(thislen); |
105 | 0 | DEBUGASSERT(thisheader[thislen-1] != ':'); |
106 | |
|
107 | 0 | for(head = data->set.headers; head; head = head->next) { |
108 | 0 | if(strncasecompare(head->data, thisheader, thislen) && |
109 | 0 | Curl_headersep(head->data[thislen]) ) |
110 | 0 | return head->data; |
111 | 0 | } |
112 | | |
113 | 0 | return NULL; |
114 | 0 | } |
115 | | #endif |
116 | | |
117 | | CURLcode Curl_get_upload_buffer(struct Curl_easy *data) |
118 | 0 | { |
119 | 0 | if(!data->state.ulbuf) { |
120 | 0 | data->state.ulbuf = malloc(data->set.upload_buffer_size); |
121 | 0 | if(!data->state.ulbuf) |
122 | 0 | return CURLE_OUT_OF_MEMORY; |
123 | 0 | } |
124 | 0 | return CURLE_OK; |
125 | 0 | } |
126 | | |
127 | | #ifndef CURL_DISABLE_HTTP |
128 | | /* |
129 | | * This function will be called to loop through the trailers buffer |
130 | | * until no more data is available for sending. |
131 | | */ |
132 | | static size_t trailers_read(char *buffer, size_t size, size_t nitems, |
133 | | void *raw) |
134 | 0 | { |
135 | 0 | struct Curl_easy *data = (struct Curl_easy *)raw; |
136 | 0 | struct dynbuf *trailers_buf = &data->state.trailers_buf; |
137 | 0 | size_t bytes_left = Curl_dyn_len(trailers_buf) - |
138 | 0 | data->state.trailers_bytes_sent; |
139 | 0 | size_t to_copy = (size*nitems < bytes_left) ? size*nitems : bytes_left; |
140 | 0 | if(to_copy) { |
141 | 0 | memcpy(buffer, |
142 | 0 | Curl_dyn_ptr(trailers_buf) + data->state.trailers_bytes_sent, |
143 | 0 | to_copy); |
144 | 0 | data->state.trailers_bytes_sent += to_copy; |
145 | 0 | } |
146 | 0 | return to_copy; |
147 | 0 | } |
148 | | |
149 | | static size_t trailers_left(void *raw) |
150 | 0 | { |
151 | 0 | struct Curl_easy *data = (struct Curl_easy *)raw; |
152 | 0 | struct dynbuf *trailers_buf = &data->state.trailers_buf; |
153 | 0 | return Curl_dyn_len(trailers_buf) - data->state.trailers_bytes_sent; |
154 | 0 | } |
155 | | #endif |
156 | | |
157 | | /* |
158 | | * This function will call the read callback to fill our buffer with data |
159 | | * to upload. |
160 | | */ |
161 | | CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes, |
162 | | size_t *nreadp) |
163 | 0 | { |
164 | 0 | size_t buffersize = bytes; |
165 | 0 | size_t nread; |
166 | 0 | curl_read_callback readfunc = NULL; |
167 | 0 | void *extra_data = NULL; |
168 | 0 | int eof_index = 0; |
169 | |
|
170 | 0 | #ifndef CURL_DISABLE_HTTP |
171 | 0 | if(data->state.trailers_state == TRAILERS_INITIALIZED) { |
172 | 0 | struct curl_slist *trailers = NULL; |
173 | 0 | CURLcode result; |
174 | 0 | int trailers_ret_code; |
175 | | |
176 | | /* at this point we already verified that the callback exists |
177 | | so we compile and store the trailers buffer, then proceed */ |
178 | 0 | infof(data, |
179 | 0 | "Moving trailers state machine from initialized to sending."); |
180 | 0 | data->state.trailers_state = TRAILERS_SENDING; |
181 | 0 | Curl_dyn_init(&data->state.trailers_buf, DYN_TRAILERS); |
182 | |
|
183 | 0 | data->state.trailers_bytes_sent = 0; |
184 | 0 | Curl_set_in_callback(data, true); |
185 | 0 | trailers_ret_code = data->set.trailer_callback(&trailers, |
186 | 0 | data->set.trailer_data); |
187 | 0 | Curl_set_in_callback(data, false); |
188 | 0 | if(trailers_ret_code == CURL_TRAILERFUNC_OK) { |
189 | 0 | result = Curl_http_compile_trailers(trailers, &data->state.trailers_buf, |
190 | 0 | data); |
191 | 0 | } |
192 | 0 | else { |
193 | 0 | failf(data, "operation aborted by trailing headers callback"); |
194 | 0 | *nreadp = 0; |
195 | 0 | result = CURLE_ABORTED_BY_CALLBACK; |
196 | 0 | } |
197 | 0 | if(result) { |
198 | 0 | Curl_dyn_free(&data->state.trailers_buf); |
199 | 0 | curl_slist_free_all(trailers); |
200 | 0 | return result; |
201 | 0 | } |
202 | 0 | infof(data, "Successfully compiled trailers."); |
203 | 0 | curl_slist_free_all(trailers); |
204 | 0 | } |
205 | 0 | #endif |
206 | | |
207 | 0 | #ifndef CURL_DISABLE_HTTP |
208 | | /* if we are transmitting trailing data, we don't need to write |
209 | | a chunk size so we skip this */ |
210 | 0 | if(data->req.upload_chunky && |
211 | 0 | data->state.trailers_state == TRAILERS_NONE) { |
212 | | /* if chunked Transfer-Encoding */ |
213 | 0 | buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */ |
214 | 0 | data->req.upload_fromhere += (8 + 2); /* 32bit hex + CRLF */ |
215 | 0 | } |
216 | |
|
217 | 0 | if(data->state.trailers_state == TRAILERS_SENDING) { |
218 | | /* if we're here then that means that we already sent the last empty chunk |
219 | | but we didn't send a final CR LF, so we sent 0 CR LF. We then start |
220 | | pulling trailing data until we have no more at which point we |
221 | | simply return to the previous point in the state machine as if |
222 | | nothing happened. |
223 | | */ |
224 | 0 | readfunc = trailers_read; |
225 | 0 | extra_data = (void *)data; |
226 | 0 | eof_index = 1; |
227 | 0 | } |
228 | 0 | else |
229 | 0 | #endif |
230 | 0 | { |
231 | 0 | readfunc = data->state.fread_func; |
232 | 0 | extra_data = data->state.in; |
233 | 0 | } |
234 | |
|
235 | 0 | if(!data->req.fread_eof[eof_index]) { |
236 | 0 | Curl_set_in_callback(data, true); |
237 | 0 | nread = readfunc(data->req.upload_fromhere, 1, buffersize, extra_data); |
238 | 0 | Curl_set_in_callback(data, false); |
239 | | /* make sure the callback is not called again after EOF */ |
240 | 0 | data->req.fread_eof[eof_index] = !nread; |
241 | 0 | } |
242 | 0 | else |
243 | 0 | nread = 0; |
244 | |
|
245 | 0 | if(nread == CURL_READFUNC_ABORT) { |
246 | 0 | failf(data, "operation aborted by callback"); |
247 | 0 | *nreadp = 0; |
248 | 0 | return CURLE_ABORTED_BY_CALLBACK; |
249 | 0 | } |
250 | 0 | if(nread == CURL_READFUNC_PAUSE) { |
251 | 0 | struct SingleRequest *k = &data->req; |
252 | |
|
253 | 0 | if(data->conn->handler->flags & PROTOPT_NONETWORK) { |
254 | | /* protocols that work without network cannot be paused. This is |
255 | | actually only FILE:// just now, and it can't pause since the transfer |
256 | | isn't done using the "normal" procedure. */ |
257 | 0 | failf(data, "Read callback asked for PAUSE when not supported"); |
258 | 0 | return CURLE_READ_ERROR; |
259 | 0 | } |
260 | | |
261 | | /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */ |
262 | 0 | k->keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */ |
263 | 0 | if(data->req.upload_chunky) { |
264 | | /* Back out the preallocation done above */ |
265 | 0 | data->req.upload_fromhere -= (8 + 2); |
266 | 0 | } |
267 | 0 | *nreadp = 0; |
268 | |
|
269 | 0 | return CURLE_OK; /* nothing was read */ |
270 | 0 | } |
271 | 0 | else if(nread > buffersize) { |
272 | | /* the read function returned a too large value */ |
273 | 0 | *nreadp = 0; |
274 | 0 | failf(data, "read function returned funny value"); |
275 | 0 | return CURLE_READ_ERROR; |
276 | 0 | } |
277 | | |
278 | 0 | #ifndef CURL_DISABLE_HTTP |
279 | 0 | if(!data->req.forbidchunk && data->req.upload_chunky) { |
280 | | /* if chunked Transfer-Encoding |
281 | | * build chunk: |
282 | | * |
283 | | * <HEX SIZE> CRLF |
284 | | * <DATA> CRLF |
285 | | */ |
286 | | /* On non-ASCII platforms the <DATA> may or may not be |
287 | | translated based on state.prefer_ascii while the protocol |
288 | | portion must always be translated to the network encoding. |
289 | | To further complicate matters, line end conversion might be |
290 | | done later on, so we need to prevent CRLFs from becoming |
291 | | CRCRLFs if that's the case. To do this we use bare LFs |
292 | | here, knowing they'll become CRLFs later on. |
293 | | */ |
294 | |
|
295 | 0 | bool added_crlf = FALSE; |
296 | 0 | int hexlen = 0; |
297 | 0 | const char *endofline_native; |
298 | 0 | const char *endofline_network; |
299 | |
|
300 | 0 | if( |
301 | 0 | #ifdef CURL_DO_LINEEND_CONV |
302 | 0 | (data->state.prefer_ascii) || |
303 | 0 | #endif |
304 | 0 | (data->set.crlf)) { |
305 | | /* \n will become \r\n later on */ |
306 | 0 | endofline_native = "\n"; |
307 | 0 | endofline_network = "\x0a"; |
308 | 0 | } |
309 | 0 | else { |
310 | 0 | endofline_native = "\r\n"; |
311 | 0 | endofline_network = "\x0d\x0a"; |
312 | 0 | } |
313 | | |
314 | | /* if we're not handling trailing data, proceed as usual */ |
315 | 0 | if(data->state.trailers_state != TRAILERS_SENDING) { |
316 | 0 | char hexbuffer[11] = ""; |
317 | 0 | hexlen = msnprintf(hexbuffer, sizeof(hexbuffer), |
318 | 0 | "%zx%s", nread, endofline_native); |
319 | | |
320 | | /* move buffer pointer */ |
321 | 0 | data->req.upload_fromhere -= hexlen; |
322 | 0 | nread += hexlen; |
323 | | |
324 | | /* copy the prefix to the buffer, leaving out the NUL */ |
325 | 0 | memcpy(data->req.upload_fromhere, hexbuffer, hexlen); |
326 | | |
327 | | /* always append ASCII CRLF to the data unless |
328 | | we have a valid trailer callback */ |
329 | 0 | if((nread-hexlen) == 0 && |
330 | 0 | data->set.trailer_callback != NULL && |
331 | 0 | data->state.trailers_state == TRAILERS_NONE) { |
332 | 0 | data->state.trailers_state = TRAILERS_INITIALIZED; |
333 | 0 | } |
334 | 0 | else { |
335 | 0 | memcpy(data->req.upload_fromhere + nread, |
336 | 0 | endofline_network, |
337 | 0 | strlen(endofline_network)); |
338 | 0 | added_crlf = TRUE; |
339 | 0 | } |
340 | 0 | } |
341 | |
|
342 | 0 | if(data->state.trailers_state == TRAILERS_SENDING && |
343 | 0 | !trailers_left(data)) { |
344 | 0 | Curl_dyn_free(&data->state.trailers_buf); |
345 | 0 | data->state.trailers_state = TRAILERS_DONE; |
346 | 0 | data->set.trailer_data = NULL; |
347 | 0 | data->set.trailer_callback = NULL; |
348 | | /* mark the transfer as done */ |
349 | 0 | data->req.upload_done = TRUE; |
350 | 0 | infof(data, "Signaling end of chunked upload after trailers."); |
351 | 0 | } |
352 | 0 | else |
353 | 0 | if((nread - hexlen) == 0 && |
354 | 0 | data->state.trailers_state != TRAILERS_INITIALIZED) { |
355 | | /* mark this as done once this chunk is transferred */ |
356 | 0 | data->req.upload_done = TRUE; |
357 | 0 | infof(data, |
358 | 0 | "Signaling end of chunked upload via terminating chunk."); |
359 | 0 | } |
360 | |
|
361 | 0 | if(added_crlf) |
362 | 0 | nread += strlen(endofline_network); /* for the added end of line */ |
363 | 0 | } |
364 | 0 | #endif |
365 | |
|
366 | 0 | *nreadp = nread; |
367 | |
|
368 | 0 | return CURLE_OK; |
369 | 0 | } |
370 | | |
371 | | static int data_pending(struct Curl_easy *data) |
372 | 0 | { |
373 | 0 | struct connectdata *conn = data->conn; |
374 | |
|
375 | 0 | if(conn->handler->protocol&PROTO_FAMILY_FTP) |
376 | 0 | return Curl_conn_data_pending(data, SECONDARYSOCKET); |
377 | | |
378 | | /* in the case of libssh2, we can never be really sure that we have emptied |
379 | | its internal buffers so we MUST always try until we get EAGAIN back */ |
380 | 0 | return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) || |
381 | 0 | Curl_conn_data_pending(data, FIRSTSOCKET); |
382 | 0 | } |
383 | | |
384 | | /* |
385 | | * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the |
386 | | * remote document with the time provided by CURLOPT_TIMEVAL |
387 | | */ |
388 | | bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) |
389 | 0 | { |
390 | 0 | if((timeofdoc == 0) || (data->set.timevalue == 0)) |
391 | 0 | return TRUE; |
392 | | |
393 | 0 | switch(data->set.timecondition) { |
394 | 0 | case CURL_TIMECOND_IFMODSINCE: |
395 | 0 | default: |
396 | 0 | if(timeofdoc <= data->set.timevalue) { |
397 | 0 | infof(data, |
398 | 0 | "The requested document is not new enough"); |
399 | 0 | data->info.timecond = TRUE; |
400 | 0 | return FALSE; |
401 | 0 | } |
402 | 0 | break; |
403 | 0 | case CURL_TIMECOND_IFUNMODSINCE: |
404 | 0 | if(timeofdoc >= data->set.timevalue) { |
405 | 0 | infof(data, |
406 | 0 | "The requested document is not old enough"); |
407 | 0 | data->info.timecond = TRUE; |
408 | 0 | return FALSE; |
409 | 0 | } |
410 | 0 | break; |
411 | 0 | } |
412 | | |
413 | 0 | return TRUE; |
414 | 0 | } |
415 | | |
416 | | /** |
417 | | * Receive raw response data for the transfer. |
418 | | * @param data the transfer |
419 | | * @param buf buffer to keep response data received |
420 | | * @param blen length of `buf` |
421 | | * @param eos_reliable if EOS detection in underlying connection is reliable |
422 | | * @param err error code in case of -1 return |
423 | | * @return number of bytes read or -1 for error |
424 | | */ |
425 | | static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data, |
426 | | char *buf, size_t blen, |
427 | | bool eos_reliable, |
428 | | CURLcode *err) |
429 | 0 | { |
430 | 0 | ssize_t nread; |
431 | |
|
432 | 0 | DEBUGASSERT(blen > 0); |
433 | | /* If we are reading BODY data and the connection does NOT handle EOF |
434 | | * and we know the size of the BODY data, limit the read amount */ |
435 | 0 | if(!eos_reliable && !data->req.header && data->req.size != -1) { |
436 | 0 | curl_off_t totalleft = data->req.size - data->req.bytecount; |
437 | 0 | if(totalleft <= 0) |
438 | 0 | blen = 0; |
439 | 0 | else if(totalleft < (curl_off_t)blen) |
440 | 0 | blen = (size_t)totalleft; |
441 | 0 | } |
442 | |
|
443 | 0 | if(!blen) { |
444 | | /* want nothing - continue as if read nothing. */ |
445 | 0 | DEBUGF(infof(data, "readwrite_data: we're done")); |
446 | 0 | *err = CURLE_OK; |
447 | 0 | return 0; |
448 | 0 | } |
449 | | |
450 | 0 | *err = Curl_read(data, data->conn->sockfd, buf, blen, &nread); |
451 | 0 | if(*err) |
452 | 0 | return -1; |
453 | 0 | DEBUGASSERT(nread >= 0); |
454 | 0 | *err = CURLE_OK; |
455 | 0 | return nread; |
456 | 0 | } |
457 | | |
458 | | /* |
459 | | * Go ahead and do a read if we have a readable socket or if |
460 | | * the stream was rewound (in which case we have data in a |
461 | | * buffer) |
462 | | */ |
463 | | static CURLcode readwrite_data(struct Curl_easy *data, |
464 | | struct SingleRequest *k, |
465 | | int *didwhat, bool *done) |
466 | 0 | { |
467 | 0 | struct connectdata *conn = data->conn; |
468 | 0 | CURLcode result = CURLE_OK; |
469 | 0 | char *buf, *xfer_buf; |
470 | 0 | size_t blen, xfer_blen; |
471 | 0 | int maxloops = 10; |
472 | 0 | curl_off_t total_received = 0; |
473 | 0 | bool is_multiplex = FALSE; |
474 | |
|
475 | 0 | *done = FALSE; |
476 | |
|
477 | 0 | result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen); |
478 | 0 | if(result) |
479 | 0 | goto out; |
480 | | |
481 | | /* This is where we loop until we have read everything there is to |
482 | | read or we get a CURLE_AGAIN */ |
483 | 0 | do { |
484 | 0 | bool is_eos = FALSE; |
485 | 0 | size_t bytestoread; |
486 | 0 | ssize_t nread; |
487 | |
|
488 | 0 | if(!is_multiplex) { |
489 | | /* Multiplexed connection have inherent handling of EOF and we do not |
490 | | * have to carefully restrict the amount we try to read. |
491 | | * Multiplexed changes only in one direction. */ |
492 | 0 | is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET); |
493 | 0 | } |
494 | |
|
495 | 0 | buf = xfer_buf; |
496 | 0 | bytestoread = xfer_blen; |
497 | | |
498 | | /* Observe any imposed speed limit */ |
499 | 0 | if(bytestoread && data->set.max_recv_speed) { |
500 | 0 | curl_off_t net_limit = data->set.max_recv_speed - total_received; |
501 | 0 | if(net_limit <= 0) |
502 | 0 | break; |
503 | 0 | if((size_t)net_limit < bytestoread) |
504 | 0 | bytestoread = (size_t)net_limit; |
505 | 0 | } |
506 | | |
507 | 0 | nread = Curl_xfer_recv_resp(data, buf, bytestoread, |
508 | 0 | is_multiplex, &result); |
509 | 0 | if(nread < 0) { |
510 | 0 | if(CURLE_AGAIN == result) { |
511 | 0 | result = CURLE_OK; |
512 | 0 | break; /* get out of loop */ |
513 | 0 | } |
514 | 0 | goto out; /* real error */ |
515 | 0 | } |
516 | | |
517 | | /* We only get a 0-length read on EndOfStream */ |
518 | 0 | blen = (size_t)nread; |
519 | 0 | is_eos = (blen == 0); |
520 | 0 | *didwhat |= KEEP_RECV; |
521 | |
|
522 | 0 | if(!blen) { |
523 | | /* if we receive 0 or less here, either the data transfer is done or the |
524 | | server closed the connection and we bail out from this! */ |
525 | 0 | if(is_multiplex) |
526 | 0 | DEBUGF(infof(data, "nread == 0, stream closed, bailing")); |
527 | 0 | else |
528 | 0 | DEBUGF(infof(data, "nread <= 0, server closed connection, bailing")); |
529 | 0 | if(k->eos_written) { /* already did write this to client, leave */ |
530 | 0 | k->keepon = 0; /* stop sending as well */ |
531 | 0 | break; |
532 | 0 | } |
533 | 0 | } |
534 | 0 | total_received += blen; |
535 | |
|
536 | 0 | result = Curl_xfer_write_resp(data, buf, blen, is_eos, done); |
537 | 0 | if(result || *done) |
538 | 0 | goto out; |
539 | | |
540 | | /* if we are done, we stop receiving. On multiplexed connections, |
541 | | * we should read the EOS. Which may arrive as meta data after |
542 | | * the bytes. Not taking it in might lead to RST of streams. */ |
543 | 0 | if((!is_multiplex && data->req.download_done) || is_eos) { |
544 | 0 | data->req.keepon &= ~KEEP_RECV; |
545 | 0 | } |
546 | | /* if we are PAUSEd or stopped receiving, leave the loop */ |
547 | 0 | if((k->keepon & KEEP_RECV_PAUSE) || !(k->keepon & KEEP_RECV)) |
548 | 0 | break; |
549 | |
|
550 | 0 | } while(maxloops-- && data_pending(data)); |
551 | | |
552 | 0 | if(maxloops <= 0) { |
553 | | /* did not read until EAGAIN, mark read-again-please */ |
554 | 0 | data->state.select_bits = CURL_CSELECT_IN; |
555 | 0 | if((k->keepon & KEEP_SENDBITS) == KEEP_SEND) |
556 | 0 | data->state.select_bits |= CURL_CSELECT_OUT; |
557 | 0 | } |
558 | |
|
559 | 0 | if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && |
560 | 0 | (conn->bits.close || is_multiplex)) { |
561 | | /* When we've read the entire thing and the close bit is set, the server |
562 | | may now close the connection. If there's now any kind of sending going |
563 | | on from our side, we need to stop that immediately. */ |
564 | 0 | infof(data, "we are done reading and this is set to close, stop send"); |
565 | 0 | k->keepon &= ~KEEP_SEND; /* no writing anymore either */ |
566 | 0 | k->keepon &= ~KEEP_SEND_PAUSE; /* no pausing anymore either */ |
567 | 0 | } |
568 | |
|
569 | 0 | out: |
570 | 0 | Curl_multi_xfer_buf_release(data, xfer_buf); |
571 | 0 | if(result) |
572 | 0 | DEBUGF(infof(data, "readwrite_data() -> %d", result)); |
573 | 0 | return result; |
574 | 0 | } |
575 | | |
576 | | CURLcode Curl_done_sending(struct Curl_easy *data, |
577 | | struct SingleRequest *k) |
578 | 0 | { |
579 | 0 | k->keepon &= ~KEEP_SEND; /* we're done writing */ |
580 | | |
581 | | /* These functions should be moved into the handler struct! */ |
582 | 0 | Curl_conn_ev_data_done_send(data); |
583 | |
|
584 | 0 | return CURLE_OK; |
585 | 0 | } |
586 | | |
587 | | #if defined(_WIN32) && defined(USE_WINSOCK) |
588 | | #ifndef SIO_IDEAL_SEND_BACKLOG_QUERY |
589 | | #define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B |
590 | | #endif |
591 | | |
592 | | static void win_update_buffer_size(curl_socket_t sockfd) |
593 | | { |
594 | | int result; |
595 | | ULONG ideal; |
596 | | DWORD ideallen; |
597 | | result = WSAIoctl(sockfd, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0, |
598 | | &ideal, sizeof(ideal), &ideallen, 0, 0); |
599 | | if(result == 0) { |
600 | | setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, |
601 | | (const char *)&ideal, sizeof(ideal)); |
602 | | } |
603 | | } |
604 | | #else |
605 | | #define win_update_buffer_size(x) |
606 | | #endif |
607 | | |
608 | | #define curl_upload_refill_watermark(data) \ |
609 | 0 | ((ssize_t)((data)->set.upload_buffer_size >> 5)) |
610 | | |
611 | | /* |
612 | | * Send data to upload to the server, when the socket is writable. |
613 | | */ |
614 | | static CURLcode readwrite_upload(struct Curl_easy *data, |
615 | | struct connectdata *conn, |
616 | | int *didwhat) |
617 | 0 | { |
618 | 0 | ssize_t i, si; |
619 | 0 | ssize_t bytes_written; |
620 | 0 | CURLcode result; |
621 | 0 | ssize_t nread; /* number of bytes read */ |
622 | 0 | bool sending_http_headers = FALSE; |
623 | 0 | struct SingleRequest *k = &data->req; |
624 | |
|
625 | 0 | *didwhat |= KEEP_SEND; |
626 | |
|
627 | 0 | do { |
628 | 0 | curl_off_t nbody; |
629 | 0 | ssize_t offset = 0; |
630 | |
|
631 | 0 | if(0 != k->upload_present && |
632 | 0 | k->upload_present < curl_upload_refill_watermark(data) && |
633 | 0 | !k->upload_chunky &&/*(variable sized chunked header; append not safe)*/ |
634 | 0 | !k->upload_done && /*!(k->upload_done once k->upload_present sent)*/ |
635 | 0 | !(k->writebytecount + k->upload_present - k->pendingheader == |
636 | 0 | data->state.infilesize)) { |
637 | 0 | offset = k->upload_present; |
638 | 0 | } |
639 | | |
640 | | /* only read more data if there's no upload data already |
641 | | present in the upload buffer, or if appending to upload buffer */ |
642 | 0 | if(0 == k->upload_present || offset) { |
643 | 0 | result = Curl_get_upload_buffer(data); |
644 | 0 | if(result) |
645 | 0 | return result; |
646 | 0 | if(offset && k->upload_fromhere != data->state.ulbuf) |
647 | 0 | memmove(data->state.ulbuf, k->upload_fromhere, offset); |
648 | | /* init the "upload from here" pointer */ |
649 | 0 | k->upload_fromhere = data->state.ulbuf; |
650 | |
|
651 | 0 | if(!k->upload_done) { |
652 | | /* HTTP pollution, this should be written nicer to become more |
653 | | protocol agnostic. */ |
654 | 0 | size_t fillcount; |
655 | 0 | struct HTTP *http = k->p.http; |
656 | |
|
657 | 0 | if((k->exp100 == EXP100_SENDING_REQUEST) && |
658 | 0 | (http->sending == HTTPSEND_BODY)) { |
659 | | /* If this call is to send body data, we must take some action: |
660 | | We have sent off the full HTTP 1.1 request, and we shall now |
661 | | go into the Expect: 100 state and await such a header */ |
662 | 0 | k->exp100 = EXP100_AWAITING_CONTINUE; /* wait for the header */ |
663 | 0 | k->keepon &= ~KEEP_SEND; /* disable writing */ |
664 | 0 | k->start100 = Curl_now(); /* timeout count starts now */ |
665 | 0 | *didwhat &= ~KEEP_SEND; /* we didn't write anything actually */ |
666 | | /* set a timeout for the multi interface */ |
667 | 0 | Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT); |
668 | 0 | break; |
669 | 0 | } |
670 | | |
671 | 0 | if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) { |
672 | 0 | if(http->sending == HTTPSEND_REQUEST) |
673 | | /* We're sending the HTTP request headers, not the data. |
674 | | Remember that so we don't change the line endings. */ |
675 | 0 | sending_http_headers = TRUE; |
676 | 0 | else |
677 | 0 | sending_http_headers = FALSE; |
678 | 0 | } |
679 | |
|
680 | 0 | k->upload_fromhere += offset; |
681 | 0 | result = Curl_fillreadbuffer(data, data->set.upload_buffer_size-offset, |
682 | 0 | &fillcount); |
683 | 0 | k->upload_fromhere -= offset; |
684 | 0 | if(result) |
685 | 0 | return result; |
686 | | |
687 | 0 | nread = offset + fillcount; |
688 | 0 | } |
689 | 0 | else |
690 | 0 | nread = 0; /* we're done uploading/reading */ |
691 | | |
692 | 0 | if(!nread && (k->keepon & KEEP_SEND_PAUSE)) { |
693 | | /* this is a paused transfer */ |
694 | 0 | break; |
695 | 0 | } |
696 | 0 | if(nread <= 0) { |
697 | 0 | result = Curl_done_sending(data, k); |
698 | 0 | if(result) |
699 | 0 | return result; |
700 | 0 | break; |
701 | 0 | } |
702 | | |
703 | | /* store number of bytes available for upload */ |
704 | 0 | k->upload_present = nread; |
705 | | |
706 | | /* convert LF to CRLF if so asked */ |
707 | 0 | if((!sending_http_headers) && ( |
708 | 0 | #ifdef CURL_DO_LINEEND_CONV |
709 | | /* always convert if we're FTPing in ASCII mode */ |
710 | 0 | (data->state.prefer_ascii) || |
711 | 0 | #endif |
712 | 0 | (data->set.crlf))) { |
713 | | /* Do we need to allocate a scratch buffer? */ |
714 | 0 | if(!data->state.scratch) { |
715 | 0 | data->state.scratch = malloc(2 * data->set.upload_buffer_size); |
716 | 0 | if(!data->state.scratch) { |
717 | 0 | failf(data, "Failed to alloc scratch buffer"); |
718 | |
|
719 | 0 | return CURLE_OUT_OF_MEMORY; |
720 | 0 | } |
721 | 0 | } |
722 | | |
723 | | /* |
724 | | * ASCII/EBCDIC Note: This is presumably a text (not binary) |
725 | | * transfer so the data should already be in ASCII. |
726 | | * That means the hex values for ASCII CR (0x0d) & LF (0x0a) |
727 | | * must be used instead of the escape sequences \r & \n. |
728 | | */ |
729 | 0 | if(offset) |
730 | 0 | memcpy(data->state.scratch, k->upload_fromhere, offset); |
731 | 0 | for(i = offset, si = offset; i < nread; i++, si++) { |
732 | 0 | if(k->upload_fromhere[i] == 0x0a) { |
733 | 0 | data->state.scratch[si++] = 0x0d; |
734 | 0 | data->state.scratch[si] = 0x0a; |
735 | 0 | if(!data->set.crlf) { |
736 | | /* we're here only because FTP is in ASCII mode... |
737 | | bump infilesize for the LF we just added */ |
738 | 0 | if(data->state.infilesize != -1) |
739 | 0 | data->state.infilesize++; |
740 | 0 | } |
741 | 0 | } |
742 | 0 | else |
743 | 0 | data->state.scratch[si] = k->upload_fromhere[i]; |
744 | 0 | } |
745 | |
|
746 | 0 | if(si != nread) { |
747 | | /* only perform the special operation if we really did replace |
748 | | anything */ |
749 | 0 | nread = si; |
750 | | |
751 | | /* upload from the new (replaced) buffer instead */ |
752 | 0 | k->upload_fromhere = data->state.scratch; |
753 | | |
754 | | /* set the new amount too */ |
755 | 0 | k->upload_present = nread; |
756 | 0 | } |
757 | 0 | } |
758 | | |
759 | 0 | #ifndef CURL_DISABLE_SMTP |
760 | 0 | if(conn->handler->protocol & PROTO_FAMILY_SMTP) { |
761 | 0 | result = Curl_smtp_escape_eob(data, nread, offset); |
762 | 0 | if(result) |
763 | 0 | return result; |
764 | 0 | } |
765 | 0 | #endif /* CURL_DISABLE_SMTP */ |
766 | 0 | } /* if 0 == k->upload_present or appended to upload buffer */ |
767 | 0 | else { |
768 | | /* We have a partial buffer left from a previous "round". Use |
769 | | that instead of reading more data */ |
770 | 0 | } |
771 | | |
772 | | /* write to socket (send away data) */ |
773 | 0 | result = Curl_write(data, |
774 | 0 | conn->writesockfd, /* socket to send to */ |
775 | 0 | k->upload_fromhere, /* buffer pointer */ |
776 | 0 | k->upload_present, /* buffer size */ |
777 | 0 | &bytes_written); /* actually sent */ |
778 | 0 | if(result) |
779 | 0 | return result; |
780 | | |
781 | | #if defined(_WIN32) && defined(USE_WINSOCK) |
782 | | { |
783 | | struct curltime n = Curl_now(); |
784 | | if(Curl_timediff(n, conn->last_sndbuf_update) > 1000) { |
785 | | win_update_buffer_size(conn->writesockfd); |
786 | | conn->last_sndbuf_update = n; |
787 | | } |
788 | | } |
789 | | #endif |
790 | | |
791 | 0 | if(k->pendingheader) { |
792 | | /* parts of what was sent was header */ |
793 | 0 | curl_off_t n = CURLMIN(k->pendingheader, bytes_written); |
794 | | /* show the data before we change the pointer upload_fromhere */ |
795 | 0 | Curl_debug(data, CURLINFO_HEADER_OUT, k->upload_fromhere, (size_t)n); |
796 | 0 | k->pendingheader -= n; |
797 | 0 | nbody = bytes_written - n; /* size of the written body part */ |
798 | 0 | } |
799 | 0 | else |
800 | 0 | nbody = bytes_written; |
801 | |
|
802 | 0 | if(nbody) { |
803 | | /* show the data before we change the pointer upload_fromhere */ |
804 | 0 | Curl_debug(data, CURLINFO_DATA_OUT, |
805 | 0 | &k->upload_fromhere[bytes_written - nbody], |
806 | 0 | (size_t)nbody); |
807 | |
|
808 | 0 | k->writebytecount += nbody; |
809 | 0 | Curl_pgrsSetUploadCounter(data, k->writebytecount); |
810 | 0 | } |
811 | |
|
812 | 0 | if((!k->upload_chunky || k->forbidchunk) && |
813 | 0 | (k->writebytecount == data->state.infilesize)) { |
814 | | /* we have sent all data we were supposed to */ |
815 | 0 | k->upload_done = TRUE; |
816 | 0 | infof(data, "We are completely uploaded and fine"); |
817 | 0 | } |
818 | |
|
819 | 0 | if(k->upload_present != bytes_written) { |
820 | | /* we only wrote a part of the buffer (if anything), deal with it! */ |
821 | | |
822 | | /* store the amount of bytes left in the buffer to write */ |
823 | 0 | k->upload_present -= bytes_written; |
824 | | |
825 | | /* advance the pointer where to find the buffer when the next send |
826 | | is to happen */ |
827 | 0 | k->upload_fromhere += bytes_written; |
828 | 0 | } |
829 | 0 | else { |
830 | | /* we've uploaded that buffer now */ |
831 | 0 | result = Curl_get_upload_buffer(data); |
832 | 0 | if(result) |
833 | 0 | return result; |
834 | 0 | k->upload_fromhere = data->state.ulbuf; |
835 | 0 | k->upload_present = 0; /* no more bytes left */ |
836 | |
|
837 | 0 | if(k->upload_done) { |
838 | 0 | result = Curl_done_sending(data, k); |
839 | 0 | if(result) |
840 | 0 | return result; |
841 | 0 | } |
842 | 0 | } |
843 | | |
844 | |
|
845 | 0 | } while(0); /* just to break out from! */ |
846 | | |
847 | 0 | return CURLE_OK; |
848 | 0 | } |
849 | | |
850 | | static int select_bits_paused(struct Curl_easy *data, int select_bits) |
851 | 0 | { |
852 | | /* See issue #11982: we really need to be careful not to progress |
853 | | * a transfer direction when that direction is paused. Not all parts |
854 | | * of our state machine are handling PAUSED transfers correctly. So, we |
855 | | * do not want to go there. |
856 | | * NOTE: we are only interested in PAUSE, not HOLD. */ |
857 | | |
858 | | /* if there is data in a direction not paused, return false */ |
859 | 0 | if(((select_bits & CURL_CSELECT_IN) && |
860 | 0 | !(data->req.keepon & KEEP_RECV_PAUSE)) || |
861 | 0 | ((select_bits & CURL_CSELECT_OUT) && |
862 | 0 | !(data->req.keepon & KEEP_SEND_PAUSE))) |
863 | 0 | return FALSE; |
864 | | |
865 | 0 | return (data->req.keepon & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)); |
866 | 0 | } |
867 | | |
868 | | /* |
869 | | * Curl_readwrite() is the low-level function to be called when data is to |
870 | | * be read and written to/from the connection. |
871 | | */ |
872 | | CURLcode Curl_readwrite(struct Curl_easy *data, |
873 | | bool *done) |
874 | 0 | { |
875 | 0 | struct connectdata *conn = data->conn; |
876 | 0 | struct SingleRequest *k = &data->req; |
877 | 0 | CURLcode result; |
878 | 0 | struct curltime now; |
879 | 0 | int didwhat = 0; |
880 | 0 | int select_bits; |
881 | |
|
882 | 0 | if(data->state.select_bits) { |
883 | 0 | if(select_bits_paused(data, data->state.select_bits)) { |
884 | | /* leave the bits unchanged, so they'll tell us what to do when |
885 | | * this transfer gets unpaused. */ |
886 | 0 | DEBUGF(infof(data, "readwrite, select_bits, early return on PAUSED")); |
887 | 0 | result = CURLE_OK; |
888 | 0 | goto out; |
889 | 0 | } |
890 | 0 | select_bits = data->state.select_bits; |
891 | 0 | data->state.select_bits = 0; |
892 | 0 | } |
893 | 0 | else { |
894 | 0 | curl_socket_t fd_read; |
895 | 0 | curl_socket_t fd_write; |
896 | | /* only use the proper socket if the *_HOLD bit is not set simultaneously |
897 | | as then we are in rate limiting state in that transfer direction */ |
898 | 0 | if((k->keepon & KEEP_RECVBITS) == KEEP_RECV) |
899 | 0 | fd_read = conn->sockfd; |
900 | 0 | else |
901 | 0 | fd_read = CURL_SOCKET_BAD; |
902 | |
|
903 | 0 | if((k->keepon & KEEP_SENDBITS) == KEEP_SEND) |
904 | 0 | fd_write = conn->writesockfd; |
905 | 0 | else |
906 | 0 | fd_write = CURL_SOCKET_BAD; |
907 | |
|
908 | 0 | select_bits = Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, 0); |
909 | 0 | } |
910 | | |
911 | 0 | if(select_bits == CURL_CSELECT_ERR) { |
912 | 0 | failf(data, "select/poll returned error"); |
913 | 0 | result = CURLE_SEND_ERROR; |
914 | 0 | goto out; |
915 | 0 | } |
916 | | |
917 | | #ifdef USE_HYPER |
918 | | if(conn->datastream) { |
919 | | result = conn->datastream(data, conn, &didwhat, done, select_bits); |
920 | | if(result || *done) |
921 | | goto out; |
922 | | } |
923 | | else { |
924 | | #endif |
925 | | /* We go ahead and do a read if we have a readable socket or if |
926 | | the stream was rewound (in which case we have data in a |
927 | | buffer) */ |
928 | 0 | if((k->keepon & KEEP_RECV) && (select_bits & CURL_CSELECT_IN)) { |
929 | 0 | result = readwrite_data(data, k, &didwhat, done); |
930 | 0 | if(result || *done) |
931 | 0 | goto out; |
932 | 0 | } |
933 | | |
934 | | /* If we still have writing to do, we check if we have a writable socket. */ |
935 | 0 | if((k->keepon & KEEP_SEND) && (select_bits & CURL_CSELECT_OUT)) { |
936 | | /* write */ |
937 | |
|
938 | 0 | result = readwrite_upload(data, conn, &didwhat); |
939 | 0 | if(result) |
940 | 0 | goto out; |
941 | 0 | } |
942 | | #ifdef USE_HYPER |
943 | | } |
944 | | #endif |
945 | | |
946 | 0 | now = Curl_now(); |
947 | 0 | if(!didwhat) { |
948 | | /* no read no write, this is a timeout? */ |
949 | 0 | if(k->exp100 == EXP100_AWAITING_CONTINUE) { |
950 | | /* This should allow some time for the header to arrive, but only a |
951 | | very short time as otherwise it'll be too much wasted time too |
952 | | often. */ |
953 | | |
954 | | /* Quoting RFC2616, section "8.2.3 Use of the 100 (Continue) Status": |
955 | | |
956 | | Therefore, when a client sends this header field to an origin server |
957 | | (possibly via a proxy) from which it has never seen a 100 (Continue) |
958 | | status, the client SHOULD NOT wait for an indefinite period before |
959 | | sending the request body. |
960 | | |
961 | | */ |
962 | |
|
963 | 0 | timediff_t ms = Curl_timediff(now, k->start100); |
964 | 0 | if(ms >= data->set.expect_100_timeout) { |
965 | | /* we've waited long enough, continue anyway */ |
966 | 0 | k->exp100 = EXP100_SEND_DATA; |
967 | 0 | k->keepon |= KEEP_SEND; |
968 | 0 | Curl_expire_done(data, EXPIRE_100_TIMEOUT); |
969 | 0 | infof(data, "Done waiting for 100-continue"); |
970 | 0 | } |
971 | 0 | } |
972 | |
|
973 | 0 | result = Curl_conn_ev_data_idle(data); |
974 | 0 | if(result) |
975 | 0 | goto out; |
976 | 0 | } |
977 | | |
978 | 0 | if(Curl_pgrsUpdate(data)) |
979 | 0 | result = CURLE_ABORTED_BY_CALLBACK; |
980 | 0 | else |
981 | 0 | result = Curl_speedcheck(data, now); |
982 | 0 | if(result) |
983 | 0 | goto out; |
984 | | |
985 | 0 | if(k->keepon) { |
986 | 0 | if(0 > Curl_timeleft(data, &now, FALSE)) { |
987 | 0 | if(k->size != -1) { |
988 | 0 | failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T |
989 | 0 | " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %" |
990 | 0 | CURL_FORMAT_CURL_OFF_T " bytes received", |
991 | 0 | Curl_timediff(now, data->progress.t_startsingle), |
992 | 0 | k->bytecount, k->size); |
993 | 0 | } |
994 | 0 | else { |
995 | 0 | failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T |
996 | 0 | " milliseconds with %" CURL_FORMAT_CURL_OFF_T " bytes received", |
997 | 0 | Curl_timediff(now, data->progress.t_startsingle), |
998 | 0 | k->bytecount); |
999 | 0 | } |
1000 | 0 | result = CURLE_OPERATION_TIMEDOUT; |
1001 | 0 | goto out; |
1002 | 0 | } |
1003 | 0 | } |
1004 | 0 | else { |
1005 | | /* |
1006 | | * The transfer has been performed. Just make some general checks before |
1007 | | * returning. |
1008 | | */ |
1009 | |
|
1010 | 0 | if(!(data->req.no_body) && (k->size != -1) && |
1011 | 0 | (k->bytecount != k->size) && |
1012 | 0 | #ifdef CURL_DO_LINEEND_CONV |
1013 | | /* Most FTP servers don't adjust their file SIZE response for CRLFs, |
1014 | | so we'll check to see if the discrepancy can be explained |
1015 | | by the number of CRLFs we've changed to LFs. |
1016 | | */ |
1017 | 0 | (k->bytecount != (k->size + data->state.crlf_conversions)) && |
1018 | 0 | #endif /* CURL_DO_LINEEND_CONV */ |
1019 | 0 | !k->newurl) { |
1020 | 0 | failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T |
1021 | 0 | " bytes remaining to read", k->size - k->bytecount); |
1022 | 0 | result = CURLE_PARTIAL_FILE; |
1023 | 0 | goto out; |
1024 | 0 | } |
1025 | 0 | if(Curl_pgrsUpdate(data)) { |
1026 | 0 | result = CURLE_ABORTED_BY_CALLBACK; |
1027 | 0 | goto out; |
1028 | 0 | } |
1029 | 0 | } |
1030 | | |
1031 | | /* Now update the "done" boolean we return */ |
1032 | 0 | *done = (0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS))) ? TRUE : FALSE; |
1033 | 0 | out: |
1034 | 0 | if(result) |
1035 | 0 | DEBUGF(infof(data, "Curl_readwrite() -> %d", result)); |
1036 | 0 | return result; |
1037 | 0 | } |
1038 | | |
1039 | | /* Curl_init_CONNECT() gets called each time the handle switches to CONNECT |
1040 | | which means this gets called once for each subsequent redirect etc */ |
1041 | | void Curl_init_CONNECT(struct Curl_easy *data) |
1042 | 0 | { |
1043 | 0 | data->state.fread_func = data->set.fread_func_set; |
1044 | 0 | data->state.in = data->set.in_set; |
1045 | 0 | data->state.upload = (data->state.httpreq == HTTPREQ_PUT); |
1046 | 0 | } |
1047 | | |
1048 | | /* |
1049 | | * Curl_pretransfer() is called immediately before a transfer starts, and only |
1050 | | * once for one transfer no matter if it has redirects or do multi-pass |
1051 | | * authentication etc. |
1052 | | */ |
1053 | | CURLcode Curl_pretransfer(struct Curl_easy *data) |
1054 | 0 | { |
1055 | 0 | CURLcode result; |
1056 | |
|
1057 | 0 | if(!data->state.url && !data->set.uh) { |
1058 | | /* we can't do anything without URL */ |
1059 | 0 | failf(data, "No URL set"); |
1060 | 0 | return CURLE_URL_MALFORMAT; |
1061 | 0 | } |
1062 | | |
1063 | | /* since the URL may have been redirected in a previous use of this handle */ |
1064 | 0 | if(data->state.url_alloc) { |
1065 | | /* the already set URL is allocated, free it first! */ |
1066 | 0 | Curl_safefree(data->state.url); |
1067 | 0 | data->state.url_alloc = FALSE; |
1068 | 0 | } |
1069 | |
|
1070 | 0 | if(!data->state.url && data->set.uh) { |
1071 | 0 | CURLUcode uc; |
1072 | 0 | free(data->set.str[STRING_SET_URL]); |
1073 | 0 | uc = curl_url_get(data->set.uh, |
1074 | 0 | CURLUPART_URL, &data->set.str[STRING_SET_URL], 0); |
1075 | 0 | if(uc) { |
1076 | 0 | failf(data, "No URL set"); |
1077 | 0 | return CURLE_URL_MALFORMAT; |
1078 | 0 | } |
1079 | 0 | } |
1080 | | |
1081 | 0 | if(data->set.postfields && data->set.set_resume_from) { |
1082 | | /* we can't */ |
1083 | 0 | failf(data, "cannot mix POSTFIELDS with RESUME_FROM"); |
1084 | 0 | return CURLE_BAD_FUNCTION_ARGUMENT; |
1085 | 0 | } |
1086 | | |
1087 | 0 | data->state.prefer_ascii = data->set.prefer_ascii; |
1088 | 0 | #ifdef CURL_LIST_ONLY_PROTOCOL |
1089 | 0 | data->state.list_only = data->set.list_only; |
1090 | 0 | #endif |
1091 | 0 | data->state.httpreq = data->set.method; |
1092 | 0 | data->state.url = data->set.str[STRING_SET_URL]; |
1093 | | |
1094 | | /* Init the SSL session ID cache here. We do it here since we want to do it |
1095 | | after the *_setopt() calls (that could specify the size of the cache) but |
1096 | | before any transfer takes place. */ |
1097 | 0 | result = Curl_ssl_initsessions(data, data->set.general_ssl.max_ssl_sessions); |
1098 | 0 | if(result) |
1099 | 0 | return result; |
1100 | | |
1101 | 0 | data->state.requests = 0; |
1102 | 0 | data->state.followlocation = 0; /* reset the location-follow counter */ |
1103 | 0 | data->state.this_is_a_follow = FALSE; /* reset this */ |
1104 | 0 | data->state.errorbuf = FALSE; /* no error has occurred */ |
1105 | 0 | data->state.httpwant = data->set.httpwant; |
1106 | 0 | data->state.httpversion = 0; |
1107 | 0 | data->state.authproblem = FALSE; |
1108 | 0 | data->state.authhost.want = data->set.httpauth; |
1109 | 0 | data->state.authproxy.want = data->set.proxyauth; |
1110 | 0 | Curl_safefree(data->info.wouldredirect); |
1111 | 0 | Curl_data_priority_clear_state(data); |
1112 | |
|
1113 | 0 | if(data->state.httpreq == HTTPREQ_PUT) |
1114 | 0 | data->state.infilesize = data->set.filesize; |
1115 | 0 | else if((data->state.httpreq != HTTPREQ_GET) && |
1116 | 0 | (data->state.httpreq != HTTPREQ_HEAD)) { |
1117 | 0 | data->state.infilesize = data->set.postfieldsize; |
1118 | 0 | if(data->set.postfields && (data->state.infilesize == -1)) |
1119 | 0 | data->state.infilesize = (curl_off_t)strlen(data->set.postfields); |
1120 | 0 | } |
1121 | 0 | else |
1122 | 0 | data->state.infilesize = 0; |
1123 | | |
1124 | | /* If there is a list of cookie files to read, do it now! */ |
1125 | 0 | Curl_cookie_loadfiles(data); |
1126 | | |
1127 | | /* If there is a list of host pairs to deal with */ |
1128 | 0 | if(data->state.resolve) |
1129 | 0 | result = Curl_loadhostpairs(data); |
1130 | | |
1131 | | /* If there is a list of hsts files to read */ |
1132 | 0 | Curl_hsts_loadfiles(data); |
1133 | |
|
1134 | 0 | if(!result) { |
1135 | | /* Allow data->set.use_port to set which port to use. This needs to be |
1136 | | * disabled for example when we follow Location: headers to URLs using |
1137 | | * different ports! */ |
1138 | 0 | data->state.allow_port = TRUE; |
1139 | |
|
1140 | | #if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) |
1141 | | /************************************************************* |
1142 | | * Tell signal handler to ignore SIGPIPE |
1143 | | *************************************************************/ |
1144 | | if(!data->set.no_signal) |
1145 | | data->state.prev_signal = signal(SIGPIPE, SIG_IGN); |
1146 | | #endif |
1147 | |
|
1148 | 0 | Curl_initinfo(data); /* reset session-specific information "variables" */ |
1149 | 0 | Curl_pgrsResetTransferSizes(data); |
1150 | 0 | Curl_pgrsStartNow(data); |
1151 | | |
1152 | | /* In case the handle is reused and an authentication method was picked |
1153 | | in the session we need to make sure we only use the one(s) we now |
1154 | | consider to be fine */ |
1155 | 0 | data->state.authhost.picked &= data->state.authhost.want; |
1156 | 0 | data->state.authproxy.picked &= data->state.authproxy.want; |
1157 | |
|
1158 | 0 | #ifndef CURL_DISABLE_FTP |
1159 | 0 | data->state.wildcardmatch = data->set.wildcard_enabled; |
1160 | 0 | if(data->state.wildcardmatch) { |
1161 | 0 | struct WildcardData *wc; |
1162 | 0 | if(!data->wildcard) { |
1163 | 0 | data->wildcard = calloc(1, sizeof(struct WildcardData)); |
1164 | 0 | if(!data->wildcard) |
1165 | 0 | return CURLE_OUT_OF_MEMORY; |
1166 | 0 | } |
1167 | 0 | wc = data->wildcard; |
1168 | 0 | if(wc->state < CURLWC_INIT) { |
1169 | 0 | if(wc->ftpwc) |
1170 | 0 | wc->dtor(wc->ftpwc); |
1171 | 0 | Curl_safefree(wc->pattern); |
1172 | 0 | Curl_safefree(wc->path); |
1173 | 0 | result = Curl_wildcard_init(wc); /* init wildcard structures */ |
1174 | 0 | if(result) |
1175 | 0 | return CURLE_OUT_OF_MEMORY; |
1176 | 0 | } |
1177 | 0 | } |
1178 | 0 | #endif |
1179 | 0 | result = Curl_hsts_loadcb(data, data->hsts); |
1180 | 0 | } |
1181 | | |
1182 | | /* |
1183 | | * Set user-agent. Used for HTTP, but since we can attempt to tunnel |
1184 | | * basically anything through an HTTP proxy we can't limit this based on |
1185 | | * protocol. |
1186 | | */ |
1187 | 0 | if(data->set.str[STRING_USERAGENT]) { |
1188 | 0 | Curl_safefree(data->state.aptr.uagent); |
1189 | 0 | data->state.aptr.uagent = |
1190 | 0 | aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]); |
1191 | 0 | if(!data->state.aptr.uagent) |
1192 | 0 | return CURLE_OUT_OF_MEMORY; |
1193 | 0 | } |
1194 | | |
1195 | 0 | if(!result) |
1196 | 0 | result = Curl_setstropt(&data->state.aptr.user, |
1197 | 0 | data->set.str[STRING_USERNAME]); |
1198 | 0 | if(!result) |
1199 | 0 | result = Curl_setstropt(&data->state.aptr.passwd, |
1200 | 0 | data->set.str[STRING_PASSWORD]); |
1201 | 0 | if(!result) |
1202 | 0 | result = Curl_setstropt(&data->state.aptr.proxyuser, |
1203 | 0 | data->set.str[STRING_PROXYUSERNAME]); |
1204 | 0 | if(!result) |
1205 | 0 | result = Curl_setstropt(&data->state.aptr.proxypasswd, |
1206 | 0 | data->set.str[STRING_PROXYPASSWORD]); |
1207 | |
|
1208 | 0 | data->req.headerbytecount = 0; |
1209 | 0 | Curl_headers_cleanup(data); |
1210 | 0 | return result; |
1211 | 0 | } |
1212 | | |
1213 | | /* |
1214 | | * Curl_posttransfer() is called immediately after a transfer ends |
1215 | | */ |
1216 | | CURLcode Curl_posttransfer(struct Curl_easy *data) |
1217 | 0 | { |
1218 | | #if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) |
1219 | | /* restore the signal handler for SIGPIPE before we get back */ |
1220 | | if(!data->set.no_signal) |
1221 | | signal(SIGPIPE, data->state.prev_signal); |
1222 | | #else |
1223 | 0 | (void)data; /* unused parameter */ |
1224 | 0 | #endif |
1225 | |
|
1226 | 0 | return CURLE_OK; |
1227 | 0 | } |
1228 | | |
1229 | | /* |
1230 | | * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string |
1231 | | * as given by the remote server and set up the new URL to request. |
1232 | | * |
1233 | | * This function DOES NOT FREE the given url. |
1234 | | */ |
1235 | | CURLcode Curl_follow(struct Curl_easy *data, |
1236 | | char *newurl, /* the Location: string */ |
1237 | | followtype type) /* see transfer.h */ |
1238 | 0 | { |
1239 | | #ifdef CURL_DISABLE_HTTP |
1240 | | (void)data; |
1241 | | (void)newurl; |
1242 | | (void)type; |
1243 | | /* Location: following will not happen when HTTP is disabled */ |
1244 | | return CURLE_TOO_MANY_REDIRECTS; |
1245 | | #else |
1246 | | |
1247 | | /* Location: redirect */ |
1248 | 0 | bool disallowport = FALSE; |
1249 | 0 | bool reachedmax = FALSE; |
1250 | 0 | CURLUcode uc; |
1251 | |
|
1252 | 0 | DEBUGASSERT(type != FOLLOW_NONE); |
1253 | |
|
1254 | 0 | if(type != FOLLOW_FAKE) |
1255 | 0 | data->state.requests++; /* count all real follows */ |
1256 | 0 | if(type == FOLLOW_REDIR) { |
1257 | 0 | if((data->set.maxredirs != -1) && |
1258 | 0 | (data->state.followlocation >= data->set.maxredirs)) { |
1259 | 0 | reachedmax = TRUE; |
1260 | 0 | type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected |
1261 | | to URL */ |
1262 | 0 | } |
1263 | 0 | else { |
1264 | 0 | data->state.followlocation++; /* count redirect-followings, including |
1265 | | auth reloads */ |
1266 | |
|
1267 | 0 | if(data->set.http_auto_referer) { |
1268 | 0 | CURLU *u; |
1269 | 0 | char *referer = NULL; |
1270 | | |
1271 | | /* We are asked to automatically set the previous URL as the referer |
1272 | | when we get the next URL. We pick the ->url field, which may or may |
1273 | | not be 100% correct */ |
1274 | |
|
1275 | 0 | if(data->state.referer_alloc) { |
1276 | 0 | Curl_safefree(data->state.referer); |
1277 | 0 | data->state.referer_alloc = FALSE; |
1278 | 0 | } |
1279 | | |
1280 | | /* Make a copy of the URL without credentials and fragment */ |
1281 | 0 | u = curl_url(); |
1282 | 0 | if(!u) |
1283 | 0 | return CURLE_OUT_OF_MEMORY; |
1284 | | |
1285 | 0 | uc = curl_url_set(u, CURLUPART_URL, data->state.url, 0); |
1286 | 0 | if(!uc) |
1287 | 0 | uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0); |
1288 | 0 | if(!uc) |
1289 | 0 | uc = curl_url_set(u, CURLUPART_USER, NULL, 0); |
1290 | 0 | if(!uc) |
1291 | 0 | uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0); |
1292 | 0 | if(!uc) |
1293 | 0 | uc = curl_url_get(u, CURLUPART_URL, &referer, 0); |
1294 | |
|
1295 | 0 | curl_url_cleanup(u); |
1296 | |
|
1297 | 0 | if(uc || !referer) |
1298 | 0 | return CURLE_OUT_OF_MEMORY; |
1299 | | |
1300 | 0 | data->state.referer = referer; |
1301 | 0 | data->state.referer_alloc = TRUE; /* yes, free this later */ |
1302 | 0 | } |
1303 | 0 | } |
1304 | 0 | } |
1305 | | |
1306 | 0 | if((type != FOLLOW_RETRY) && |
1307 | 0 | (data->req.httpcode != 401) && (data->req.httpcode != 407) && |
1308 | 0 | Curl_is_absolute_url(newurl, NULL, 0, FALSE)) { |
1309 | | /* If this is not redirect due to a 401 or 407 response and an absolute |
1310 | | URL: don't allow a custom port number */ |
1311 | 0 | disallowport = TRUE; |
1312 | 0 | } |
1313 | |
|
1314 | 0 | DEBUGASSERT(data->state.uh); |
1315 | 0 | uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, |
1316 | 0 | (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME : |
1317 | 0 | ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) | |
1318 | 0 | CURLU_ALLOW_SPACE | |
1319 | 0 | (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)); |
1320 | 0 | if(uc) { |
1321 | 0 | if(type != FOLLOW_FAKE) { |
1322 | 0 | failf(data, "The redirect target URL could not be parsed: %s", |
1323 | 0 | curl_url_strerror(uc)); |
1324 | 0 | return Curl_uc_to_curlcode(uc); |
1325 | 0 | } |
1326 | | |
1327 | | /* the URL could not be parsed for some reason, but since this is FAKE |
1328 | | mode, just duplicate the field as-is */ |
1329 | 0 | newurl = strdup(newurl); |
1330 | 0 | if(!newurl) |
1331 | 0 | return CURLE_OUT_OF_MEMORY; |
1332 | 0 | } |
1333 | 0 | else { |
1334 | 0 | uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0); |
1335 | 0 | if(uc) |
1336 | 0 | return Curl_uc_to_curlcode(uc); |
1337 | | |
1338 | | /* Clear auth if this redirects to a different port number or protocol, |
1339 | | unless permitted */ |
1340 | 0 | if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) { |
1341 | 0 | char *portnum; |
1342 | 0 | int port; |
1343 | 0 | bool clear = FALSE; |
1344 | |
|
1345 | 0 | if(data->set.use_port && data->state.allow_port) |
1346 | | /* a custom port is used */ |
1347 | 0 | port = (int)data->set.use_port; |
1348 | 0 | else { |
1349 | 0 | uc = curl_url_get(data->state.uh, CURLUPART_PORT, &portnum, |
1350 | 0 | CURLU_DEFAULT_PORT); |
1351 | 0 | if(uc) { |
1352 | 0 | free(newurl); |
1353 | 0 | return Curl_uc_to_curlcode(uc); |
1354 | 0 | } |
1355 | 0 | port = atoi(portnum); |
1356 | 0 | free(portnum); |
1357 | 0 | } |
1358 | 0 | if(port != data->info.conn_remote_port) { |
1359 | 0 | infof(data, "Clear auth, redirects to port from %u to %u", |
1360 | 0 | data->info.conn_remote_port, port); |
1361 | 0 | clear = TRUE; |
1362 | 0 | } |
1363 | 0 | else { |
1364 | 0 | char *scheme; |
1365 | 0 | const struct Curl_handler *p; |
1366 | 0 | uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0); |
1367 | 0 | if(uc) { |
1368 | 0 | free(newurl); |
1369 | 0 | return Curl_uc_to_curlcode(uc); |
1370 | 0 | } |
1371 | | |
1372 | 0 | p = Curl_get_scheme_handler(scheme); |
1373 | 0 | if(p && (p->protocol != data->info.conn_protocol)) { |
1374 | 0 | infof(data, "Clear auth, redirects scheme from %s to %s", |
1375 | 0 | data->info.conn_scheme, scheme); |
1376 | 0 | clear = TRUE; |
1377 | 0 | } |
1378 | 0 | free(scheme); |
1379 | 0 | } |
1380 | 0 | if(clear) { |
1381 | 0 | Curl_safefree(data->state.aptr.user); |
1382 | 0 | Curl_safefree(data->state.aptr.passwd); |
1383 | 0 | } |
1384 | 0 | } |
1385 | 0 | } |
1386 | | |
1387 | 0 | if(type == FOLLOW_FAKE) { |
1388 | | /* we're only figuring out the new url if we would've followed locations |
1389 | | but now we're done so we can get out! */ |
1390 | 0 | data->info.wouldredirect = newurl; |
1391 | |
|
1392 | 0 | if(reachedmax) { |
1393 | 0 | failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs); |
1394 | 0 | return CURLE_TOO_MANY_REDIRECTS; |
1395 | 0 | } |
1396 | 0 | return CURLE_OK; |
1397 | 0 | } |
1398 | | |
1399 | 0 | if(disallowport) |
1400 | 0 | data->state.allow_port = FALSE; |
1401 | |
|
1402 | 0 | if(data->state.url_alloc) |
1403 | 0 | Curl_safefree(data->state.url); |
1404 | |
|
1405 | 0 | data->state.url = newurl; |
1406 | 0 | data->state.url_alloc = TRUE; |
1407 | |
|
1408 | 0 | infof(data, "Issue another request to this URL: '%s'", data->state.url); |
1409 | | |
1410 | | /* |
1411 | | * We get here when the HTTP code is 300-399 (and 401). We need to perform |
1412 | | * differently based on exactly what return code there was. |
1413 | | * |
1414 | | * News from 7.10.6: we can also get here on a 401 or 407, in case we act on |
1415 | | * an HTTP (proxy-) authentication scheme other than Basic. |
1416 | | */ |
1417 | 0 | switch(data->info.httpcode) { |
1418 | | /* 401 - Act on a WWW-Authenticate, we keep on moving and do the |
1419 | | Authorization: XXXX header in the HTTP request code snippet */ |
1420 | | /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the |
1421 | | Proxy-Authorization: XXXX header in the HTTP request code snippet */ |
1422 | | /* 300 - Multiple Choices */ |
1423 | | /* 306 - Not used */ |
1424 | | /* 307 - Temporary Redirect */ |
1425 | 0 | default: /* for all above (and the unknown ones) */ |
1426 | | /* Some codes are explicitly mentioned since I've checked RFC2616 and they |
1427 | | * seem to be OK to POST to. |
1428 | | */ |
1429 | 0 | break; |
1430 | 0 | case 301: /* Moved Permanently */ |
1431 | | /* (quote from RFC7231, section 6.4.2) |
1432 | | * |
1433 | | * Note: For historical reasons, a user agent MAY change the request |
1434 | | * method from POST to GET for the subsequent request. If this |
1435 | | * behavior is undesired, the 307 (Temporary Redirect) status code |
1436 | | * can be used instead. |
1437 | | * |
1438 | | * ---- |
1439 | | * |
1440 | | * Many webservers expect this, so these servers often answers to a POST |
1441 | | * request with an error page. To be sure that libcurl gets the page that |
1442 | | * most user agents would get, libcurl has to force GET. |
1443 | | * |
1444 | | * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and |
1445 | | * can be overridden with CURLOPT_POSTREDIR. |
1446 | | */ |
1447 | 0 | if((data->state.httpreq == HTTPREQ_POST |
1448 | 0 | || data->state.httpreq == HTTPREQ_POST_FORM |
1449 | 0 | || data->state.httpreq == HTTPREQ_POST_MIME) |
1450 | 0 | && !(data->set.keep_post & CURL_REDIR_POST_301)) { |
1451 | 0 | infof(data, "Switch from POST to GET"); |
1452 | 0 | data->state.httpreq = HTTPREQ_GET; |
1453 | 0 | } |
1454 | 0 | break; |
1455 | 0 | case 302: /* Found */ |
1456 | | /* (quote from RFC7231, section 6.4.3) |
1457 | | * |
1458 | | * Note: For historical reasons, a user agent MAY change the request |
1459 | | * method from POST to GET for the subsequent request. If this |
1460 | | * behavior is undesired, the 307 (Temporary Redirect) status code |
1461 | | * can be used instead. |
1462 | | * |
1463 | | * ---- |
1464 | | * |
1465 | | * Many webservers expect this, so these servers often answers to a POST |
1466 | | * request with an error page. To be sure that libcurl gets the page that |
1467 | | * most user agents would get, libcurl has to force GET. |
1468 | | * |
1469 | | * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and |
1470 | | * can be overridden with CURLOPT_POSTREDIR. |
1471 | | */ |
1472 | 0 | if((data->state.httpreq == HTTPREQ_POST |
1473 | 0 | || data->state.httpreq == HTTPREQ_POST_FORM |
1474 | 0 | || data->state.httpreq == HTTPREQ_POST_MIME) |
1475 | 0 | && !(data->set.keep_post & CURL_REDIR_POST_302)) { |
1476 | 0 | infof(data, "Switch from POST to GET"); |
1477 | 0 | data->state.httpreq = HTTPREQ_GET; |
1478 | 0 | } |
1479 | 0 | break; |
1480 | | |
1481 | 0 | case 303: /* See Other */ |
1482 | | /* 'See Other' location is not the resource but a substitute for the |
1483 | | * resource. In this case we switch the method to GET/HEAD, unless the |
1484 | | * method is POST and the user specified to keep it as POST. |
1485 | | * https://github.com/curl/curl/issues/5237#issuecomment-614641049 |
1486 | | */ |
1487 | 0 | if(data->state.httpreq != HTTPREQ_GET && |
1488 | 0 | ((data->state.httpreq != HTTPREQ_POST && |
1489 | 0 | data->state.httpreq != HTTPREQ_POST_FORM && |
1490 | 0 | data->state.httpreq != HTTPREQ_POST_MIME) || |
1491 | 0 | !(data->set.keep_post & CURL_REDIR_POST_303))) { |
1492 | 0 | data->state.httpreq = HTTPREQ_GET; |
1493 | 0 | infof(data, "Switch to %s", |
1494 | 0 | data->req.no_body?"HEAD":"GET"); |
1495 | 0 | } |
1496 | 0 | break; |
1497 | 0 | case 304: /* Not Modified */ |
1498 | | /* 304 means we did a conditional request and it was "Not modified". |
1499 | | * We shouldn't get any Location: header in this response! |
1500 | | */ |
1501 | 0 | break; |
1502 | 0 | case 305: /* Use Proxy */ |
1503 | | /* (quote from RFC2616, section 10.3.6): |
1504 | | * "The requested resource MUST be accessed through the proxy given |
1505 | | * by the Location field. The Location field gives the URI of the |
1506 | | * proxy. The recipient is expected to repeat this single request |
1507 | | * via the proxy. 305 responses MUST only be generated by origin |
1508 | | * servers." |
1509 | | */ |
1510 | 0 | break; |
1511 | 0 | } |
1512 | 0 | Curl_pgrsTime(data, TIMER_REDIRECT); |
1513 | 0 | Curl_pgrsResetTransferSizes(data); |
1514 | |
|
1515 | 0 | return CURLE_OK; |
1516 | 0 | #endif /* CURL_DISABLE_HTTP */ |
1517 | 0 | } |
1518 | | |
1519 | | /* Returns CURLE_OK *and* sets '*url' if a request retry is wanted. |
1520 | | |
1521 | | NOTE: that the *url is malloc()ed. */ |
1522 | | CURLcode Curl_retry_request(struct Curl_easy *data, char **url) |
1523 | 0 | { |
1524 | 0 | struct connectdata *conn = data->conn; |
1525 | 0 | bool retry = FALSE; |
1526 | 0 | *url = NULL; |
1527 | | |
1528 | | /* if we're talking upload, we can't do the checks below, unless the protocol |
1529 | | is HTTP as when uploading over HTTP we will still get a response */ |
1530 | 0 | if(data->state.upload && |
1531 | 0 | !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP))) |
1532 | 0 | return CURLE_OK; |
1533 | | |
1534 | 0 | if((data->req.bytecount + data->req.headerbytecount == 0) && |
1535 | 0 | conn->bits.reuse && |
1536 | 0 | (!data->req.no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP)) |
1537 | 0 | #ifndef CURL_DISABLE_RTSP |
1538 | 0 | && (data->set.rtspreq != RTSPREQ_RECEIVE) |
1539 | 0 | #endif |
1540 | 0 | ) |
1541 | | /* We got no data, we attempted to reuse a connection. For HTTP this |
1542 | | can be a retry so we try again regardless if we expected a body. |
1543 | | For other protocols we only try again only if we expected a body. |
1544 | | |
1545 | | This might happen if the connection was left alive when we were |
1546 | | done using it before, but that was closed when we wanted to read from |
1547 | | it again. Bad luck. Retry the same request on a fresh connect! */ |
1548 | 0 | retry = TRUE; |
1549 | 0 | else if(data->state.refused_stream && |
1550 | 0 | (data->req.bytecount + data->req.headerbytecount == 0) ) { |
1551 | | /* This was sent on a refused stream, safe to rerun. A refused stream |
1552 | | error can typically only happen on HTTP/2 level if the stream is safe |
1553 | | to issue again, but the nghttp2 API can deliver the message to other |
1554 | | streams as well, which is why this adds the check the data counters |
1555 | | too. */ |
1556 | 0 | infof(data, "REFUSED_STREAM, retrying a fresh connect"); |
1557 | 0 | data->state.refused_stream = FALSE; /* clear again */ |
1558 | 0 | retry = TRUE; |
1559 | 0 | } |
1560 | 0 | if(retry) { |
1561 | 0 | #define CONN_MAX_RETRIES 5 |
1562 | 0 | if(data->state.retrycount++ >= CONN_MAX_RETRIES) { |
1563 | 0 | failf(data, "Connection died, tried %d times before giving up", |
1564 | 0 | CONN_MAX_RETRIES); |
1565 | 0 | data->state.retrycount = 0; |
1566 | 0 | return CURLE_SEND_ERROR; |
1567 | 0 | } |
1568 | 0 | infof(data, "Connection died, retrying a fresh connect (retry count: %d)", |
1569 | 0 | data->state.retrycount); |
1570 | 0 | *url = strdup(data->state.url); |
1571 | 0 | if(!*url) |
1572 | 0 | return CURLE_OUT_OF_MEMORY; |
1573 | | |
1574 | 0 | connclose(conn, "retry"); /* close this connection */ |
1575 | 0 | conn->bits.retry = TRUE; /* mark this as a connection we're about |
1576 | | to retry. Marking it this way should |
1577 | | prevent i.e HTTP transfers to return |
1578 | | error just because nothing has been |
1579 | | transferred! */ |
1580 | | |
1581 | |
|
1582 | 0 | if((conn->handler->protocol&PROTO_FAMILY_HTTP) && |
1583 | 0 | data->req.writebytecount) { |
1584 | 0 | data->state.rewindbeforesend = TRUE; |
1585 | 0 | infof(data, "state.rewindbeforesend = TRUE"); |
1586 | 0 | } |
1587 | 0 | } |
1588 | 0 | return CURLE_OK; |
1589 | 0 | } |
1590 | | |
1591 | | /* |
1592 | | * Curl_setup_transfer() is called to setup some basic properties for the |
1593 | | * upcoming transfer. |
1594 | | */ |
1595 | | void |
1596 | | Curl_setup_transfer( |
1597 | | struct Curl_easy *data, /* transfer */ |
1598 | | int sockindex, /* socket index to read from or -1 */ |
1599 | | curl_off_t size, /* -1 if unknown at this point */ |
1600 | | bool getheader, /* TRUE if header parsing is wanted */ |
1601 | | int writesockindex /* socket index to write to, it may very well be |
1602 | | the same we read from. -1 disables */ |
1603 | | ) |
1604 | 0 | { |
1605 | 0 | struct SingleRequest *k = &data->req; |
1606 | 0 | struct connectdata *conn = data->conn; |
1607 | 0 | struct HTTP *http = data->req.p.http; |
1608 | 0 | bool httpsending; |
1609 | |
|
1610 | 0 | DEBUGASSERT(conn != NULL); |
1611 | 0 | DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); |
1612 | |
|
1613 | 0 | httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) && |
1614 | 0 | (http->sending == HTTPSEND_REQUEST)); |
1615 | |
|
1616 | 0 | if(conn->bits.multiplex || conn->httpversion >= 20 || httpsending) { |
1617 | | /* when multiplexing, the read/write sockets need to be the same! */ |
1618 | 0 | conn->sockfd = sockindex == -1 ? |
1619 | 0 | ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) : |
1620 | 0 | conn->sock[sockindex]; |
1621 | 0 | conn->writesockfd = conn->sockfd; |
1622 | 0 | if(httpsending) |
1623 | | /* special and very HTTP-specific */ |
1624 | 0 | writesockindex = FIRSTSOCKET; |
1625 | 0 | } |
1626 | 0 | else { |
1627 | 0 | conn->sockfd = sockindex == -1 ? |
1628 | 0 | CURL_SOCKET_BAD : conn->sock[sockindex]; |
1629 | 0 | conn->writesockfd = writesockindex == -1 ? |
1630 | 0 | CURL_SOCKET_BAD:conn->sock[writesockindex]; |
1631 | 0 | } |
1632 | 0 | k->getheader = getheader; |
1633 | |
|
1634 | 0 | k->size = size; |
1635 | | |
1636 | | /* The code sequence below is placed in this function just because all |
1637 | | necessary input is not always known in do_complete() as this function may |
1638 | | be called after that */ |
1639 | |
|
1640 | 0 | if(!k->getheader) { |
1641 | 0 | k->header = FALSE; |
1642 | 0 | if(size > 0) |
1643 | 0 | Curl_pgrsSetDownloadSize(data, size); |
1644 | 0 | } |
1645 | | /* we want header and/or body, if neither then don't do this! */ |
1646 | 0 | if(k->getheader || !data->req.no_body) { |
1647 | |
|
1648 | 0 | if(sockindex != -1) |
1649 | 0 | k->keepon |= KEEP_RECV; |
1650 | |
|
1651 | 0 | if(writesockindex != -1) { |
1652 | | /* HTTP 1.1 magic: |
1653 | | |
1654 | | Even if we require a 100-return code before uploading data, we might |
1655 | | need to write data before that since the REQUEST may not have been |
1656 | | finished sent off just yet. |
1657 | | |
1658 | | Thus, we must check if the request has been sent before we set the |
1659 | | state info where we wait for the 100-return code |
1660 | | */ |
1661 | 0 | if((data->state.expect100header) && |
1662 | 0 | (conn->handler->protocol&PROTO_FAMILY_HTTP) && |
1663 | 0 | (http->sending == HTTPSEND_BODY)) { |
1664 | | /* wait with write until we either got 100-continue or a timeout */ |
1665 | 0 | k->exp100 = EXP100_AWAITING_CONTINUE; |
1666 | 0 | k->start100 = Curl_now(); |
1667 | | |
1668 | | /* Set a timeout for the multi interface. Add the inaccuracy margin so |
1669 | | that we don't fire slightly too early and get denied to run. */ |
1670 | 0 | Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT); |
1671 | 0 | } |
1672 | 0 | else { |
1673 | 0 | if(data->state.expect100header) |
1674 | | /* when we've sent off the rest of the headers, we must await a |
1675 | | 100-continue but first finish sending the request */ |
1676 | 0 | k->exp100 = EXP100_SENDING_REQUEST; |
1677 | | |
1678 | | /* enable the write bit when we're not waiting for continue */ |
1679 | 0 | k->keepon |= KEEP_SEND; |
1680 | 0 | } |
1681 | 0 | } /* if(writesockindex != -1) */ |
1682 | 0 | } /* if(k->getheader || !data->req.no_body) */ |
1683 | |
|
1684 | 0 | } |
1685 | | |
1686 | | CURLcode Curl_xfer_write_resp(struct Curl_easy *data, |
1687 | | char *buf, size_t blen, |
1688 | | bool is_eos, bool *done) |
1689 | 0 | { |
1690 | 0 | CURLcode result = CURLE_OK; |
1691 | |
|
1692 | 0 | if(data->conn->handler->write_resp) { |
1693 | | /* protocol handlers offering this function take full responsibility |
1694 | | * for writing all received download data to the client. */ |
1695 | 0 | result = data->conn->handler->write_resp(data, buf, blen, is_eos, done); |
1696 | 0 | } |
1697 | 0 | else { |
1698 | | /* No special handling by protocol handler, write all received data |
1699 | | * as BODY to the client. */ |
1700 | 0 | if(blen || is_eos) { |
1701 | 0 | int cwtype = CLIENTWRITE_BODY; |
1702 | 0 | if(is_eos) |
1703 | 0 | cwtype |= CLIENTWRITE_EOS; |
1704 | |
|
1705 | 0 | #ifndef CURL_DISABLE_POP3 |
1706 | 0 | if(blen && data->conn->handler->protocol & PROTO_FAMILY_POP3) { |
1707 | 0 | result = data->req.ignorebody? CURLE_OK : |
1708 | 0 | Curl_pop3_write(data, buf, blen); |
1709 | 0 | } |
1710 | 0 | else |
1711 | 0 | #endif /* CURL_DISABLE_POP3 */ |
1712 | 0 | result = Curl_client_write(data, cwtype, buf, blen); |
1713 | 0 | } |
1714 | 0 | } |
1715 | |
|
1716 | 0 | if(!result && is_eos) { |
1717 | | /* If we wrote the EOS, we are definitely done */ |
1718 | 0 | data->req.eos_written = TRUE; |
1719 | 0 | data->req.download_done = TRUE; |
1720 | 0 | } |
1721 | 0 | return result; |
1722 | 0 | } |