VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/request.c@ 105284

Last change on this file since 105284 was 104204, checked in by vboxsync, 11 months ago

fixing export flags in libs

File size: 11.0 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <[email protected]>, 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
43CURLcode Curl_req_init(struct SingleRequest *req)
44{
45 memset(req, 0, sizeof(*req));
46 return CURLE_OK;
47}
48
49CURLcode Curl_req_soft_reset(struct SingleRequest *req,
50 struct Curl_easy *data)
51{
52 CURLcode result;
53
54 req->done = FALSE;
55 req->upload_done = FALSE;
56 req->download_done = FALSE;
57 req->ignorebody = FALSE;
58 req->bytecount = 0;
59 req->writebytecount = 0;
60 req->header = TRUE; /* assume header */
61 req->headerline = 0;
62 req->headerbytecount = 0;
63 req->allheadercount = 0;
64 req->deductheadercount = 0;
65
66 result = Curl_client_start(data);
67 if(result)
68 return result;
69
70 if(!req->sendbuf_init) {
71 Curl_bufq_init2(&req->sendbuf, data->set.upload_buffer_size, 1,
72 BUFQ_OPT_SOFT_LIMIT);
73 req->sendbuf_init = TRUE;
74 }
75 else {
76 Curl_bufq_reset(&req->sendbuf);
77 if(data->set.upload_buffer_size != req->sendbuf.chunk_size) {
78 Curl_bufq_free(&req->sendbuf);
79 Curl_bufq_init2(&req->sendbuf, data->set.upload_buffer_size, 1,
80 BUFQ_OPT_SOFT_LIMIT);
81 }
82 }
83
84 return CURLE_OK;
85}
86
87CURLcode Curl_req_start(struct SingleRequest *req,
88 struct Curl_easy *data)
89{
90 req->start = Curl_now();
91 return Curl_req_soft_reset(req, data);
92}
93
94static CURLcode req_flush(struct Curl_easy *data);
95
96CURLcode Curl_req_done(struct SingleRequest *req,
97 struct Curl_easy *data, bool aborted)
98{
99 (void)req;
100 if(!aborted)
101 (void)req_flush(data);
102 Curl_client_reset(data);
103 return CURLE_OK;
104}
105
106void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data)
107{
108 struct curltime t0 = {0, 0};
109
110 /* This is a bit ugly. `req->p` is a union and we assume we can
111 * free this safely without leaks. */
112 Curl_safefree(req->p.http);
113 Curl_safefree(req->newurl);
114 Curl_client_reset(data);
115 if(req->sendbuf_init)
116 Curl_bufq_reset(&req->sendbuf);
117
118#ifndef CURL_DISABLE_DOH
119 if(req->doh) {
120 Curl_close(&req->doh->probe[0].easy);
121 Curl_close(&req->doh->probe[1].easy);
122 }
123#endif
124 /* Can no longer memset() this struct as we need to keep some state */
125 req->size = -1;
126 req->maxdownload = -1;
127 req->bytecount = 0;
128 req->writebytecount = 0;
129 req->start = t0;
130 req->headerbytecount = 0;
131 req->allheadercount = 0;
132 req->deductheadercount = 0;
133 req->headerline = 0;
134 req->offset = 0;
135 req->httpcode = 0;
136 req->keepon = 0;
137 req->upgr101 = UPGR101_INIT;
138 req->timeofdoc = 0;
139 req->bodywrites = 0;
140 req->location = NULL;
141 req->newurl = NULL;
142#ifndef CURL_DISABLE_COOKIES
143 req->setcookies = 0;
144#endif
145 req->header = FALSE;
146 req->content_range = FALSE;
147 req->download_done = FALSE;
148 req->eos_written = FALSE;
149 req->eos_read = FALSE;
150 req->upload_done = FALSE;
151 req->upload_aborted = FALSE;
152 req->ignorebody = FALSE;
153 req->http_bodyless = FALSE;
154 req->chunk = FALSE;
155 req->ignore_cl = FALSE;
156 req->upload_chunky = FALSE;
157 req->getheader = FALSE;
158 req->no_body = data->set.opt_no_body;
159 req->authneg = FALSE;
160}
161
162void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data)
163{
164 /* This is a bit ugly. `req->p` is a union and we assume we can
165 * free this safely without leaks. */
166 Curl_safefree(req->p.http);
167 Curl_safefree(req->newurl);
168 if(req->sendbuf_init)
169 Curl_bufq_free(&req->sendbuf);
170 Curl_client_cleanup(data);
171
172#ifndef CURL_DISABLE_DOH
173 if(req->doh) {
174 Curl_close(&req->doh->probe[0].easy);
175 Curl_close(&req->doh->probe[1].easy);
176 Curl_dyn_free(&req->doh->probe[0].serverdoh);
177 Curl_dyn_free(&req->doh->probe[1].serverdoh);
178 curl_slist_free_all(req->doh->headers);
179 Curl_safefree(req->doh);
180 }
181#endif
182}
183
184static CURLcode xfer_send(struct Curl_easy *data,
185 const char *buf, size_t blen,
186 size_t hds_len, size_t *pnwritten)
187{
188 CURLcode result = CURLE_OK;
189
190 *pnwritten = 0;
191#ifdef CURLDEBUG
192 {
193 /* Allow debug builds to override this logic to force short initial
194 sends
195 */
196 char *p = getenv("CURL_SMALLREQSEND");
197 if(p) {
198 size_t altsize = (size_t)strtoul(p, NULL, 10);
199 if(altsize && altsize < blen)
200 blen = altsize;
201 }
202 }
203#endif
204 /* Make sure this doesn't send more body bytes than what the max send
205 speed says. The headers do not count to the max speed. */
206 if(data->set.max_send_speed) {
207 size_t body_bytes = blen - hds_len;
208 if((curl_off_t)body_bytes > data->set.max_send_speed)
209 blen = hds_len + (size_t)data->set.max_send_speed;
210 }
211
212 result = Curl_xfer_send(data, buf, blen, pnwritten);
213 if(!result && *pnwritten) {
214 if(hds_len)
215 Curl_debug(data, CURLINFO_HEADER_OUT, (char *)buf,
216 CURLMIN(hds_len, *pnwritten));
217 if(*pnwritten > hds_len) {
218 size_t body_len = *pnwritten - hds_len;
219 Curl_debug(data, CURLINFO_DATA_OUT, (char *)buf + hds_len, body_len);
220 data->req.writebytecount += body_len;
221 Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
222 }
223 }
224 return result;
225}
226
227static CURLcode req_send_buffer_flush(struct Curl_easy *data)
228{
229 CURLcode result = CURLE_OK;
230 const unsigned char *buf;
231 size_t blen;
232
233 while(Curl_bufq_peek(&data->req.sendbuf, &buf, &blen)) {
234 size_t nwritten, hds_len = CURLMIN(data->req.sendbuf_hds_len, blen);
235 result = xfer_send(data, (const char *)buf, blen, hds_len, &nwritten);
236 if(result)
237 break;
238
239 Curl_bufq_skip(&data->req.sendbuf, nwritten);
240 if(hds_len) {
241 data->req.sendbuf_hds_len -= CURLMIN(hds_len, nwritten);
242 }
243 /* leave if we could not send all. Maybe network blocking or
244 * speed limits on transfer */
245 if(nwritten < blen)
246 break;
247 }
248 return result;
249}
250
251static CURLcode req_set_upload_done(struct Curl_easy *data)
252{
253 DEBUGASSERT(!data->req.upload_done);
254 data->req.upload_done = TRUE;
255 data->req.keepon &= ~(KEEP_SEND|KEEP_SEND_TIMED); /* we're done sending */
256
257 Curl_creader_done(data, data->req.upload_aborted);
258
259 if(data->req.upload_aborted) {
260 if(data->req.writebytecount)
261 infof(data, "abort upload after having sent %" CURL_FORMAT_CURL_OFF_T
262 " bytes", data->req.writebytecount);
263 else
264 infof(data, "abort upload");
265 }
266 else if(data->req.writebytecount)
267 infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
268 " bytes", data->req.writebytecount);
269 else
270 infof(data, Curl_creader_total_length(data)?
271 "We are completely uploaded and fine" :
272 "Request completely sent off");
273
274 return Curl_xfer_send_close(data);
275}
276
277static CURLcode req_flush(struct Curl_easy *data)
278{
279 CURLcode result;
280
281 if(!data || !data->conn)
282 return CURLE_FAILED_INIT;
283
284 if(!Curl_bufq_is_empty(&data->req.sendbuf)) {
285 result = req_send_buffer_flush(data);
286 if(result)
287 return result;
288 if(!Curl_bufq_is_empty(&data->req.sendbuf)) {
289 return CURLE_AGAIN;
290 }
291 }
292
293 if(!data->req.upload_done && data->req.eos_read &&
294 Curl_bufq_is_empty(&data->req.sendbuf)) {
295 return req_set_upload_done(data);
296 }
297 return CURLE_OK;
298}
299
300static ssize_t add_from_client(void *reader_ctx,
301 unsigned char *buf, size_t buflen,
302 CURLcode *err)
303{
304 struct Curl_easy *data = reader_ctx;
305 size_t nread;
306 bool eos;
307
308 *err = Curl_client_read(data, (char *)buf, buflen, &nread, &eos);
309 if(*err)
310 return -1;
311 if(eos)
312 data->req.eos_read = TRUE;
313 return (ssize_t)nread;
314}
315
316#ifndef USE_HYPER
317
318static CURLcode req_send_buffer_add(struct Curl_easy *data,
319 const char *buf, size_t blen,
320 size_t hds_len)
321{
322 CURLcode result = CURLE_OK;
323 ssize_t n;
324 n = Curl_bufq_write(&data->req.sendbuf,
325 (const unsigned char *)buf, blen, &result);
326 if(n < 0)
327 return result;
328 /* We rely on a SOFTLIMIT on sendbuf, so it can take all data in */
329 DEBUGASSERT((size_t)n == blen);
330 data->req.sendbuf_hds_len += hds_len;
331 return CURLE_OK;
332}
333
334CURLcode Curl_req_send(struct Curl_easy *data, struct dynbuf *req)
335{
336 CURLcode result;
337 const char *buf;
338 size_t blen, nwritten;
339
340 if(!data || !data->conn)
341 return CURLE_FAILED_INIT;
342
343 buf = Curl_dyn_ptr(req);
344 blen = Curl_dyn_len(req);
345 if(!Curl_creader_total_length(data)) {
346 /* Request without body. Try to send directly from the buf given. */
347 data->req.eos_read = TRUE;
348 result = xfer_send(data, buf, blen, blen, &nwritten);
349 if(result)
350 return result;
351 buf += nwritten;
352 blen -= nwritten;
353 }
354
355 if(blen) {
356 /* Either we have a request body, or we could not send the complete
357 * request in one go. Buffer the remainder and try to add as much
358 * body bytes as room is left in the buffer. Then flush. */
359 result = req_send_buffer_add(data, buf, blen, blen);
360 if(result)
361 return result;
362
363 return Curl_req_send_more(data);
364 }
365 return CURLE_OK;
366}
367#endif /* !USE_HYPER */
368
369bool Curl_req_want_send(struct Curl_easy *data)
370{
371 return data->req.sendbuf_init && !Curl_bufq_is_empty(&data->req.sendbuf);
372}
373
374bool Curl_req_done_sending(struct Curl_easy *data)
375{
376 if(data->req.upload_done) {
377 DEBUGASSERT(Curl_bufq_is_empty(&data->req.sendbuf));
378 return TRUE;
379 }
380 return FALSE;
381}
382
383CURLcode Curl_req_send_more(struct Curl_easy *data)
384{
385 CURLcode result;
386
387 /* Fill our send buffer if more from client can be read. */
388 if(!data->req.eos_read && !Curl_bufq_is_full(&data->req.sendbuf)) {
389 ssize_t nread = Curl_bufq_sipn(&data->req.sendbuf, 0,
390 add_from_client, data, &result);
391 if(nread < 0 && result != CURLE_AGAIN)
392 return result;
393 }
394
395 result = req_flush(data);
396 if(result == CURLE_AGAIN)
397 result = CURLE_OK;
398 return result;
399}
400
401CURLcode Curl_req_abort_sending(struct Curl_easy *data)
402{
403 if(!data->req.upload_done) {
404 Curl_bufq_reset(&data->req.sendbuf);
405 data->req.upload_aborted = TRUE;
406 return req_set_upload_done(data);
407 }
408 return CURLE_OK;
409}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette