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