• 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 
27 #include "urldata.h"
28 #include "cfilters.h"
29 #include "dynbuf.h"
30 #include "doh.h"
31 #include "multiif.h"
32 #include "progress.h"
33 #include "request.h"
34 #include "sendf.h"
35 #include "transfer.h"
36 #include "url.h"
37 
38 /* The last 3 #include files should be in this order */
39 #include "curl_printf.h"
40 #include "curl_memory.h"
41 #include "memdebug.h"
42 
Curl_req_init(struct SingleRequest * req)43 void Curl_req_init(struct SingleRequest *req)
44 {
45   memset(req, 0, sizeof(*req));
46 }
47 
Curl_req_soft_reset(struct SingleRequest * req,struct Curl_easy * data)48 CURLcode Curl_req_soft_reset(struct SingleRequest *req,
49                              struct Curl_easy *data)
50 {
51   CURLcode result;
52 
53   req->done = FALSE;
54   req->upload_done = FALSE;
55   req->upload_aborted = FALSE;
56   req->download_done = FALSE;
57   req->eos_written = FALSE;
58   req->eos_read = FALSE;
59   req->eos_sent = FALSE;
60   req->ignorebody = FALSE;
61   req->shutdown = FALSE;
62   req->bytecount = 0;
63   req->writebytecount = 0;
64   req->header = TRUE; /* assume header */
65   req->headerline = 0;
66   req->headerbytecount = 0;
67   req->allheadercount =  0;
68   req->deductheadercount = 0;
69   req->httpversion_sent = 0;
70   req->httpversion = 0;
71   result = Curl_client_start(data);
72   if(result)
73     return result;
74 
75   if(!req->sendbuf_init) {
76     Curl_bufq_init2(&req->sendbuf, data->set.upload_buffer_size, 1,
77                     BUFQ_OPT_SOFT_LIMIT);
78     req->sendbuf_init = TRUE;
79   }
80   else {
81     Curl_bufq_reset(&req->sendbuf);
82     if(data->set.upload_buffer_size != req->sendbuf.chunk_size) {
83       Curl_bufq_free(&req->sendbuf);
84       Curl_bufq_init2(&req->sendbuf, data->set.upload_buffer_size, 1,
85                       BUFQ_OPT_SOFT_LIMIT);
86     }
87   }
88 
89   return CURLE_OK;
90 }
91 
Curl_req_start(struct SingleRequest * req,struct Curl_easy * data)92 CURLcode Curl_req_start(struct SingleRequest *req,
93                         struct Curl_easy *data)
94 {
95   req->start = Curl_now();
96   return Curl_req_soft_reset(req, data);
97 }
98 
99 static CURLcode req_flush(struct Curl_easy *data);
100 
Curl_req_done(struct SingleRequest * req,struct Curl_easy * data,bool aborted)101 CURLcode Curl_req_done(struct SingleRequest *req,
102                        struct Curl_easy *data, bool aborted)
103 {
104   (void)req;
105   if(!aborted)
106     (void)req_flush(data);
107   Curl_client_reset(data);
108 #ifndef CURL_DISABLE_DOH
109   Curl_doh_close(data);
110 #endif
111   return CURLE_OK;
112 }
113 
Curl_req_hard_reset(struct SingleRequest * req,struct Curl_easy * data)114 void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data)
115 {
116   struct curltime t0 = {0, 0};
117 
118   /* This is a bit ugly. `req->p` is a union and we assume we can
119    * free this safely without leaks. */
120   Curl_safefree(req->p.ftp);
121   Curl_safefree(req->newurl);
122   Curl_client_reset(data);
123   if(req->sendbuf_init)
124     Curl_bufq_reset(&req->sendbuf);
125 
126 #ifndef CURL_DISABLE_DOH
127   Curl_doh_close(data);
128 #endif
129   /* Can no longer memset() this struct as we need to keep some state */
130   req->size = -1;
131   req->maxdownload = -1;
132   req->bytecount = 0;
133   req->writebytecount = 0;
134   req->start = t0;
135   req->headerbytecount = 0;
136   req->allheadercount =  0;
137   req->deductheadercount = 0;
138   req->headerline = 0;
139   req->offset = 0;
140   req->httpcode = 0;
141   req->keepon = 0;
142   req->upgr101 = UPGR101_INIT;
143   req->timeofdoc = 0;
144   req->location = NULL;
145   req->newurl = NULL;
146 #ifndef CURL_DISABLE_COOKIES
147   req->setcookies = 0;
148 #endif
149   req->header = FALSE;
150   req->content_range = FALSE;
151   req->download_done = FALSE;
152   req->eos_written = FALSE;
153   req->eos_read = FALSE;
154   req->eos_sent = FALSE;
155   req->upload_done = FALSE;
156   req->upload_aborted = FALSE;
157   req->ignorebody = FALSE;
158   req->http_bodyless = FALSE;
159   req->chunk = FALSE;
160   req->ignore_cl = FALSE;
161   req->upload_chunky = FALSE;
162   req->getheader = FALSE;
163   req->no_body = data->set.opt_no_body;
164   req->authneg = FALSE;
165   req->shutdown = FALSE;
166 }
167 
Curl_req_free(struct SingleRequest * req,struct Curl_easy * data)168 void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data)
169 {
170   /* This is a bit ugly. `req->p` is a union and we assume we can
171    * free this safely without leaks. */
172   Curl_safefree(req->p.ftp);
173   Curl_safefree(req->newurl);
174   if(req->sendbuf_init)
175     Curl_bufq_free(&req->sendbuf);
176   Curl_client_cleanup(data);
177 
178 #ifndef CURL_DISABLE_DOH
179   Curl_doh_cleanup(data);
180 #endif
181 }
182 
xfer_send(struct Curl_easy * data,const char * buf,size_t blen,size_t hds_len,size_t * pnwritten)183 static CURLcode xfer_send(struct Curl_easy *data,
184                           const char *buf, size_t blen,
185                           size_t hds_len, size_t *pnwritten)
186 {
187   CURLcode result = CURLE_OK;
188   bool eos = FALSE;
189 
190   *pnwritten = 0;
191   DEBUGASSERT(hds_len <= blen);
192 #ifdef DEBUGBUILD
193   {
194     /* Allow debug builds to override this logic to force short initial
195        sends */
196     size_t body_len = blen - hds_len;
197     char *p = getenv("CURL_SMALLREQSEND");
198     if(p) {
199       size_t body_small = (size_t)strtoul(p, NULL, 10);
200       if(body_small && body_small < body_len)
201         blen = hds_len + body_small;
202     }
203   }
204 #endif
205   /* Make sure this does not send more body bytes than what the max send
206      speed says. The headers do not count to the max speed. */
207   if(data->set.max_send_speed) {
208     size_t body_bytes = blen - hds_len;
209     if((curl_off_t)body_bytes > data->set.max_send_speed)
210       blen = hds_len + (size_t)data->set.max_send_speed;
211   }
212 
213   if(data->req.eos_read &&
214     (Curl_bufq_is_empty(&data->req.sendbuf) ||
215      Curl_bufq_len(&data->req.sendbuf) == blen)) {
216     DEBUGF(infof(data, "sending last upload chunk of %zu bytes", blen));
217     eos = TRUE;
218   }
219   result = Curl_xfer_send(data, buf, blen, eos, pnwritten);
220   if(!result) {
221     if(eos && (blen == *pnwritten))
222       data->req.eos_sent = TRUE;
223     if(*pnwritten) {
224       if(hds_len)
225         Curl_debug(data, CURLINFO_HEADER_OUT, (char *)buf,
226                    CURLMIN(hds_len, *pnwritten));
227       if(*pnwritten > hds_len) {
228         size_t body_len = *pnwritten - hds_len;
229         Curl_debug(data, CURLINFO_DATA_OUT, (char *)buf + hds_len, body_len);
230         data->req.writebytecount += body_len;
231         Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
232       }
233     }
234   }
235   return result;
236 }
237 
req_send_buffer_flush(struct Curl_easy * data)238 static CURLcode req_send_buffer_flush(struct Curl_easy *data)
239 {
240   CURLcode result = CURLE_OK;
241   const unsigned char *buf;
242   size_t blen;
243 
244   while(Curl_bufq_peek(&data->req.sendbuf, &buf, &blen)) {
245     size_t nwritten, hds_len = CURLMIN(data->req.sendbuf_hds_len, blen);
246     result = xfer_send(data, (const char *)buf, blen, hds_len, &nwritten);
247     if(result)
248       break;
249 
250     Curl_bufq_skip(&data->req.sendbuf, nwritten);
251     if(hds_len) {
252       data->req.sendbuf_hds_len -= CURLMIN(hds_len, nwritten);
253     }
254     /* leave if we could not send all. Maybe network blocking or
255      * speed limits on transfer */
256     if(nwritten < blen)
257       break;
258   }
259   return result;
260 }
261 
req_set_upload_done(struct Curl_easy * data)262 static CURLcode req_set_upload_done(struct Curl_easy *data)
263 {
264   DEBUGASSERT(!data->req.upload_done);
265   data->req.upload_done = TRUE;
266   data->req.keepon &= ~(KEEP_SEND|KEEP_SEND_TIMED); /* we are done sending */
267 
268   Curl_pgrsTime(data, TIMER_POSTRANSFER);
269   Curl_creader_done(data, data->req.upload_aborted);
270 
271   if(data->req.upload_aborted) {
272     Curl_bufq_reset(&data->req.sendbuf);
273     if(data->req.writebytecount)
274       infof(data, "abort upload after having sent %" FMT_OFF_T " bytes",
275             data->req.writebytecount);
276     else
277       infof(data, "abort upload");
278   }
279   else if(data->req.writebytecount)
280     infof(data, "upload completely sent off: %" FMT_OFF_T " bytes",
281           data->req.writebytecount);
282   else if(!data->req.download_done) {
283     DEBUGASSERT(Curl_bufq_is_empty(&data->req.sendbuf));
284     infof(data, Curl_creader_total_length(data) ?
285           "We are completely uploaded and fine" :
286           "Request completely sent off");
287   }
288 
289   return Curl_xfer_send_close(data);
290 }
291 
req_flush(struct Curl_easy * data)292 static CURLcode req_flush(struct Curl_easy *data)
293 {
294   CURLcode result;
295 
296   if(!data || !data->conn)
297     return CURLE_FAILED_INIT;
298 
299   if(!Curl_bufq_is_empty(&data->req.sendbuf)) {
300     result = req_send_buffer_flush(data);
301     if(result)
302       return result;
303     if(!Curl_bufq_is_empty(&data->req.sendbuf)) {
304       DEBUGF(infof(data, "Curl_req_flush(len=%zu) -> EAGAIN",
305              Curl_bufq_len(&data->req.sendbuf)));
306       return CURLE_AGAIN;
307     }
308   }
309   else if(Curl_xfer_needs_flush(data)) {
310     DEBUGF(infof(data, "Curl_req_flush(), xfer send_pending"));
311     return Curl_xfer_flush(data);
312   }
313 
314   if(data->req.eos_read && !data->req.eos_sent) {
315     char tmp;
316     size_t nwritten;
317     result = xfer_send(data, &tmp, 0, 0, &nwritten);
318     if(result)
319       return result;
320     DEBUGASSERT(data->req.eos_sent);
321   }
322 
323   if(!data->req.upload_done && data->req.eos_read && data->req.eos_sent) {
324     DEBUGASSERT(Curl_bufq_is_empty(&data->req.sendbuf));
325     if(data->req.shutdown) {
326       bool done;
327       result = Curl_xfer_send_shutdown(data, &done);
328       if(result && data->req.shutdown_err_ignore) {
329         infof(data, "Shutdown send direction error: %d. Broken server? "
330               "Proceeding as if everything is ok.", result);
331         result = CURLE_OK;
332         done = TRUE;
333       }
334 
335       if(result)
336         return result;
337       if(!done)
338         return CURLE_AGAIN;
339     }
340     return req_set_upload_done(data);
341   }
342   return CURLE_OK;
343 }
344 
add_from_client(void * reader_ctx,unsigned char * buf,size_t buflen,CURLcode * err)345 static ssize_t add_from_client(void *reader_ctx,
346                                unsigned char *buf, size_t buflen,
347                                CURLcode *err)
348 {
349   struct Curl_easy *data = reader_ctx;
350   size_t nread;
351   bool eos;
352 
353   *err = Curl_client_read(data, (char *)buf, buflen, &nread, &eos);
354   if(*err)
355     return -1;
356   if(eos)
357     data->req.eos_read = TRUE;
358   return (ssize_t)nread;
359 }
360 
req_send_buffer_add(struct Curl_easy * data,const char * buf,size_t blen,size_t hds_len)361 static CURLcode req_send_buffer_add(struct Curl_easy *data,
362                                     const char *buf, size_t blen,
363                                     size_t hds_len)
364 {
365   CURLcode result = CURLE_OK;
366   ssize_t n;
367   n = Curl_bufq_write(&data->req.sendbuf,
368                       (const unsigned char *)buf, blen, &result);
369   if(n < 0)
370     return result;
371   /* We rely on a SOFTLIMIT on sendbuf, so it can take all data in */
372   DEBUGASSERT((size_t)n == blen);
373   data->req.sendbuf_hds_len += hds_len;
374   return CURLE_OK;
375 }
376 
Curl_req_send(struct Curl_easy * data,struct dynbuf * req,unsigned char httpversion)377 CURLcode Curl_req_send(struct Curl_easy *data, struct dynbuf *req,
378                        unsigned char httpversion)
379 {
380   CURLcode result;
381   const char *buf;
382   size_t blen, nwritten;
383 
384   if(!data || !data->conn)
385     return CURLE_FAILED_INIT;
386 
387   data->req.httpversion_sent = httpversion;
388   buf = Curl_dyn_ptr(req);
389   blen = Curl_dyn_len(req);
390   if(!Curl_creader_total_length(data)) {
391     /* Request without body. Try to send directly from the buf given. */
392     data->req.eos_read = TRUE;
393     result = xfer_send(data, buf, blen, blen, &nwritten);
394     if(result)
395       return result;
396     buf += nwritten;
397     blen -= nwritten;
398   }
399 
400   if(blen) {
401     /* Either we have a request body, or we could not send the complete
402      * request in one go. Buffer the remainder and try to add as much
403      * body bytes as room is left in the buffer. Then flush. */
404     result = req_send_buffer_add(data, buf, blen, blen);
405     if(result)
406       return result;
407 
408     return Curl_req_send_more(data);
409   }
410   return CURLE_OK;
411 }
412 
Curl_req_sendbuf_empty(struct Curl_easy * data)413 bool Curl_req_sendbuf_empty(struct Curl_easy *data)
414 {
415   return !data->req.sendbuf_init || Curl_bufq_is_empty(&data->req.sendbuf);
416 }
417 
Curl_req_want_send(struct Curl_easy * data)418 bool Curl_req_want_send(struct Curl_easy *data)
419 {
420   /* Not done and
421    * - KEEP_SEND and not PAUSEd.
422    * - or request has buffered data to send
423    * - or transfer connection has pending data to send */
424   return !data->req.done &&
425          (((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) ||
426            !Curl_req_sendbuf_empty(data) ||
427            Curl_xfer_needs_flush(data));
428 }
429 
Curl_req_done_sending(struct Curl_easy * data)430 bool Curl_req_done_sending(struct Curl_easy *data)
431 {
432   return data->req.upload_done && !Curl_req_want_send(data);
433 }
434 
Curl_req_send_more(struct Curl_easy * data)435 CURLcode Curl_req_send_more(struct Curl_easy *data)
436 {
437   CURLcode result;
438 
439   /* Fill our send buffer if more from client can be read. */
440   if(!data->req.upload_aborted &&
441      !data->req.eos_read &&
442      !(data->req.keepon & KEEP_SEND_PAUSE) &&
443      !Curl_bufq_is_full(&data->req.sendbuf)) {
444     ssize_t nread = Curl_bufq_sipn(&data->req.sendbuf, 0,
445                                    add_from_client, data, &result);
446     if(nread < 0 && result != CURLE_AGAIN)
447       return result;
448   }
449 
450   result = req_flush(data);
451   if(result == CURLE_AGAIN)
452     result = CURLE_OK;
453 
454   return result;
455 }
456 
Curl_req_abort_sending(struct Curl_easy * data)457 CURLcode Curl_req_abort_sending(struct Curl_easy *data)
458 {
459   if(!data->req.upload_done) {
460     Curl_bufq_reset(&data->req.sendbuf);
461     data->req.upload_aborted = TRUE;
462     /* no longer KEEP_SEND and KEEP_SEND_PAUSE */
463     data->req.keepon &= ~KEEP_SENDBITS;
464     return req_set_upload_done(data);
465   }
466   return CURLE_OK;
467 }
468 
Curl_req_stop_send_recv(struct Curl_easy * data)469 CURLcode Curl_req_stop_send_recv(struct Curl_easy *data)
470 {
471   /* stop receiving and ALL sending as well, including PAUSE and HOLD.
472    * We might still be paused on receive client writes though, so
473    * keep those bits around. */
474   data->req.keepon &= ~(KEEP_RECV|KEEP_SENDBITS);
475   return Curl_req_abort_sending(data);
476 }
477