xref: /curl/lib/transfer.c (revision cb5c7039)
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