VirtualBox

source: vbox/trunk/src/libs/curl-8.11.1/lib/sendf.c@ 108333

最後變更 在這個檔案從108333是 108048,由 vboxsync 提交於 7 週 前

curl-8.11.1: Applied and adjusted our curl changes to 8.7.1. jiraref:VBP-1535

  • 屬性 svn:eol-style 設為 native
檔案大小: 38.2 KB
 
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#ifdef HAVE_NETINET_IN_H
28#include <netinet/in.h>
29#endif
30
31#ifdef HAVE_LINUX_TCP_H
32#include <linux/tcp.h>
33#elif defined(HAVE_NETINET_TCP_H)
34#include <netinet/tcp.h>
35#endif
36
37#include <curl/curl.h>
38
39#include "urldata.h"
40#include "sendf.h"
41#include "cfilters.h"
42#include "connect.h"
43#include "content_encoding.h"
44#include "cw-out.h"
45#include "vtls/vtls.h"
46#include "vssh/ssh.h"
47#include "easyif.h"
48#include "multiif.h"
49#include "strerror.h"
50#include "select.h"
51#include "strdup.h"
52#include "http2.h"
53#include "progress.h"
54#include "warnless.h"
55#include "ws.h"
56
57/* The last 3 #include files should be in this order */
58#include "curl_printf.h"
59#include "curl_memory.h"
60#include "memdebug.h"
61
62
63static CURLcode do_init_writer_stack(struct Curl_easy *data);
64
65/* Curl_client_write() sends data to the write callback(s)
66
67 The bit pattern defines to what "streams" to write to. Body and/or header.
68 The defines are in sendf.h of course.
69 */
70CURLcode Curl_client_write(struct Curl_easy *data,
71 int type, const char *buf, size_t blen)
72{
73 CURLcode result;
74
75 /* it is one of those, at least */
76 DEBUGASSERT(type & (CLIENTWRITE_BODY|CLIENTWRITE_HEADER|CLIENTWRITE_INFO));
77 /* BODY is only BODY (with optional EOS) */
78 DEBUGASSERT(!(type & CLIENTWRITE_BODY) ||
79 ((type & ~(CLIENTWRITE_BODY|CLIENTWRITE_EOS)) == 0));
80 /* INFO is only INFO (with optional EOS) */
81 DEBUGASSERT(!(type & CLIENTWRITE_INFO) ||
82 ((type & ~(CLIENTWRITE_INFO|CLIENTWRITE_EOS)) == 0));
83
84 if(!data->req.writer_stack) {
85 result = do_init_writer_stack(data);
86 if(result)
87 return result;
88 DEBUGASSERT(data->req.writer_stack);
89 }
90
91 result = Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
92 CURL_TRC_WRITE(data, "client_write(type=%x, len=%zu) -> %d",
93 type, blen, result);
94 return result;
95}
96
97static void cl_reset_writer(struct Curl_easy *data)
98{
99 struct Curl_cwriter *writer = data->req.writer_stack;
100 while(writer) {
101 data->req.writer_stack = writer->next;
102 writer->cwt->do_close(data, writer);
103 free(writer);
104 writer = data->req.writer_stack;
105 }
106}
107
108static void cl_reset_reader(struct Curl_easy *data)
109{
110 struct Curl_creader *reader = data->req.reader_stack;
111 while(reader) {
112 data->req.reader_stack = reader->next;
113 reader->crt->do_close(data, reader);
114 free(reader);
115 reader = data->req.reader_stack;
116 }
117}
118
119void Curl_client_cleanup(struct Curl_easy *data)
120{
121 cl_reset_reader(data);
122 cl_reset_writer(data);
123
124 data->req.bytecount = 0;
125 data->req.headerline = 0;
126}
127
128void Curl_client_reset(struct Curl_easy *data)
129{
130 if(data->req.rewind_read) {
131 /* already requested */
132 CURL_TRC_READ(data, "client_reset, will rewind reader");
133 }
134 else {
135 CURL_TRC_READ(data, "client_reset, clear readers");
136 cl_reset_reader(data);
137 }
138 cl_reset_writer(data);
139
140 data->req.bytecount = 0;
141 data->req.headerline = 0;
142}
143
144CURLcode Curl_client_start(struct Curl_easy *data)
145{
146 if(data->req.rewind_read) {
147 struct Curl_creader *r = data->req.reader_stack;
148 CURLcode result = CURLE_OK;
149
150 CURL_TRC_READ(data, "client start, rewind readers");
151 while(r) {
152 result = r->crt->rewind(data, r);
153 if(result) {
154 failf(data, "rewind of client reader '%s' failed: %d",
155 r->crt->name, result);
156 return result;
157 }
158 r = r->next;
159 }
160 data->req.rewind_read = FALSE;
161 cl_reset_reader(data);
162 }
163 return CURLE_OK;
164}
165
166bool Curl_creader_will_rewind(struct Curl_easy *data)
167{
168 return data->req.rewind_read;
169}
170
171void Curl_creader_set_rewind(struct Curl_easy *data, bool enable)
172{
173 data->req.rewind_read = !!enable;
174}
175
176/* Write data using an unencoding writer stack. */
177CURLcode Curl_cwriter_write(struct Curl_easy *data,
178 struct Curl_cwriter *writer, int type,
179 const char *buf, size_t nbytes)
180{
181 if(!writer)
182 return CURLE_WRITE_ERROR;
183 return writer->cwt->do_write(data, writer, type, buf, nbytes);
184}
185
186CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
187 struct Curl_cwriter *writer)
188{
189 (void)data;
190 (void)writer;
191 return CURLE_OK;
192}
193
194CURLcode Curl_cwriter_def_write(struct Curl_easy *data,
195 struct Curl_cwriter *writer, int type,
196 const char *buf, size_t nbytes)
197{
198 return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
199}
200
201void Curl_cwriter_def_close(struct Curl_easy *data,
202 struct Curl_cwriter *writer)
203{
204 (void) data;
205 (void) writer;
206}
207
208static size_t get_max_body_write_len(struct Curl_easy *data, curl_off_t limit)
209{
210 if(limit != -1) {
211 /* How much more are we allowed to write? */
212 curl_off_t remain_diff;
213 remain_diff = limit - data->req.bytecount;
214 if(remain_diff < 0) {
215 /* already written too much! */
216 return 0;
217 }
218#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
219 else if(remain_diff > SSIZE_T_MAX) {
220 return SIZE_T_MAX;
221 }
222#endif
223 else {
224 return (size_t)remain_diff;
225 }
226 }
227 return SIZE_T_MAX;
228}
229
230struct cw_download_ctx {
231 struct Curl_cwriter super;
232 BIT(started_response);
233};
234/* Download client writer in phase CURL_CW_PROTOCOL that
235 * sees the "real" download body data. */
236static CURLcode cw_download_write(struct Curl_easy *data,
237 struct Curl_cwriter *writer, int type,
238 const char *buf, size_t nbytes)
239{
240 struct cw_download_ctx *ctx = writer->ctx;
241 CURLcode result;
242 size_t nwrite, excess_len = 0;
243 bool is_connect = !!(type & CLIENTWRITE_CONNECT);
244
245 if(!is_connect && !ctx->started_response) {
246 Curl_pgrsTime(data, TIMER_STARTTRANSFER);
247 ctx->started_response = TRUE;
248 }
249
250 if(!(type & CLIENTWRITE_BODY)) {
251 if(is_connect && data->set.suppress_connect_headers)
252 return CURLE_OK;
253 result = Curl_cwriter_write(data, writer->next, type, buf, nbytes);
254 CURL_TRC_WRITE(data, "download_write header(type=%x, blen=%zu) -> %d",
255 type, nbytes, result);
256 return result;
257 }
258
259 /* Here, we deal with REAL BODY bytes. All filtering and transfer
260 * encodings have been applied and only the true content, e.g. BODY,
261 * bytes are passed here.
262 * This allows us to check sizes, update stats, etc. independent
263 * from the protocol in play. */
264
265 if(data->req.no_body && nbytes > 0) {
266 /* BODY arrives although we want none, bail out */
267 streamclose(data->conn, "ignoring body");
268 CURL_TRC_WRITE(data, "download_write body(type=%x, blen=%zu), "
269 "did not want a BODY", type, nbytes);
270 data->req.download_done = TRUE;
271 if(data->info.header_size)
272 /* if headers have been received, this is fine */
273 return CURLE_OK;
274 return CURLE_WEIRD_SERVER_REPLY;
275 }
276
277 /* Determine if we see any bytes in excess to what is allowed.
278 * We write the allowed bytes and handle excess further below.
279 * This gives deterministic BODY writes on varying buffer receive
280 * lengths. */
281 nwrite = nbytes;
282 if(-1 != data->req.maxdownload) {
283 size_t wmax = get_max_body_write_len(data, data->req.maxdownload);
284 if(nwrite > wmax) {
285 excess_len = nbytes - wmax;
286 nwrite = wmax;
287 }
288
289 if(nwrite == wmax) {
290 data->req.download_done = TRUE;
291 }
292
293 if((type & CLIENTWRITE_EOS) && !data->req.no_body &&
294 (data->req.maxdownload > data->req.bytecount)) {
295 failf(data, "end of response with %" FMT_OFF_T " bytes missing",
296 data->req.maxdownload - data->req.bytecount);
297 return CURLE_PARTIAL_FILE;
298 }
299 }
300
301 /* Error on too large filesize is handled below, after writing
302 * the permitted bytes */
303 if(data->set.max_filesize && !data->req.ignorebody) {
304 size_t wmax = get_max_body_write_len(data, data->set.max_filesize);
305 if(nwrite > wmax) {
306 nwrite = wmax;
307 }
308 }
309
310 if(!data->req.ignorebody && (nwrite || (type & CLIENTWRITE_EOS))) {
311 result = Curl_cwriter_write(data, writer->next, type, buf, nwrite);
312 CURL_TRC_WRITE(data, "download_write body(type=%x, blen=%zu) -> %d",
313 type, nbytes, result);
314 if(result)
315 return result;
316 }
317 /* Update stats, write and report progress */
318 data->req.bytecount += nwrite;
319#ifdef USE_HYPER
320 data->req.bodywritten = TRUE;
321#endif
322 result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
323 if(result)
324 return result;
325
326 if(excess_len) {
327 if(!data->req.ignorebody) {
328 infof(data,
329 "Excess found writing body:"
330 " excess = %zu"
331 ", size = %" FMT_OFF_T
332 ", maxdownload = %" FMT_OFF_T
333 ", bytecount = %" FMT_OFF_T,
334 excess_len, data->req.size, data->req.maxdownload,
335 data->req.bytecount);
336 connclose(data->conn, "excess found in a read");
337 }
338 }
339 else if((nwrite < nbytes) && !data->req.ignorebody) {
340 failf(data, "Exceeded the maximum allowed file size "
341 "(%" FMT_OFF_T ") with %" FMT_OFF_T " bytes",
342 data->set.max_filesize, data->req.bytecount);
343 return CURLE_FILESIZE_EXCEEDED;
344 }
345
346 return CURLE_OK;
347}
348
349static const struct Curl_cwtype cw_download = {
350 "protocol",
351 NULL,
352 Curl_cwriter_def_init,
353 cw_download_write,
354 Curl_cwriter_def_close,
355 sizeof(struct cw_download_ctx)
356};
357
358/* RAW client writer in phase CURL_CW_RAW that
359 * enabled tracing of raw data. */
360static CURLcode cw_raw_write(struct Curl_easy *data,
361 struct Curl_cwriter *writer, int type,
362 const char *buf, size_t nbytes)
363{
364 if(type & CLIENTWRITE_BODY && data->set.verbose && !data->req.ignorebody) {
365 Curl_debug(data, CURLINFO_DATA_IN, (char *)buf, nbytes);
366 }
367 return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
368}
369
370static const struct Curl_cwtype cw_raw = {
371 "raw",
372 NULL,
373 Curl_cwriter_def_init,
374 cw_raw_write,
375 Curl_cwriter_def_close,
376 sizeof(struct Curl_cwriter)
377};
378
379/* Create an unencoding writer stage using the given handler. */
380CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
381 struct Curl_easy *data,
382 const struct Curl_cwtype *cwt,
383 Curl_cwriter_phase phase)
384{
385 struct Curl_cwriter *writer = NULL;
386 CURLcode result = CURLE_OUT_OF_MEMORY;
387 void *p;
388
389 DEBUGASSERT(cwt->cwriter_size >= sizeof(struct Curl_cwriter));
390 p = calloc(1, cwt->cwriter_size);
391 if(!p)
392 goto out;
393
394 writer = (struct Curl_cwriter *)p;
395 writer->cwt = cwt;
396 writer->ctx = p;
397 writer->phase = phase;
398 result = cwt->do_init(data, writer);
399
400out:
401 *pwriter = result ? NULL : writer;
402 if(result)
403 free(writer);
404 return result;
405}
406
407void Curl_cwriter_free(struct Curl_easy *data,
408 struct Curl_cwriter *writer)
409{
410 if(writer) {
411 writer->cwt->do_close(data, writer);
412 free(writer);
413 }
414}
415
416size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase)
417{
418 struct Curl_cwriter *w;
419 size_t n = 0;
420
421 for(w = data->req.writer_stack; w; w = w->next) {
422 if(w->phase == phase)
423 ++n;
424 }
425 return n;
426}
427
428static CURLcode do_init_writer_stack(struct Curl_easy *data)
429{
430 struct Curl_cwriter *writer;
431 CURLcode result;
432
433 DEBUGASSERT(!data->req.writer_stack);
434 result = Curl_cwriter_create(&data->req.writer_stack,
435 data, &Curl_cwt_out, CURL_CW_CLIENT);
436 if(result)
437 return result;
438
439 result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
440 if(result)
441 return result;
442 result = Curl_cwriter_add(data, writer);
443 if(result) {
444 Curl_cwriter_free(data, writer);
445 }
446
447 result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
448 if(result)
449 return result;
450 result = Curl_cwriter_add(data, writer);
451 if(result) {
452 Curl_cwriter_free(data, writer);
453 }
454 return result;
455}
456
457CURLcode Curl_cwriter_add(struct Curl_easy *data,
458 struct Curl_cwriter *writer)
459{
460 CURLcode result;
461 struct Curl_cwriter **anchor = &data->req.writer_stack;
462
463 if(!*anchor) {
464 result = do_init_writer_stack(data);
465 if(result)
466 return result;
467 }
468
469 /* Insert the writer as first in its phase.
470 * Skip existing writers of lower phases. */
471 while(*anchor && (*anchor)->phase < writer->phase)
472 anchor = &((*anchor)->next);
473 writer->next = *anchor;
474 *anchor = writer;
475 return CURLE_OK;
476}
477
478struct Curl_cwriter *Curl_cwriter_get_by_name(struct Curl_easy *data,
479 const char *name)
480{
481 struct Curl_cwriter *writer;
482 for(writer = data->req.writer_stack; writer; writer = writer->next) {
483 if(!strcmp(name, writer->cwt->name))
484 return writer;
485 }
486 return NULL;
487}
488
489struct Curl_cwriter *Curl_cwriter_get_by_type(struct Curl_easy *data,
490 const struct Curl_cwtype *cwt)
491{
492 struct Curl_cwriter *writer;
493 for(writer = data->req.writer_stack; writer; writer = writer->next) {
494 if(writer->cwt == cwt)
495 return writer;
496 }
497 return NULL;
498}
499
500void Curl_cwriter_remove_by_name(struct Curl_easy *data,
501 const char *name)
502{
503 struct Curl_cwriter **anchor = &data->req.writer_stack;
504
505 while(*anchor) {
506 if(!strcmp(name, (*anchor)->cwt->name)) {
507 struct Curl_cwriter *w = (*anchor);
508 *anchor = w->next;
509 Curl_cwriter_free(data, w);
510 continue;
511 }
512 anchor = &((*anchor)->next);
513 }
514}
515
516bool Curl_cwriter_is_paused(struct Curl_easy *data)
517{
518 return Curl_cw_out_is_paused(data);
519}
520
521CURLcode Curl_cwriter_unpause(struct Curl_easy *data)
522{
523 return Curl_cw_out_unpause(data);
524}
525
526CURLcode Curl_creader_read(struct Curl_easy *data,
527 struct Curl_creader *reader,
528 char *buf, size_t blen, size_t *nread, bool *eos)
529{
530 *nread = 0;
531 *eos = FALSE;
532 if(!reader)
533 return CURLE_READ_ERROR;
534 return reader->crt->do_read(data, reader, buf, blen, nread, eos);
535}
536
537CURLcode Curl_creader_def_init(struct Curl_easy *data,
538 struct Curl_creader *reader)
539{
540 (void)data;
541 (void)reader;
542 return CURLE_OK;
543}
544
545void Curl_creader_def_close(struct Curl_easy *data,
546 struct Curl_creader *reader)
547{
548 (void)data;
549 (void)reader;
550}
551
552CURLcode Curl_creader_def_read(struct Curl_easy *data,
553 struct Curl_creader *reader,
554 char *buf, size_t blen,
555 size_t *nread, bool *eos)
556{
557 if(reader->next)
558 return reader->next->crt->do_read(data, reader->next, buf, blen,
559 nread, eos);
560 else {
561 *nread = 0;
562 *eos = FALSE;
563 return CURLE_READ_ERROR;
564 }
565}
566
567bool Curl_creader_def_needs_rewind(struct Curl_easy *data,
568 struct Curl_creader *reader)
569{
570 (void)data;
571 (void)reader;
572 return FALSE;
573}
574
575curl_off_t Curl_creader_def_total_length(struct Curl_easy *data,
576 struct Curl_creader *reader)
577{
578 return reader->next ?
579 reader->next->crt->total_length(data, reader->next) : -1;
580}
581
582CURLcode Curl_creader_def_resume_from(struct Curl_easy *data,
583 struct Curl_creader *reader,
584 curl_off_t offset)
585{
586 (void)data;
587 (void)reader;
588 (void)offset;
589 return CURLE_READ_ERROR;
590}
591
592CURLcode Curl_creader_def_rewind(struct Curl_easy *data,
593 struct Curl_creader *reader)
594{
595 (void)data;
596 (void)reader;
597 return CURLE_OK;
598}
599
600CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
601 struct Curl_creader *reader)
602{
603 (void)data;
604 (void)reader;
605 return CURLE_OK;
606}
607
608bool Curl_creader_def_is_paused(struct Curl_easy *data,
609 struct Curl_creader *reader)
610{
611 (void)data;
612 (void)reader;
613 return FALSE;
614}
615
616void Curl_creader_def_done(struct Curl_easy *data,
617 struct Curl_creader *reader, int premature)
618{
619 (void)data;
620 (void)reader;
621 (void)premature;
622}
623
624struct cr_in_ctx {
625 struct Curl_creader super;
626 curl_read_callback read_cb;
627 void *cb_user_data;
628 curl_off_t total_len;
629 curl_off_t read_len;
630 CURLcode error_result;
631 BIT(seen_eos);
632 BIT(errored);
633 BIT(has_used_cb);
634 BIT(is_paused);
635};
636
637static CURLcode cr_in_init(struct Curl_easy *data, struct Curl_creader *reader)
638{
639 struct cr_in_ctx *ctx = reader->ctx;
640 (void)data;
641 ctx->read_cb = data->state.fread_func;
642 ctx->cb_user_data = data->state.in;
643 ctx->total_len = -1;
644 ctx->read_len = 0;
645 return CURLE_OK;
646}
647
648/* Real client reader to installed client callbacks. */
649static CURLcode cr_in_read(struct Curl_easy *data,
650 struct Curl_creader *reader,
651 char *buf, size_t blen,
652 size_t *pnread, bool *peos)
653{
654 struct cr_in_ctx *ctx = reader->ctx;
655 size_t nread;
656
657 ctx->is_paused = FALSE;
658
659 /* Once we have errored, we will return the same error forever */
660 if(ctx->errored) {
661 *pnread = 0;
662 *peos = FALSE;
663 return ctx->error_result;
664 }
665 if(ctx->seen_eos) {
666 *pnread = 0;
667 *peos = TRUE;
668 return CURLE_OK;
669 }
670 /* respect length limitations */
671 if(ctx->total_len >= 0) {
672 curl_off_t remain = ctx->total_len - ctx->read_len;
673 if(remain <= 0)
674 blen = 0;
675 else if(remain < (curl_off_t)blen)
676 blen = (size_t)remain;
677 }
678 nread = 0;
679 if(ctx->read_cb && blen) {
680 Curl_set_in_callback(data, TRUE);
681 nread = ctx->read_cb(buf, 1, blen, ctx->cb_user_data);
682 Curl_set_in_callback(data, FALSE);
683 ctx->has_used_cb = TRUE;
684 }
685
686 switch(nread) {
687 case 0:
688 if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
689 failf(data, "client read function EOF fail, "
690 "only %"FMT_OFF_T"/%"FMT_OFF_T " of needed bytes read",
691 ctx->read_len, ctx->total_len);
692 return CURLE_READ_ERROR;
693 }
694 *pnread = 0;
695 *peos = TRUE;
696 ctx->seen_eos = TRUE;
697 break;
698
699 case CURL_READFUNC_ABORT:
700 failf(data, "operation aborted by callback");
701 *pnread = 0;
702 *peos = FALSE;
703 ctx->errored = TRUE;
704 ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
705 return CURLE_ABORTED_BY_CALLBACK;
706
707 case CURL_READFUNC_PAUSE:
708 if(data->conn->handler->flags & PROTOPT_NONETWORK) {
709 /* protocols that work without network cannot be paused. This is
710 actually only FILE:// just now, and it cannot pause since the transfer
711 is not done using the "normal" procedure. */
712 failf(data, "Read callback asked for PAUSE when not supported");
713 return CURLE_READ_ERROR;
714 }
715 /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
716 CURL_TRC_READ(data, "cr_in_read, callback returned CURL_READFUNC_PAUSE");
717 ctx->is_paused = TRUE;
718 data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
719 *pnread = 0;
720 *peos = FALSE;
721 break; /* nothing was read */
722
723 default:
724 if(nread > blen) {
725 /* the read function returned a too large value */
726 failf(data, "read function returned funny value");
727 *pnread = 0;
728 *peos = FALSE;
729 ctx->errored = TRUE;
730 ctx->error_result = CURLE_READ_ERROR;
731 return CURLE_READ_ERROR;
732 }
733 ctx->read_len += nread;
734 if(ctx->total_len >= 0)
735 ctx->seen_eos = (ctx->read_len >= ctx->total_len);
736 *pnread = nread;
737 *peos = ctx->seen_eos;
738 break;
739 }
740 CURL_TRC_READ(data, "cr_in_read(len=%zu, total=%"FMT_OFF_T
741 ", read=%"FMT_OFF_T") -> %d, nread=%zu, eos=%d",
742 blen, ctx->total_len, ctx->read_len, CURLE_OK,
743 *pnread, *peos);
744 return CURLE_OK;
745}
746
747static bool cr_in_needs_rewind(struct Curl_easy *data,
748 struct Curl_creader *reader)
749{
750 struct cr_in_ctx *ctx = reader->ctx;
751 (void)data;
752 return ctx->has_used_cb;
753}
754
755static curl_off_t cr_in_total_length(struct Curl_easy *data,
756 struct Curl_creader *reader)
757{
758 struct cr_in_ctx *ctx = reader->ctx;
759 (void)data;
760 return ctx->total_len;
761}
762
763static CURLcode cr_in_resume_from(struct Curl_easy *data,
764 struct Curl_creader *reader,
765 curl_off_t offset)
766{
767 struct cr_in_ctx *ctx = reader->ctx;
768 int seekerr = CURL_SEEKFUNC_CANTSEEK;
769
770 DEBUGASSERT(data->conn);
771 /* already started reading? */
772 if(ctx->read_len)
773 return CURLE_READ_ERROR;
774
775 if(data->set.seek_func) {
776 Curl_set_in_callback(data, TRUE);
777 seekerr = data->set.seek_func(data->set.seek_client, offset, SEEK_SET);
778 Curl_set_in_callback(data, FALSE);
779 }
780
781 if(seekerr != CURL_SEEKFUNC_OK) {
782 curl_off_t passed = 0;
783
784 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
785 failf(data, "Could not seek stream");
786 return CURLE_READ_ERROR;
787 }
788 /* when seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
789 do {
790 char scratch[4*1024];
791 size_t readthisamountnow =
792 (offset - passed > (curl_off_t)sizeof(scratch)) ?
793 sizeof(scratch) :
794 curlx_sotouz(offset - passed);
795 size_t actuallyread;
796
797 Curl_set_in_callback(data, TRUE);
798 actuallyread = ctx->read_cb(scratch, 1, readthisamountnow,
799 ctx->cb_user_data);
800 Curl_set_in_callback(data, FALSE);
801
802 passed += actuallyread;
803 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
804 /* this checks for greater-than only to make sure that the
805 CURL_READFUNC_ABORT return code still aborts */
806 failf(data, "Could only read %" FMT_OFF_T " bytes from the input",
807 passed);
808 return CURLE_READ_ERROR;
809 }
810 } while(passed < offset);
811 }
812
813 /* now, decrease the size of the read */
814 if(ctx->total_len > 0) {
815 ctx->total_len -= offset;
816
817 if(ctx->total_len <= 0) {
818 failf(data, "File already completely uploaded");
819 return CURLE_PARTIAL_FILE;
820 }
821 }
822 /* we have passed, proceed as normal */
823 return CURLE_OK;
824}
825
826static CURLcode cr_in_rewind(struct Curl_easy *data,
827 struct Curl_creader *reader)
828{
829 struct cr_in_ctx *ctx = reader->ctx;
830
831 /* If we never invoked the callback, there is noting to rewind */
832 if(!ctx->has_used_cb)
833 return CURLE_OK;
834
835 if(data->set.seek_func) {
836 int err;
837
838 Curl_set_in_callback(data, TRUE);
839 err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
840 Curl_set_in_callback(data, FALSE);
841 CURL_TRC_READ(data, "cr_in, rewind via set.seek_func -> %d", err);
842 if(err) {
843 failf(data, "seek callback returned error %d", (int)err);
844 return CURLE_SEND_FAIL_REWIND;
845 }
846 }
847 else if(data->set.ioctl_func) {
848 curlioerr err;
849
850 Curl_set_in_callback(data, TRUE);
851 err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
852 data->set.ioctl_client);
853 Curl_set_in_callback(data, FALSE);
854 CURL_TRC_READ(data, "cr_in, rewind via set.ioctl_func -> %d", (int)err);
855 if(err) {
856 failf(data, "ioctl callback returned error %d", (int)err);
857 return CURLE_SEND_FAIL_REWIND;
858 }
859 }
860 else {
861 /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
862 given FILE * stream and we can actually attempt to rewind that
863 ourselves with fseek() */
864 if(data->state.fread_func == (curl_read_callback)fread) {
865 int err = fseek(data->state.in, 0, SEEK_SET);
866 CURL_TRC_READ(data, "cr_in, rewind via fseek -> %d(%d)",
867 (int)err, (int)errno);
868 if(-1 != err)
869 /* successful rewind */
870 return CURLE_OK;
871 }
872
873 /* no callback set or failure above, makes us fail at once */
874 failf(data, "necessary data rewind was not possible");
875 return CURLE_SEND_FAIL_REWIND;
876 }
877 return CURLE_OK;
878}
879
880static CURLcode cr_in_unpause(struct Curl_easy *data,
881 struct Curl_creader *reader)
882{
883 struct cr_in_ctx *ctx = reader->ctx;
884 (void)data;
885 ctx->is_paused = FALSE;
886 return CURLE_OK;
887}
888
889static bool cr_in_is_paused(struct Curl_easy *data,
890 struct Curl_creader *reader)
891{
892 struct cr_in_ctx *ctx = reader->ctx;
893 (void)data;
894 return ctx->is_paused;
895}
896
897static const struct Curl_crtype cr_in = {
898 "cr-in",
899 cr_in_init,
900 cr_in_read,
901 Curl_creader_def_close,
902 cr_in_needs_rewind,
903 cr_in_total_length,
904 cr_in_resume_from,
905 cr_in_rewind,
906 cr_in_unpause,
907 cr_in_is_paused,
908 Curl_creader_def_done,
909 sizeof(struct cr_in_ctx)
910};
911
912CURLcode Curl_creader_create(struct Curl_creader **preader,
913 struct Curl_easy *data,
914 const struct Curl_crtype *crt,
915 Curl_creader_phase phase)
916{
917 struct Curl_creader *reader = NULL;
918 CURLcode result = CURLE_OUT_OF_MEMORY;
919 void *p;
920
921 DEBUGASSERT(crt->creader_size >= sizeof(struct Curl_creader));
922 p = calloc(1, crt->creader_size);
923 if(!p)
924 goto out;
925
926 reader = (struct Curl_creader *)p;
927 reader->crt = crt;
928 reader->ctx = p;
929 reader->phase = phase;
930 result = crt->do_init(data, reader);
931
932out:
933 *preader = result ? NULL : reader;
934 if(result)
935 free(reader);
936 return result;
937}
938
939void Curl_creader_free(struct Curl_easy *data, struct Curl_creader *reader)
940{
941 if(reader) {
942 reader->crt->do_close(data, reader);
943 free(reader);
944 }
945}
946
947struct cr_lc_ctx {
948 struct Curl_creader super;
949 struct bufq buf;
950 BIT(read_eos); /* we read an EOS from the next reader */
951 BIT(eos); /* we have returned an EOS */
952 BIT(prev_cr); /* the last byte was a CR */
953};
954
955static CURLcode cr_lc_init(struct Curl_easy *data, struct Curl_creader *reader)
956{
957 struct cr_lc_ctx *ctx = reader->ctx;
958 (void)data;
959 Curl_bufq_init2(&ctx->buf, (16 * 1024), 1, BUFQ_OPT_SOFT_LIMIT);
960 return CURLE_OK;
961}
962
963static void cr_lc_close(struct Curl_easy *data, struct Curl_creader *reader)
964{
965 struct cr_lc_ctx *ctx = reader->ctx;
966 (void)data;
967 Curl_bufq_free(&ctx->buf);
968}
969
970/* client reader doing line end conversions. */
971static CURLcode cr_lc_read(struct Curl_easy *data,
972 struct Curl_creader *reader,
973 char *buf, size_t blen,
974 size_t *pnread, bool *peos)
975{
976 struct cr_lc_ctx *ctx = reader->ctx;
977 CURLcode result;
978 size_t nread, i, start, n;
979 bool eos;
980
981 if(ctx->eos) {
982 *pnread = 0;
983 *peos = TRUE;
984 return CURLE_OK;
985 }
986
987 if(Curl_bufq_is_empty(&ctx->buf)) {
988 if(ctx->read_eos) {
989 ctx->eos = TRUE;
990 *pnread = 0;
991 *peos = TRUE;
992 return CURLE_OK;
993 }
994 /* Still getting data form the next reader, ctx->buf is empty */
995 result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);
996 if(result)
997 return result;
998 ctx->read_eos = eos;
999
1000 if(!nread || !memchr(buf, '\n', nread)) {
1001 /* nothing to convert, return this right away */
1002 if(ctx->read_eos)
1003 ctx->eos = TRUE;
1004 *pnread = nread;
1005 *peos = ctx->eos;
1006 goto out;
1007 }
1008
1009 /* at least one \n might need conversion to '\r\n', place into ctx->buf */
1010 for(i = start = 0; i < nread; ++i) {
1011 /* if this byte is not an LF character, or if the preceding character is
1012 a CR (meaning this already is a CRLF pair), go to next */
1013 if((buf[i] != '\n') || ctx->prev_cr) {
1014 ctx->prev_cr = (buf[i] == '\r');
1015 continue;
1016 }
1017 ctx->prev_cr = FALSE;
1018 /* on a soft limit bufq, we do not need to check length */
1019 result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
1020 if(!result)
1021 result = Curl_bufq_cwrite(&ctx->buf, STRCONST("\r\n"), &n);
1022 if(result)
1023 return result;
1024 start = i + 1;
1025 if(!data->set.crlf && (data->state.infilesize != -1)) {
1026 /* we are here only because FTP is in ASCII mode...
1027 bump infilesize for the LF we just added */
1028 data->state.infilesize++;
1029 /* comment: this might work for FTP, but in HTTP we could not change
1030 * the content length after having started the request... */
1031 }
1032 }
1033
1034 if(start < i) { /* leftover */
1035 result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
1036 if(result)
1037 return result;
1038 }
1039 }
1040
1041 DEBUGASSERT(!Curl_bufq_is_empty(&ctx->buf));
1042 *peos = FALSE;
1043 result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
1044 if(!result && ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
1045 /* no more data, read all, done. */
1046 ctx->eos = TRUE;
1047 *peos = TRUE;
1048 }
1049
1050out:
1051 CURL_TRC_READ(data, "cr_lc_read(len=%zu) -> %d, nread=%zu, eos=%d",
1052 blen, result, *pnread, *peos);
1053 return result;
1054}
1055
1056static curl_off_t cr_lc_total_length(struct Curl_easy *data,
1057 struct Curl_creader *reader)
1058{
1059 /* this reader changes length depending on input */
1060 (void)data;
1061 (void)reader;
1062 return -1;
1063}
1064
1065static const struct Curl_crtype cr_lc = {
1066 "cr-lineconv",
1067 cr_lc_init,
1068 cr_lc_read,
1069 cr_lc_close,
1070 Curl_creader_def_needs_rewind,
1071 cr_lc_total_length,
1072 Curl_creader_def_resume_from,
1073 Curl_creader_def_rewind,
1074 Curl_creader_def_unpause,
1075 Curl_creader_def_is_paused,
1076 Curl_creader_def_done,
1077 sizeof(struct cr_lc_ctx)
1078};
1079
1080static CURLcode cr_lc_add(struct Curl_easy *data)
1081{
1082 struct Curl_creader *reader = NULL;
1083 CURLcode result;
1084
1085 result = Curl_creader_create(&reader, data, &cr_lc,
1086 CURL_CR_CONTENT_ENCODE);
1087 if(!result)
1088 result = Curl_creader_add(data, reader);
1089
1090 if(result && reader)
1091 Curl_creader_free(data, reader);
1092 return result;
1093}
1094
1095static CURLcode do_init_reader_stack(struct Curl_easy *data,
1096 struct Curl_creader *r)
1097{
1098 CURLcode result = CURLE_OK;
1099 curl_off_t clen;
1100
1101 DEBUGASSERT(r);
1102 DEBUGASSERT(r->crt);
1103 DEBUGASSERT(r->phase == CURL_CR_CLIENT);
1104 DEBUGASSERT(!data->req.reader_stack);
1105
1106 data->req.reader_stack = r;
1107 clen = r->crt->total_length(data, r);
1108 /* if we do not have 0 length init, and crlf conversion is wanted,
1109 * add the reader for it */
1110 if(clen && (data->set.crlf
1111#ifdef CURL_PREFER_LF_LINEENDS
1112 || data->state.prefer_ascii
1113#endif
1114 )) {
1115 result = cr_lc_add(data);
1116 if(result)
1117 return result;
1118 }
1119
1120 return result;
1121}
1122
1123CURLcode Curl_creader_set_fread(struct Curl_easy *data, curl_off_t len)
1124{
1125 CURLcode result;
1126 struct Curl_creader *r;
1127 struct cr_in_ctx *ctx;
1128
1129 result = Curl_creader_create(&r, data, &cr_in, CURL_CR_CLIENT);
1130 if(result)
1131 goto out;
1132 ctx = r->ctx;
1133 ctx->total_len = len;
1134
1135 cl_reset_reader(data);
1136 result = do_init_reader_stack(data, r);
1137out:
1138 CURL_TRC_READ(data, "add fread reader, len=%"FMT_OFF_T " -> %d",
1139 len, result);
1140 return result;
1141}
1142
1143CURLcode Curl_creader_add(struct Curl_easy *data,
1144 struct Curl_creader *reader)
1145{
1146 CURLcode result;
1147 struct Curl_creader **anchor = &data->req.reader_stack;
1148
1149 if(!*anchor) {
1150 result = Curl_creader_set_fread(data, data->state.infilesize);
1151 if(result)
1152 return result;
1153 }
1154
1155 /* Insert the writer as first in its phase.
1156 * Skip existing readers of lower phases. */
1157 while(*anchor && (*anchor)->phase < reader->phase)
1158 anchor = &((*anchor)->next);
1159 reader->next = *anchor;
1160 *anchor = reader;
1161 return CURLE_OK;
1162}
1163
1164CURLcode Curl_creader_set(struct Curl_easy *data, struct Curl_creader *r)
1165{
1166 CURLcode result;
1167
1168 DEBUGASSERT(r);
1169 DEBUGASSERT(r->crt);
1170 DEBUGASSERT(r->phase == CURL_CR_CLIENT);
1171
1172 cl_reset_reader(data);
1173 result = do_init_reader_stack(data, r);
1174 if(result)
1175 Curl_creader_free(data, r);
1176 return result;
1177}
1178
1179CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
1180 size_t *nread, bool *eos)
1181{
1182 CURLcode result;
1183
1184 DEBUGASSERT(buf);
1185 DEBUGASSERT(blen);
1186 DEBUGASSERT(nread);
1187 DEBUGASSERT(eos);
1188
1189 if(!data->req.reader_stack) {
1190 result = Curl_creader_set_fread(data, data->state.infilesize);
1191 if(result)
1192 return result;
1193 DEBUGASSERT(data->req.reader_stack);
1194 }
1195
1196 result = Curl_creader_read(data, data->req.reader_stack, buf, blen,
1197 nread, eos);
1198 CURL_TRC_READ(data, "client_read(len=%zu) -> %d, nread=%zu, eos=%d",
1199 blen, result, *nread, *eos);
1200 return result;
1201}
1202
1203bool Curl_creader_needs_rewind(struct Curl_easy *data)
1204{
1205 struct Curl_creader *reader = data->req.reader_stack;
1206 while(reader) {
1207 if(reader->crt->needs_rewind(data, reader)) {
1208 CURL_TRC_READ(data, "client reader needs rewind before next request");
1209 return TRUE;
1210 }
1211 reader = reader->next;
1212 }
1213 return FALSE;
1214}
1215
1216static CURLcode cr_null_read(struct Curl_easy *data,
1217 struct Curl_creader *reader,
1218 char *buf, size_t blen,
1219 size_t *pnread, bool *peos)
1220{
1221 (void)data;
1222 (void)reader;
1223 (void)buf;
1224 (void)blen;
1225 *pnread = 0;
1226 *peos = TRUE;
1227 return CURLE_OK;
1228}
1229
1230static curl_off_t cr_null_total_length(struct Curl_easy *data,
1231 struct Curl_creader *reader)
1232{
1233 /* this reader changes length depending on input */
1234 (void)data;
1235 (void)reader;
1236 return 0;
1237}
1238
1239static const struct Curl_crtype cr_null = {
1240 "cr-null",
1241 Curl_creader_def_init,
1242 cr_null_read,
1243 Curl_creader_def_close,
1244 Curl_creader_def_needs_rewind,
1245 cr_null_total_length,
1246 Curl_creader_def_resume_from,
1247 Curl_creader_def_rewind,
1248 Curl_creader_def_unpause,
1249 Curl_creader_def_is_paused,
1250 Curl_creader_def_done,
1251 sizeof(struct Curl_creader)
1252};
1253
1254CURLcode Curl_creader_set_null(struct Curl_easy *data)
1255{
1256 struct Curl_creader *r;
1257 CURLcode result;
1258
1259 result = Curl_creader_create(&r, data, &cr_null, CURL_CR_CLIENT);
1260 if(result)
1261 return result;
1262
1263 cl_reset_reader(data);
1264 return do_init_reader_stack(data, r);
1265}
1266
1267struct cr_buf_ctx {
1268 struct Curl_creader super;
1269 const char *buf;
1270 size_t blen;
1271 size_t index;
1272};
1273
1274static CURLcode cr_buf_read(struct Curl_easy *data,
1275 struct Curl_creader *reader,
1276 char *buf, size_t blen,
1277 size_t *pnread, bool *peos)
1278{
1279 struct cr_buf_ctx *ctx = reader->ctx;
1280 size_t nread = ctx->blen - ctx->index;
1281
1282 (void)data;
1283 if(!nread || !ctx->buf) {
1284 *pnread = 0;
1285 *peos = TRUE;
1286 }
1287 else {
1288 if(nread > blen)
1289 nread = blen;
1290 memcpy(buf, ctx->buf + ctx->index, nread);
1291 *pnread = nread;
1292 ctx->index += nread;
1293 *peos = (ctx->index == ctx->blen);
1294 }
1295 CURL_TRC_READ(data, "cr_buf_read(len=%zu) -> 0, nread=%zu, eos=%d",
1296 blen, *pnread, *peos);
1297 return CURLE_OK;
1298}
1299
1300static bool cr_buf_needs_rewind(struct Curl_easy *data,
1301 struct Curl_creader *reader)
1302{
1303 struct cr_buf_ctx *ctx = reader->ctx;
1304 (void)data;
1305 return ctx->index > 0;
1306}
1307
1308static curl_off_t cr_buf_total_length(struct Curl_easy *data,
1309 struct Curl_creader *reader)
1310{
1311 struct cr_buf_ctx *ctx = reader->ctx;
1312 (void)data;
1313 return (curl_off_t)ctx->blen;
1314}
1315
1316static CURLcode cr_buf_resume_from(struct Curl_easy *data,
1317 struct Curl_creader *reader,
1318 curl_off_t offset)
1319{
1320 struct cr_buf_ctx *ctx = reader->ctx;
1321 size_t boffset;
1322
1323 (void)data;
1324 DEBUGASSERT(data->conn);
1325 /* already started reading? */
1326 if(ctx->index)
1327 return CURLE_READ_ERROR;
1328 if(offset <= 0)
1329 return CURLE_OK;
1330 boffset = (size_t)offset;
1331 if(boffset > ctx->blen)
1332 return CURLE_READ_ERROR;
1333
1334 ctx->buf += boffset;
1335 ctx->blen -= boffset;
1336 return CURLE_OK;
1337}
1338
1339static const struct Curl_crtype cr_buf = {
1340 "cr-buf",
1341 Curl_creader_def_init,
1342 cr_buf_read,
1343 Curl_creader_def_close,
1344 cr_buf_needs_rewind,
1345 cr_buf_total_length,
1346 cr_buf_resume_from,
1347 Curl_creader_def_rewind,
1348 Curl_creader_def_unpause,
1349 Curl_creader_def_is_paused,
1350 Curl_creader_def_done,
1351 sizeof(struct cr_buf_ctx)
1352};
1353
1354CURLcode Curl_creader_set_buf(struct Curl_easy *data,
1355 const char *buf, size_t blen)
1356{
1357 CURLcode result;
1358 struct Curl_creader *r;
1359 struct cr_buf_ctx *ctx;
1360
1361 result = Curl_creader_create(&r, data, &cr_buf, CURL_CR_CLIENT);
1362 if(result)
1363 goto out;
1364 ctx = r->ctx;
1365 ctx->buf = buf;
1366 ctx->blen = blen;
1367 ctx->index = 0;
1368
1369 cl_reset_reader(data);
1370 result = do_init_reader_stack(data, r);
1371out:
1372 CURL_TRC_READ(data, "add buf reader, len=%zu -> %d", blen, result);
1373 return result;
1374}
1375
1376curl_off_t Curl_creader_total_length(struct Curl_easy *data)
1377{
1378 struct Curl_creader *r = data->req.reader_stack;
1379 return r ? r->crt->total_length(data, r) : -1;
1380}
1381
1382curl_off_t Curl_creader_client_length(struct Curl_easy *data)
1383{
1384 struct Curl_creader *r = data->req.reader_stack;
1385 while(r && r->phase != CURL_CR_CLIENT)
1386 r = r->next;
1387 return r ? r->crt->total_length(data, r) : -1;
1388}
1389
1390CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset)
1391{
1392 struct Curl_creader *r = data->req.reader_stack;
1393 while(r && r->phase != CURL_CR_CLIENT)
1394 r = r->next;
1395 return r ? r->crt->resume_from(data, r, offset) : CURLE_READ_ERROR;
1396}
1397
1398CURLcode Curl_creader_unpause(struct Curl_easy *data)
1399{
1400 struct Curl_creader *reader = data->req.reader_stack;
1401 CURLcode result = CURLE_OK;
1402
1403 while(reader) {
1404 result = reader->crt->unpause(data, reader);
1405 if(result)
1406 break;
1407 reader = reader->next;
1408 }
1409 return result;
1410}
1411
1412bool Curl_creader_is_paused(struct Curl_easy *data)
1413{
1414 struct Curl_creader *reader = data->req.reader_stack;
1415
1416 while(reader) {
1417 if(reader->crt->is_paused(data, reader))
1418 return TRUE;
1419 reader = reader->next;
1420 }
1421 return FALSE;
1422}
1423
1424void Curl_creader_done(struct Curl_easy *data, int premature)
1425{
1426 struct Curl_creader *reader = data->req.reader_stack;
1427 while(reader) {
1428 reader->crt->done(data, reader, premature);
1429 reader = reader->next;
1430 }
1431}
1432
1433struct Curl_creader *Curl_creader_get_by_type(struct Curl_easy *data,
1434 const struct Curl_crtype *crt)
1435{
1436 struct Curl_creader *r;
1437 for(r = data->req.reader_stack; r; r = r->next) {
1438 if(r->crt == crt)
1439 return r;
1440 }
1441 return NULL;
1442
1443}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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