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 "cw-out.h"
67 #include "transfer.h"
68 #include "sendf.h"
69 #include "speedcheck.h"
70 #include "progress.h"
71 #include "http.h"
72 #include "url.h"
73 #include "getinfo.h"
74 #include "vtls/vtls.h"
75 #include "vquic/vquic.h"
76 #include "select.h"
77 #include "multiif.h"
78 #include "connect.h"
79 #include "http2.h"
80 #include "mime.h"
81 #include "strcase.h"
82 #include "urlapi-int.h"
83 #include "hsts.h"
84 #include "setopt.h"
85 #include "headers.h"
86
87 /* The last 3 #include files should be in this order */
88 #include "curl_printf.h"
89 #include "curl_memory.h"
90 #include "memdebug.h"
91
92 #if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \
93 !defined(CURL_DISABLE_IMAP)
94 /*
95 * checkheaders() checks the linked list of custom headers for a
96 * particular header (prefix). Provide the prefix without colon!
97 *
98 * Returns a pointer to the first matching header or NULL if none matched.
99 */
Curl_checkheaders(const struct Curl_easy * data,const char * thisheader,const size_t thislen)100 char *Curl_checkheaders(const struct Curl_easy *data,
101 const char *thisheader,
102 const size_t thislen)
103 {
104 struct curl_slist *head;
105 DEBUGASSERT(thislen);
106 DEBUGASSERT(thisheader[thislen-1] != ':');
107
108 for(head = data->set.headers; head; head = head->next) {
109 if(strncasecompare(head->data, thisheader, thislen) &&
110 Curl_headersep(head->data[thislen]) )
111 return head->data;
112 }
113
114 return NULL;
115 }
116 #endif
117
data_pending(struct Curl_easy * data)118 static int data_pending(struct Curl_easy *data)
119 {
120 struct connectdata *conn = data->conn;
121
122 if(conn->handler->protocol&PROTO_FAMILY_FTP)
123 return Curl_conn_data_pending(data, SECONDARYSOCKET);
124
125 /* in the case of libssh2, we can never be really sure that we have emptied
126 its internal buffers so we MUST always try until we get EAGAIN back */
127 return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) ||
128 Curl_conn_data_pending(data, FIRSTSOCKET);
129 }
130
131 /*
132 * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the
133 * remote document with the time provided by CURLOPT_TIMEVAL
134 */
Curl_meets_timecondition(struct Curl_easy * data,time_t timeofdoc)135 bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
136 {
137 if((timeofdoc == 0) || (data->set.timevalue == 0))
138 return TRUE;
139
140 switch(data->set.timecondition) {
141 case CURL_TIMECOND_IFMODSINCE:
142 default:
143 if(timeofdoc <= data->set.timevalue) {
144 infof(data,
145 "The requested document is not new enough");
146 data->info.timecond = TRUE;
147 return FALSE;
148 }
149 break;
150 case CURL_TIMECOND_IFUNMODSINCE:
151 if(timeofdoc >= data->set.timevalue) {
152 infof(data,
153 "The requested document is not old enough");
154 data->info.timecond = TRUE;
155 return FALSE;
156 }
157 break;
158 }
159
160 return TRUE;
161 }
162
xfer_recv_shutdown(struct Curl_easy * data,bool * done)163 static CURLcode xfer_recv_shutdown(struct Curl_easy *data, bool *done)
164 {
165 int sockindex;
166
167 if(!data || !data->conn)
168 return CURLE_FAILED_INIT;
169 if(data->conn->sockfd == CURL_SOCKET_BAD)
170 return CURLE_FAILED_INIT;
171 sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]);
172 return Curl_conn_shutdown(data, sockindex, done);
173 }
174
xfer_recv_shutdown_started(struct Curl_easy * data)175 static bool xfer_recv_shutdown_started(struct Curl_easy *data)
176 {
177 int sockindex;
178
179 if(!data || !data->conn)
180 return CURLE_FAILED_INIT;
181 if(data->conn->sockfd == CURL_SOCKET_BAD)
182 return CURLE_FAILED_INIT;
183 sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]);
184 return Curl_shutdown_started(data, sockindex);
185 }
186
187 /**
188 * Receive raw response data for the transfer.
189 * @param data the transfer
190 * @param buf buffer to keep response data received
191 * @param blen length of `buf`
192 * @param eos_reliable if EOS detection in underlying connection is reliable
193 * @param err error code in case of -1 return
194 * @return number of bytes read or -1 for error
195 */
Curl_xfer_recv_resp(struct Curl_easy * data,char * buf,size_t blen,bool eos_reliable,CURLcode * err)196 static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data,
197 char *buf, size_t blen,
198 bool eos_reliable,
199 CURLcode *err)
200 {
201 ssize_t nread;
202
203 DEBUGASSERT(blen > 0);
204 /* If we are reading BODY data and the connection does NOT handle EOF
205 * and we know the size of the BODY data, limit the read amount */
206 if(!eos_reliable && !data->req.header && data->req.size != -1) {
207 curl_off_t totalleft = data->req.size - data->req.bytecount;
208 if(totalleft <= 0)
209 blen = 0;
210 else if(totalleft < (curl_off_t)blen)
211 blen = (size_t)totalleft;
212 }
213 else if(xfer_recv_shutdown_started(data)) {
214 /* we already reveived everything. Do not try more. */
215 blen = 0;
216 }
217
218 if(!blen) {
219 /* want nothing more */
220 *err = CURLE_OK;
221 nread = 0;
222 }
223 else {
224 *err = Curl_xfer_recv(data, buf, blen, &nread);
225 }
226
227 if(*err)
228 return -1;
229 if(nread == 0) {
230 if(data->req.shutdown) {
231 bool done;
232 *err = xfer_recv_shutdown(data, &done);
233 if(*err)
234 return -1;
235 if(!done) {
236 *err = CURLE_AGAIN;
237 return -1;
238 }
239 }
240 DEBUGF(infof(data, "readwrite_data: we're done"));
241 }
242 DEBUGASSERT(nread >= 0);
243 return nread;
244 }
245
246 /*
247 * Go ahead and do a read if we have a readable socket or if
248 * the stream was rewound (in which case we have data in a
249 * buffer)
250 */
readwrite_data(struct Curl_easy * data,struct SingleRequest * k,int * didwhat)251 static CURLcode readwrite_data(struct Curl_easy *data,
252 struct SingleRequest *k,
253 int *didwhat)
254 {
255 struct connectdata *conn = data->conn;
256 CURLcode result = CURLE_OK;
257 char *buf, *xfer_buf;
258 size_t blen, xfer_blen;
259 int maxloops = 10;
260 curl_off_t total_received = 0;
261 bool is_multiplex = FALSE;
262
263 result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
264 if(result)
265 goto out;
266
267 /* This is where we loop until we have read everything there is to
268 read or we get a CURLE_AGAIN */
269 do {
270 bool is_eos = FALSE;
271 size_t bytestoread;
272 ssize_t nread;
273
274 if(!is_multiplex) {
275 /* Multiplexed connection have inherent handling of EOF and we do not
276 * have to carefully restrict the amount we try to read.
277 * Multiplexed changes only in one direction. */
278 is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
279 }
280
281 buf = xfer_buf;
282 bytestoread = xfer_blen;
283
284 if(bytestoread && data->set.max_recv_speed) {
285 /* In case of speed limit on receiving: if this loop already got
286 * data, break out. If not, limit the amount of bytes to receive.
287 * The overall, timed, speed limiting is done in multi.c */
288 if(total_received)
289 break;
290 if((size_t)data->set.max_recv_speed < bytestoread)
291 bytestoread = (size_t)data->set.max_recv_speed;
292 }
293
294 nread = Curl_xfer_recv_resp(data, buf, bytestoread,
295 is_multiplex, &result);
296 if(nread < 0) {
297 if(CURLE_AGAIN == result) {
298 result = CURLE_OK;
299 break; /* get out of loop */
300 }
301 goto out; /* real error */
302 }
303
304 /* We only get a 0-length read on EndOfStream */
305 blen = (size_t)nread;
306 is_eos = (blen == 0);
307 *didwhat |= KEEP_RECV;
308
309 if(!blen) {
310 /* if we receive 0 or less here, either the data transfer is done or the
311 server closed the connection and we bail out from this! */
312 if(is_multiplex)
313 DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
314 else
315 DEBUGF(infof(data, "nread <= 0, server closed connection, bailing"));
316 /* stop receiving and ALL sending as well, including PAUSE and HOLD.
317 * We might still be paused on receive client writes though, so
318 * keep those bits around. */
319 k->keepon &= ~(KEEP_RECV|KEEP_SENDBITS);
320 if(k->eos_written) /* already did write this to client, leave */
321 break;
322 }
323 total_received += blen;
324
325 result = Curl_xfer_write_resp(data, buf, blen, is_eos);
326 if(result || data->req.done)
327 goto out;
328
329 /* if we are done, we stop receiving. On multiplexed connections,
330 * we should read the EOS. Which may arrive as meta data after
331 * the bytes. Not taking it in might lead to RST of streams. */
332 if((!is_multiplex && data->req.download_done) || is_eos) {
333 data->req.keepon &= ~KEEP_RECV;
334 }
335 /* if we are PAUSEd or stopped receiving, leave the loop */
336 if((k->keepon & KEEP_RECV_PAUSE) || !(k->keepon & KEEP_RECV))
337 break;
338
339 } while(maxloops-- && data_pending(data));
340
341 if((maxloops <= 0) || data_pending(data)) {
342 /* did not read until EAGAIN or there is still pending data, mark as
343 read-again-please */
344 data->state.select_bits = CURL_CSELECT_IN;
345 if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
346 data->state.select_bits |= CURL_CSELECT_OUT;
347 }
348
349 if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
350 (conn->bits.close || is_multiplex)) {
351 /* When we've read the entire thing and the close bit is set, the server
352 may now close the connection. If there's now any kind of sending going
353 on from our side, we need to stop that immediately. */
354 infof(data, "we are done reading and this is set to close, stop send");
355 k->keepon &= ~KEEP_SEND; /* no writing anymore either */
356 k->keepon &= ~KEEP_SEND_PAUSE; /* no pausing anymore either */
357 }
358
359 out:
360 Curl_multi_xfer_buf_release(data, xfer_buf);
361 if(result)
362 DEBUGF(infof(data, "readwrite_data() -> %d", result));
363 return result;
364 }
365
366 /*
367 * Send data to upload to the server, when the socket is writable.
368 */
readwrite_upload(struct Curl_easy * data,int * didwhat)369 static CURLcode readwrite_upload(struct Curl_easy *data, int *didwhat)
370 {
371 if((data->req.keepon & KEEP_SEND_PAUSE))
372 return CURLE_OK;
373
374 /* We should not get here when the sending is already done. It
375 * probably means that someone set `data-req.keepon |= KEEP_SEND`
376 * when it should not. */
377 DEBUGASSERT(!Curl_req_done_sending(data));
378
379 if(!Curl_req_done_sending(data)) {
380 *didwhat |= KEEP_SEND;
381 return Curl_req_send_more(data);
382 }
383 return CURLE_OK;
384 }
385
select_bits_paused(struct Curl_easy * data,int select_bits)386 static int select_bits_paused(struct Curl_easy *data, int select_bits)
387 {
388 /* See issue #11982: we really need to be careful not to progress
389 * a transfer direction when that direction is paused. Not all parts
390 * of our state machine are handling PAUSED transfers correctly. So, we
391 * do not want to go there.
392 * NOTE: we are only interested in PAUSE, not HOLD. */
393
394 /* if there is data in a direction not paused, return false */
395 if(((select_bits & CURL_CSELECT_IN) &&
396 !(data->req.keepon & KEEP_RECV_PAUSE)) ||
397 ((select_bits & CURL_CSELECT_OUT) &&
398 !(data->req.keepon & KEEP_SEND_PAUSE)))
399 return FALSE;
400
401 return (data->req.keepon & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE));
402 }
403
404 /*
405 * Curl_readwrite() is the low-level function to be called when data is to
406 * be read and written to/from the connection.
407 */
Curl_readwrite(struct Curl_easy * data)408 CURLcode Curl_readwrite(struct Curl_easy *data)
409 {
410 struct connectdata *conn = data->conn;
411 struct SingleRequest *k = &data->req;
412 CURLcode result;
413 struct curltime now;
414 int didwhat = 0;
415 int select_bits;
416
417 /* Check if client writes had been paused and can resume now. */
418 if(!(k->keepon & KEEP_RECV_PAUSE) && Curl_cwriter_is_paused(data)) {
419 Curl_conn_ev_data_pause(data, FALSE);
420 result = Curl_cwriter_unpause(data);
421 if(result)
422 goto out;
423 }
424
425 if(data->state.select_bits) {
426 if(select_bits_paused(data, data->state.select_bits)) {
427 /* leave the bits unchanged, so they'll tell us what to do when
428 * this transfer gets unpaused. */
429 DEBUGF(infof(data, "readwrite, select_bits, early return on PAUSED"));
430 result = CURLE_OK;
431 goto out;
432 }
433 select_bits = data->state.select_bits;
434 data->state.select_bits = 0;
435 }
436 else {
437 curl_socket_t fd_read;
438 curl_socket_t fd_write;
439 /* only use the proper socket if the *_HOLD bit is not set simultaneously
440 as then we are in rate limiting state in that transfer direction */
441 if((k->keepon & KEEP_RECVBITS) == KEEP_RECV)
442 fd_read = conn->sockfd;
443 else
444 fd_read = CURL_SOCKET_BAD;
445
446 if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
447 fd_write = conn->writesockfd;
448 else
449 fd_write = CURL_SOCKET_BAD;
450
451 select_bits = Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, 0);
452 }
453
454 if(select_bits == CURL_CSELECT_ERR) {
455 failf(data, "select/poll returned error");
456 result = CURLE_SEND_ERROR;
457 goto out;
458 }
459
460 #ifdef USE_HYPER
461 if(conn->datastream) {
462 result = conn->datastream(data, conn, &didwhat, select_bits);
463 if(result || data->req.done)
464 goto out;
465 }
466 else {
467 #endif
468 /* We go ahead and do a read if we have a readable socket or if
469 the stream was rewound (in which case we have data in a
470 buffer) */
471 if((k->keepon & KEEP_RECV) && (select_bits & CURL_CSELECT_IN)) {
472 result = readwrite_data(data, k, &didwhat);
473 if(result || data->req.done)
474 goto out;
475 }
476
477 /* If we still have writing to do, we check if we have a writable socket. */
478 if(((k->keepon & KEEP_SEND) && (select_bits & CURL_CSELECT_OUT)) ||
479 (k->keepon & KEEP_SEND_TIMED)) {
480 /* write */
481
482 result = readwrite_upload(data, &didwhat);
483 if(result)
484 goto out;
485 }
486 #ifdef USE_HYPER
487 }
488 #endif
489
490 now = Curl_now();
491 if(!didwhat) {
492 result = Curl_conn_ev_data_idle(data);
493 if(result)
494 goto out;
495 }
496
497 if(Curl_pgrsUpdate(data))
498 result = CURLE_ABORTED_BY_CALLBACK;
499 else
500 result = Curl_speedcheck(data, now);
501 if(result)
502 goto out;
503
504 if(k->keepon) {
505 if(0 > Curl_timeleft(data, &now, FALSE)) {
506 if(k->size != -1) {
507 failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
508 " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
509 CURL_FORMAT_CURL_OFF_T " bytes received",
510 Curl_timediff(now, data->progress.t_startsingle),
511 k->bytecount, k->size);
512 }
513 else {
514 failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
515 " milliseconds with %" CURL_FORMAT_CURL_OFF_T " bytes received",
516 Curl_timediff(now, data->progress.t_startsingle),
517 k->bytecount);
518 }
519 result = CURLE_OPERATION_TIMEDOUT;
520 goto out;
521 }
522 }
523 else {
524 /*
525 * The transfer has been performed. Just make some general checks before
526 * returning.
527 */
528 if(!(data->req.no_body) && (k->size != -1) &&
529 (k->bytecount != k->size) &&
530 #ifdef CURL_DO_LINEEND_CONV
531 /* Most FTP servers don't adjust their file SIZE response for CRLFs,
532 so we'll check to see if the discrepancy can be explained
533 by the number of CRLFs we've changed to LFs.
534 */
535 (k->bytecount != (k->size + data->state.crlf_conversions)) &&
536 #endif /* CURL_DO_LINEEND_CONV */
537 !k->newurl) {
538 failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T
539 " bytes remaining to read", k->size - k->bytecount);
540 result = CURLE_PARTIAL_FILE;
541 goto out;
542 }
543 if(Curl_pgrsUpdate(data)) {
544 result = CURLE_ABORTED_BY_CALLBACK;
545 goto out;
546 }
547 }
548
549 /* If there is nothing more to send/recv, the request is done */
550 if(0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS)))
551 data->req.done = TRUE;
552
553 out:
554 if(result)
555 DEBUGF(infof(data, "Curl_readwrite() -> %d", result));
556 return result;
557 }
558
559 /* Curl_init_CONNECT() gets called each time the handle switches to CONNECT
560 which means this gets called once for each subsequent redirect etc */
Curl_init_CONNECT(struct Curl_easy * data)561 void Curl_init_CONNECT(struct Curl_easy *data)
562 {
563 data->state.fread_func = data->set.fread_func_set;
564 data->state.in = data->set.in_set;
565 data->state.upload = (data->state.httpreq == HTTPREQ_PUT);
566 }
567
568 /*
569 * Curl_pretransfer() is called immediately before a transfer starts, and only
570 * once for one transfer no matter if it has redirects or do multi-pass
571 * authentication etc.
572 */
Curl_pretransfer(struct Curl_easy * data)573 CURLcode Curl_pretransfer(struct Curl_easy *data)
574 {
575 CURLcode result;
576
577 if(!data->state.url && !data->set.uh) {
578 /* we can't do anything without URL */
579 failf(data, "No URL set");
580 return CURLE_URL_MALFORMAT;
581 }
582
583 /* since the URL may have been redirected in a previous use of this handle */
584 if(data->state.url_alloc) {
585 /* the already set URL is allocated, free it first! */
586 Curl_safefree(data->state.url);
587 data->state.url_alloc = FALSE;
588 }
589
590 if(!data->state.url && data->set.uh) {
591 CURLUcode uc;
592 free(data->set.str[STRING_SET_URL]);
593 uc = curl_url_get(data->set.uh,
594 CURLUPART_URL, &data->set.str[STRING_SET_URL], 0);
595 if(uc) {
596 failf(data, "No URL set");
597 return CURLE_URL_MALFORMAT;
598 }
599 }
600
601 if(data->set.postfields && data->set.set_resume_from) {
602 /* we can't */
603 failf(data, "cannot mix POSTFIELDS with RESUME_FROM");
604 return CURLE_BAD_FUNCTION_ARGUMENT;
605 }
606
607 data->state.prefer_ascii = data->set.prefer_ascii;
608 #ifdef CURL_LIST_ONLY_PROTOCOL
609 data->state.list_only = data->set.list_only;
610 #endif
611 data->state.httpreq = data->set.method;
612 data->state.url = data->set.str[STRING_SET_URL];
613
614 /* Init the SSL session ID cache here. We do it here since we want to do it
615 after the *_setopt() calls (that could specify the size of the cache) but
616 before any transfer takes place. */
617 result = Curl_ssl_initsessions(data, data->set.general_ssl.max_ssl_sessions);
618 if(result)
619 return result;
620
621 data->state.requests = 0;
622 data->state.followlocation = 0; /* reset the location-follow counter */
623 data->state.this_is_a_follow = FALSE; /* reset this */
624 data->state.errorbuf = FALSE; /* no error has occurred */
625 data->state.httpwant = data->set.httpwant;
626 data->state.httpversion = 0;
627 data->state.authproblem = FALSE;
628 data->state.authhost.want = data->set.httpauth;
629 data->state.authproxy.want = data->set.proxyauth;
630 Curl_safefree(data->info.wouldredirect);
631 Curl_data_priority_clear_state(data);
632
633 if(data->state.httpreq == HTTPREQ_PUT)
634 data->state.infilesize = data->set.filesize;
635 else if((data->state.httpreq != HTTPREQ_GET) &&
636 (data->state.httpreq != HTTPREQ_HEAD)) {
637 data->state.infilesize = data->set.postfieldsize;
638 if(data->set.postfields && (data->state.infilesize == -1))
639 data->state.infilesize = (curl_off_t)strlen(data->set.postfields);
640 }
641 else
642 data->state.infilesize = 0;
643
644 /* If there is a list of cookie files to read, do it now! */
645 Curl_cookie_loadfiles(data);
646
647 /* If there is a list of host pairs to deal with */
648 if(data->state.resolve)
649 result = Curl_loadhostpairs(data);
650
651 /* If there is a list of hsts files to read */
652 Curl_hsts_loadfiles(data);
653
654 if(!result) {
655 /* Allow data->set.use_port to set which port to use. This needs to be
656 * disabled for example when we follow Location: headers to URLs using
657 * different ports! */
658 data->state.allow_port = TRUE;
659
660 #if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
661 /*************************************************************
662 * Tell signal handler to ignore SIGPIPE
663 *************************************************************/
664 if(!data->set.no_signal)
665 data->state.prev_signal = signal(SIGPIPE, SIG_IGN);
666 #endif
667
668 Curl_initinfo(data); /* reset session-specific information "variables" */
669 Curl_pgrsResetTransferSizes(data);
670 Curl_pgrsStartNow(data);
671
672 /* In case the handle is reused and an authentication method was picked
673 in the session we need to make sure we only use the one(s) we now
674 consider to be fine */
675 data->state.authhost.picked &= data->state.authhost.want;
676 data->state.authproxy.picked &= data->state.authproxy.want;
677
678 #ifndef CURL_DISABLE_FTP
679 data->state.wildcardmatch = data->set.wildcard_enabled;
680 if(data->state.wildcardmatch) {
681 struct WildcardData *wc;
682 if(!data->wildcard) {
683 data->wildcard = calloc(1, sizeof(struct WildcardData));
684 if(!data->wildcard)
685 return CURLE_OUT_OF_MEMORY;
686 }
687 wc = data->wildcard;
688 if(wc->state < CURLWC_INIT) {
689 if(wc->ftpwc)
690 wc->dtor(wc->ftpwc);
691 Curl_safefree(wc->pattern);
692 Curl_safefree(wc->path);
693 result = Curl_wildcard_init(wc); /* init wildcard structures */
694 if(result)
695 return CURLE_OUT_OF_MEMORY;
696 }
697 }
698 #endif
699 result = Curl_hsts_loadcb(data, data->hsts);
700 }
701
702 /*
703 * Set user-agent. Used for HTTP, but since we can attempt to tunnel
704 * basically anything through an HTTP proxy we can't limit this based on
705 * protocol.
706 */
707 if(data->set.str[STRING_USERAGENT]) {
708 Curl_safefree(data->state.aptr.uagent);
709 data->state.aptr.uagent =
710 aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
711 if(!data->state.aptr.uagent)
712 return CURLE_OUT_OF_MEMORY;
713 }
714
715 if(!result)
716 result = Curl_setstropt(&data->state.aptr.user,
717 data->set.str[STRING_USERNAME]);
718 if(!result)
719 result = Curl_setstropt(&data->state.aptr.passwd,
720 data->set.str[STRING_PASSWORD]);
721 #ifndef CURL_DISABLE_PROXY
722 if(!result)
723 result = Curl_setstropt(&data->state.aptr.proxyuser,
724 data->set.str[STRING_PROXYUSERNAME]);
725 if(!result)
726 result = Curl_setstropt(&data->state.aptr.proxypasswd,
727 data->set.str[STRING_PROXYPASSWORD]);
728 #endif
729
730 data->req.headerbytecount = 0;
731 Curl_headers_cleanup(data);
732 return result;
733 }
734
735 /*
736 * Curl_posttransfer() is called immediately after a transfer ends
737 */
Curl_posttransfer(struct Curl_easy * data)738 CURLcode Curl_posttransfer(struct Curl_easy *data)
739 {
740 #if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
741 /* restore the signal handler for SIGPIPE before we get back */
742 if(!data->set.no_signal)
743 signal(SIGPIPE, data->state.prev_signal);
744 #else
745 (void)data; /* unused parameter */
746 #endif
747
748 return CURLE_OK;
749 }
750
751 /*
752 * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
753 * as given by the remote server and set up the new URL to request.
754 *
755 * This function DOES NOT FREE the given url.
756 */
Curl_follow(struct Curl_easy * data,char * newurl,followtype type)757 CURLcode Curl_follow(struct Curl_easy *data,
758 char *newurl, /* the Location: string */
759 followtype type) /* see transfer.h */
760 {
761 #ifdef CURL_DISABLE_HTTP
762 (void)data;
763 (void)newurl;
764 (void)type;
765 /* Location: following will not happen when HTTP is disabled */
766 return CURLE_TOO_MANY_REDIRECTS;
767 #else
768
769 /* Location: redirect */
770 bool disallowport = FALSE;
771 bool reachedmax = FALSE;
772 CURLUcode uc;
773
774 DEBUGASSERT(type != FOLLOW_NONE);
775
776 if(type != FOLLOW_FAKE)
777 data->state.requests++; /* count all real follows */
778 if(type == FOLLOW_REDIR) {
779 if((data->set.maxredirs != -1) &&
780 (data->state.followlocation >= data->set.maxredirs)) {
781 reachedmax = TRUE;
782 type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected
783 to URL */
784 }
785 else {
786 data->state.followlocation++; /* count redirect-followings, including
787 auth reloads */
788
789 if(data->set.http_auto_referer) {
790 CURLU *u;
791 char *referer = NULL;
792
793 /* We are asked to automatically set the previous URL as the referer
794 when we get the next URL. We pick the ->url field, which may or may
795 not be 100% correct */
796
797 if(data->state.referer_alloc) {
798 Curl_safefree(data->state.referer);
799 data->state.referer_alloc = FALSE;
800 }
801
802 /* Make a copy of the URL without credentials and fragment */
803 u = curl_url();
804 if(!u)
805 return CURLE_OUT_OF_MEMORY;
806
807 uc = curl_url_set(u, CURLUPART_URL, data->state.url, 0);
808 if(!uc)
809 uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0);
810 if(!uc)
811 uc = curl_url_set(u, CURLUPART_USER, NULL, 0);
812 if(!uc)
813 uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0);
814 if(!uc)
815 uc = curl_url_get(u, CURLUPART_URL, &referer, 0);
816
817 curl_url_cleanup(u);
818
819 if(uc || !referer)
820 return CURLE_OUT_OF_MEMORY;
821
822 data->state.referer = referer;
823 data->state.referer_alloc = TRUE; /* yes, free this later */
824 }
825 }
826 }
827
828 if((type != FOLLOW_RETRY) &&
829 (data->req.httpcode != 401) && (data->req.httpcode != 407) &&
830 Curl_is_absolute_url(newurl, NULL, 0, FALSE)) {
831 /* If this is not redirect due to a 401 or 407 response and an absolute
832 URL: don't allow a custom port number */
833 disallowport = TRUE;
834 }
835
836 DEBUGASSERT(data->state.uh);
837 uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, (unsigned int)
838 ((type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
839 ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
840 CURLU_ALLOW_SPACE |
841 (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
842 if(uc) {
843 if(type != FOLLOW_FAKE) {
844 failf(data, "The redirect target URL could not be parsed: %s",
845 curl_url_strerror(uc));
846 return Curl_uc_to_curlcode(uc);
847 }
848
849 /* the URL could not be parsed for some reason, but since this is FAKE
850 mode, just duplicate the field as-is */
851 newurl = strdup(newurl);
852 if(!newurl)
853 return CURLE_OUT_OF_MEMORY;
854 }
855 else {
856 uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0);
857 if(uc)
858 return Curl_uc_to_curlcode(uc);
859
860 /* Clear auth if this redirects to a different port number or protocol,
861 unless permitted */
862 if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) {
863 char *portnum;
864 int port;
865 bool clear = FALSE;
866
867 if(data->set.use_port && data->state.allow_port)
868 /* a custom port is used */
869 port = (int)data->set.use_port;
870 else {
871 uc = curl_url_get(data->state.uh, CURLUPART_PORT, &portnum,
872 CURLU_DEFAULT_PORT);
873 if(uc) {
874 free(newurl);
875 return Curl_uc_to_curlcode(uc);
876 }
877 port = atoi(portnum);
878 free(portnum);
879 }
880 if(port != data->info.conn_remote_port) {
881 infof(data, "Clear auth, redirects to port from %u to %u",
882 data->info.conn_remote_port, port);
883 clear = TRUE;
884 }
885 else {
886 char *scheme;
887 const struct Curl_handler *p;
888 uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0);
889 if(uc) {
890 free(newurl);
891 return Curl_uc_to_curlcode(uc);
892 }
893
894 p = Curl_get_scheme_handler(scheme);
895 if(p && (p->protocol != data->info.conn_protocol)) {
896 infof(data, "Clear auth, redirects scheme from %s to %s",
897 data->info.conn_scheme, scheme);
898 clear = TRUE;
899 }
900 free(scheme);
901 }
902 if(clear) {
903 Curl_safefree(data->state.aptr.user);
904 Curl_safefree(data->state.aptr.passwd);
905 }
906 }
907 }
908
909 if(type == FOLLOW_FAKE) {
910 /* we're only figuring out the new url if we would've followed locations
911 but now we're done so we can get out! */
912 data->info.wouldredirect = newurl;
913
914 if(reachedmax) {
915 failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs);
916 return CURLE_TOO_MANY_REDIRECTS;
917 }
918 return CURLE_OK;
919 }
920
921 if(disallowport)
922 data->state.allow_port = FALSE;
923
924 if(data->state.url_alloc)
925 Curl_safefree(data->state.url);
926
927 data->state.url = newurl;
928 data->state.url_alloc = TRUE;
929 Curl_req_soft_reset(&data->req, data);
930 infof(data, "Issue another request to this URL: '%s'", data->state.url);
931
932 /*
933 * We get here when the HTTP code is 300-399 (and 401). We need to perform
934 * differently based on exactly what return code there was.
935 *
936 * News from 7.10.6: we can also get here on a 401 or 407, in case we act on
937 * an HTTP (proxy-) authentication scheme other than Basic.
938 */
939 switch(data->info.httpcode) {
940 /* 401 - Act on a WWW-Authenticate, we keep on moving and do the
941 Authorization: XXXX header in the HTTP request code snippet */
942 /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the
943 Proxy-Authorization: XXXX header in the HTTP request code snippet */
944 /* 300 - Multiple Choices */
945 /* 306 - Not used */
946 /* 307 - Temporary Redirect */
947 default: /* for all above (and the unknown ones) */
948 /* Some codes are explicitly mentioned since I've checked RFC2616 and they
949 * seem to be OK to POST to.
950 */
951 break;
952 case 301: /* Moved Permanently */
953 /* (quote from RFC7231, section 6.4.2)
954 *
955 * Note: For historical reasons, a user agent MAY change the request
956 * method from POST to GET for the subsequent request. If this
957 * behavior is undesired, the 307 (Temporary Redirect) status code
958 * can be used instead.
959 *
960 * ----
961 *
962 * Many webservers expect this, so these servers often answers to a POST
963 * request with an error page. To be sure that libcurl gets the page that
964 * most user agents would get, libcurl has to force GET.
965 *
966 * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
967 * can be overridden with CURLOPT_POSTREDIR.
968 */
969 if((data->state.httpreq == HTTPREQ_POST
970 || data->state.httpreq == HTTPREQ_POST_FORM
971 || data->state.httpreq == HTTPREQ_POST_MIME)
972 && !(data->set.keep_post & CURL_REDIR_POST_301)) {
973 infof(data, "Switch from POST to GET");
974 data->state.httpreq = HTTPREQ_GET;
975 Curl_creader_set_rewind(data, FALSE);
976 }
977 break;
978 case 302: /* Found */
979 /* (quote from RFC7231, section 6.4.3)
980 *
981 * Note: For historical reasons, a user agent MAY change the request
982 * method from POST to GET for the subsequent request. If this
983 * behavior is undesired, the 307 (Temporary Redirect) status code
984 * can be used instead.
985 *
986 * ----
987 *
988 * Many webservers expect this, so these servers often answers to a POST
989 * request with an error page. To be sure that libcurl gets the page that
990 * most user agents would get, libcurl has to force GET.
991 *
992 * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
993 * can be overridden with CURLOPT_POSTREDIR.
994 */
995 if((data->state.httpreq == HTTPREQ_POST
996 || data->state.httpreq == HTTPREQ_POST_FORM
997 || data->state.httpreq == HTTPREQ_POST_MIME)
998 && !(data->set.keep_post & CURL_REDIR_POST_302)) {
999 infof(data, "Switch from POST to GET");
1000 data->state.httpreq = HTTPREQ_GET;
1001 Curl_creader_set_rewind(data, FALSE);
1002 }
1003 break;
1004
1005 case 303: /* See Other */
1006 /* 'See Other' location is not the resource but a substitute for the
1007 * resource. In this case we switch the method to GET/HEAD, unless the
1008 * method is POST and the user specified to keep it as POST.
1009 * https://github.com/curl/curl/issues/5237#issuecomment-614641049
1010 */
1011 if(data->state.httpreq != HTTPREQ_GET &&
1012 ((data->state.httpreq != HTTPREQ_POST &&
1013 data->state.httpreq != HTTPREQ_POST_FORM &&
1014 data->state.httpreq != HTTPREQ_POST_MIME) ||
1015 !(data->set.keep_post & CURL_REDIR_POST_303))) {
1016 data->state.httpreq = HTTPREQ_GET;
1017 infof(data, "Switch to %s",
1018 data->req.no_body?"HEAD":"GET");
1019 }
1020 break;
1021 case 304: /* Not Modified */
1022 /* 304 means we did a conditional request and it was "Not modified".
1023 * We shouldn't get any Location: header in this response!
1024 */
1025 break;
1026 case 305: /* Use Proxy */
1027 /* (quote from RFC2616, section 10.3.6):
1028 * "The requested resource MUST be accessed through the proxy given
1029 * by the Location field. The Location field gives the URI of the
1030 * proxy. The recipient is expected to repeat this single request
1031 * via the proxy. 305 responses MUST only be generated by origin
1032 * servers."
1033 */
1034 break;
1035 }
1036 Curl_pgrsTime(data, TIMER_REDIRECT);
1037 Curl_pgrsResetTransferSizes(data);
1038
1039 return CURLE_OK;
1040 #endif /* CURL_DISABLE_HTTP */
1041 }
1042
1043 /* Returns CURLE_OK *and* sets '*url' if a request retry is wanted.
1044
1045 NOTE: that the *url is malloc()ed. */
Curl_retry_request(struct Curl_easy * data,char ** url)1046 CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
1047 {
1048 struct connectdata *conn = data->conn;
1049 bool retry = FALSE;
1050 *url = NULL;
1051
1052 /* if we're talking upload, we can't do the checks below, unless the protocol
1053 is HTTP as when uploading over HTTP we will still get a response */
1054 if(data->state.upload &&
1055 !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)))
1056 return CURLE_OK;
1057
1058 if((data->req.bytecount + data->req.headerbytecount == 0) &&
1059 conn->bits.reuse &&
1060 (!data->req.no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP))
1061 #ifndef CURL_DISABLE_RTSP
1062 && (data->set.rtspreq != RTSPREQ_RECEIVE)
1063 #endif
1064 )
1065 /* We got no data, we attempted to reuse a connection. For HTTP this
1066 can be a retry so we try again regardless if we expected a body.
1067 For other protocols we only try again only if we expected a body.
1068
1069 This might happen if the connection was left alive when we were
1070 done using it before, but that was closed when we wanted to read from
1071 it again. Bad luck. Retry the same request on a fresh connect! */
1072 retry = TRUE;
1073 else if(data->state.refused_stream &&
1074 (data->req.bytecount + data->req.headerbytecount == 0) ) {
1075 /* This was sent on a refused stream, safe to rerun. A refused stream
1076 error can typically only happen on HTTP/2 level if the stream is safe
1077 to issue again, but the nghttp2 API can deliver the message to other
1078 streams as well, which is why this adds the check the data counters
1079 too. */
1080 infof(data, "REFUSED_STREAM, retrying a fresh connect");
1081 data->state.refused_stream = FALSE; /* clear again */
1082 retry = TRUE;
1083 }
1084 if(retry) {
1085 #define CONN_MAX_RETRIES 5
1086 if(data->state.retrycount++ >= CONN_MAX_RETRIES) {
1087 failf(data, "Connection died, tried %d times before giving up",
1088 CONN_MAX_RETRIES);
1089 data->state.retrycount = 0;
1090 return CURLE_SEND_ERROR;
1091 }
1092 infof(data, "Connection died, retrying a fresh connect (retry count: %d)",
1093 data->state.retrycount);
1094 *url = strdup(data->state.url);
1095 if(!*url)
1096 return CURLE_OUT_OF_MEMORY;
1097
1098 connclose(conn, "retry"); /* close this connection */
1099 conn->bits.retry = TRUE; /* mark this as a connection we're about
1100 to retry. Marking it this way should
1101 prevent i.e HTTP transfers to return
1102 error just because nothing has been
1103 transferred! */
1104 Curl_creader_set_rewind(data, TRUE);
1105 }
1106 return CURLE_OK;
1107 }
1108
1109 /*
1110 * xfer_setup() is called to setup basic properties for the transfer.
1111 */
xfer_setup(struct Curl_easy * data,int sockindex,curl_off_t size,bool getheader,int writesockindex,bool shutdown)1112 static void xfer_setup(
1113 struct Curl_easy *data, /* transfer */
1114 int sockindex, /* socket index to read from or -1 */
1115 curl_off_t size, /* -1 if unknown at this point */
1116 bool getheader, /* TRUE if header parsing is wanted */
1117 int writesockindex, /* socket index to write to, it may very well be
1118 the same we read from. -1 disables */
1119 bool shutdown /* shutdown connection at transfer end. Only
1120 * supported when sending OR receiving. */
1121 )
1122 {
1123 struct SingleRequest *k = &data->req;
1124 struct connectdata *conn = data->conn;
1125 bool want_send = Curl_req_want_send(data);
1126
1127 DEBUGASSERT(conn != NULL);
1128 DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
1129 DEBUGASSERT((writesockindex <= 1) && (writesockindex >= -1));
1130 DEBUGASSERT(!shutdown || (sockindex == -1) || (writesockindex == -1));
1131
1132 if(conn->bits.multiplex || conn->httpversion >= 20 || want_send) {
1133 /* when multiplexing, the read/write sockets need to be the same! */
1134 conn->sockfd = sockindex == -1 ?
1135 ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) :
1136 conn->sock[sockindex];
1137 conn->writesockfd = conn->sockfd;
1138 if(want_send)
1139 /* special and very HTTP-specific */
1140 writesockindex = FIRSTSOCKET;
1141 }
1142 else {
1143 conn->sockfd = sockindex == -1 ?
1144 CURL_SOCKET_BAD : conn->sock[sockindex];
1145 conn->writesockfd = writesockindex == -1 ?
1146 CURL_SOCKET_BAD:conn->sock[writesockindex];
1147 }
1148
1149 k->getheader = getheader;
1150 k->size = size;
1151 k->shutdown = shutdown;
1152
1153 /* The code sequence below is placed in this function just because all
1154 necessary input is not always known in do_complete() as this function may
1155 be called after that */
1156
1157 if(!k->getheader) {
1158 k->header = FALSE;
1159 if(size > 0)
1160 Curl_pgrsSetDownloadSize(data, size);
1161 }
1162 /* we want header and/or body, if neither then don't do this! */
1163 if(k->getheader || !data->req.no_body) {
1164
1165 if(sockindex != -1)
1166 k->keepon |= KEEP_RECV;
1167
1168 if(writesockindex != -1)
1169 k->keepon |= KEEP_SEND;
1170 } /* if(k->getheader || !data->req.no_body) */
1171
1172 }
1173
Curl_xfer_setup_nop(struct Curl_easy * data)1174 void Curl_xfer_setup_nop(struct Curl_easy *data)
1175 {
1176 xfer_setup(data, -1, -1, FALSE, -1, FALSE);
1177 }
1178
Curl_xfer_setup1(struct Curl_easy * data,int send_recv,curl_off_t recv_size,bool getheader)1179 void Curl_xfer_setup1(struct Curl_easy *data,
1180 int send_recv,
1181 curl_off_t recv_size,
1182 bool getheader)
1183 {
1184 int recv_index = (send_recv & CURL_XFER_RECV)? FIRSTSOCKET : -1;
1185 int send_index = (send_recv & CURL_XFER_SEND)? FIRSTSOCKET : -1;
1186 DEBUGASSERT((recv_index >= 0) || (recv_size == -1));
1187 xfer_setup(data, recv_index, recv_size, getheader, send_index, FALSE);
1188 }
1189
Curl_xfer_setup2(struct Curl_easy * data,int send_recv,curl_off_t recv_size,bool shutdown)1190 void Curl_xfer_setup2(struct Curl_easy *data,
1191 int send_recv,
1192 curl_off_t recv_size,
1193 bool shutdown)
1194 {
1195 int recv_index = (send_recv & CURL_XFER_RECV)? SECONDARYSOCKET : -1;
1196 int send_index = (send_recv & CURL_XFER_SEND)? SECONDARYSOCKET : -1;
1197 DEBUGASSERT((recv_index >= 0) || (recv_size == -1));
1198 xfer_setup(data, recv_index, recv_size, FALSE, send_index, shutdown);
1199 }
1200
Curl_xfer_write_resp(struct Curl_easy * data,const char * buf,size_t blen,bool is_eos)1201 CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
1202 const char *buf, size_t blen,
1203 bool is_eos)
1204 {
1205 CURLcode result = CURLE_OK;
1206
1207 if(data->conn->handler->write_resp) {
1208 /* protocol handlers offering this function take full responsibility
1209 * for writing all received download data to the client. */
1210 result = data->conn->handler->write_resp(data, buf, blen, is_eos);
1211 }
1212 else {
1213 /* No special handling by protocol handler, write all received data
1214 * as BODY to the client. */
1215 if(blen || is_eos) {
1216 int cwtype = CLIENTWRITE_BODY;
1217 if(is_eos)
1218 cwtype |= CLIENTWRITE_EOS;
1219
1220 #ifndef CURL_DISABLE_POP3
1221 if(blen && data->conn->handler->protocol & PROTO_FAMILY_POP3) {
1222 result = data->req.ignorebody? CURLE_OK :
1223 Curl_pop3_write(data, buf, blen);
1224 }
1225 else
1226 #endif /* CURL_DISABLE_POP3 */
1227 result = Curl_client_write(data, cwtype, buf, blen);
1228 }
1229 }
1230
1231 if(!result && is_eos) {
1232 /* If we wrote the EOS, we are definitely done */
1233 data->req.eos_written = TRUE;
1234 data->req.download_done = TRUE;
1235 }
1236 CURL_TRC_WRITE(data, "xfer_write_resp(len=%zu, eos=%d) -> %d",
1237 blen, is_eos, result);
1238 return result;
1239 }
1240
Curl_xfer_write_resp_hd(struct Curl_easy * data,const char * hd0,size_t hdlen,bool is_eos)1241 CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
1242 const char *hd0, size_t hdlen, bool is_eos)
1243 {
1244 if(data->conn->handler->write_resp_hd) {
1245 /* protocol handlers offering this function take full responsibility
1246 * for writing all received download data to the client. */
1247 return data->conn->handler->write_resp_hd(data, hd0, hdlen, is_eos);
1248 }
1249 /* No special handling by protocol handler, write as response bytes */
1250 return Curl_xfer_write_resp(data, hd0, hdlen, is_eos);
1251 }
1252
Curl_xfer_write_done(struct Curl_easy * data,bool premature)1253 CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature)
1254 {
1255 (void)premature;
1256 return Curl_cw_out_done(data);
1257 }
1258
Curl_xfer_send(struct Curl_easy * data,const void * buf,size_t blen,size_t * pnwritten)1259 CURLcode Curl_xfer_send(struct Curl_easy *data,
1260 const void *buf, size_t blen,
1261 size_t *pnwritten)
1262 {
1263 CURLcode result;
1264 int sockindex;
1265
1266 if(!data || !data->conn)
1267 return CURLE_FAILED_INIT;
1268 /* FIXME: would like to enable this, but some protocols (MQTT) do not
1269 * setup the transfer correctly, it seems
1270 if(data->conn->writesockfd == CURL_SOCKET_BAD) {
1271 failf(data, "transfer not setup for sending");
1272 DEBUGASSERT(0);
1273 return CURLE_SEND_ERROR;
1274 } */
1275 sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
1276 (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
1277 result = Curl_conn_send(data, sockindex, buf, blen, pnwritten);
1278 if(result == CURLE_AGAIN) {
1279 result = CURLE_OK;
1280 *pnwritten = 0;
1281 }
1282 else if(!result && *pnwritten)
1283 data->info.request_size += *pnwritten;
1284
1285 return result;
1286 }
1287
Curl_xfer_recv(struct Curl_easy * data,char * buf,size_t blen,ssize_t * pnrcvd)1288 CURLcode Curl_xfer_recv(struct Curl_easy *data,
1289 char *buf, size_t blen,
1290 ssize_t *pnrcvd)
1291 {
1292 int sockindex;
1293
1294 if(!data || !data->conn)
1295 return CURLE_FAILED_INIT;
1296 /* FIXME: would like to enable this, but some protocols (MQTT) do not
1297 * setup the transfer correctly, it seems
1298 if(data->conn->sockfd == CURL_SOCKET_BAD) {
1299 failf(data, "transfer not setup for receiving");
1300 DEBUGASSERT(0);
1301 return CURLE_RECV_ERROR;
1302 } */
1303 sockindex = ((data->conn->sockfd != CURL_SOCKET_BAD) &&
1304 (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]));
1305 if(data->set.buffer_size > 0 && (size_t)data->set.buffer_size < blen)
1306 blen = (size_t)data->set.buffer_size;
1307 return Curl_conn_recv(data, sockindex, buf, blen, pnrcvd);
1308 }
1309
Curl_xfer_send_close(struct Curl_easy * data)1310 CURLcode Curl_xfer_send_close(struct Curl_easy *data)
1311 {
1312 Curl_conn_ev_data_done_send(data);
1313 return CURLE_OK;
1314 }
1315
Curl_xfer_send_shutdown(struct Curl_easy * data,bool * done)1316 CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done)
1317 {
1318 int sockindex;
1319
1320 if(!data || !data->conn)
1321 return CURLE_FAILED_INIT;
1322 if(data->conn->writesockfd == CURL_SOCKET_BAD)
1323 return CURLE_FAILED_INIT;
1324 sockindex = (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]);
1325 return Curl_conn_shutdown(data, sockindex, done);
1326 }
1327
Curl_xfer_is_blocked(struct Curl_easy * data)1328 bool Curl_xfer_is_blocked(struct Curl_easy *data)
1329 {
1330 bool want_send = ((data)->req.keepon & KEEP_SEND);
1331 bool want_recv = ((data)->req.keepon & KEEP_RECV);
1332 if(!want_send)
1333 return (want_recv && Curl_cwriter_is_paused(data));
1334 else if(!want_recv)
1335 return (want_send && Curl_creader_is_paused(data));
1336 else
1337 return Curl_creader_is_paused(data) && Curl_cwriter_is_paused(data);
1338 }
1339