VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/sendf.c@ 106165

最後變更 在這個檔案從106165是 104083,由 vboxsync 提交於 8 月 前

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

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

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