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 |
|
---|
63 | static 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 | */
|
---|
70 | CURLcode 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 |
|
---|
94 | static 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 |
|
---|
105 | static 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 |
|
---|
116 | void 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 |
|
---|
126 | void 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 |
|
---|
142 | CURLcode 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 |
|
---|
164 | bool Curl_creader_will_rewind(struct Curl_easy *data)
|
---|
165 | {
|
---|
166 | return data->req.rewind_read;
|
---|
167 | }
|
---|
168 |
|
---|
169 | void 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. */
|
---|
176 | CURLcode 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 |
|
---|
185 | CURLcode 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 |
|
---|
193 | CURLcode 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 |
|
---|
200 | void Curl_cwriter_def_close(struct Curl_easy *data,
|
---|
201 | struct Curl_cwriter *writer)
|
---|
202 | {
|
---|
203 | (void) data;
|
---|
204 | (void) writer;
|
---|
205 | }
|
---|
206 |
|
---|
207 | static 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 |
|
---|
229 | struct 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. */
|
---|
235 | static 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 |
|
---|
335 | static 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. */
|
---|
346 | static 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 |
|
---|
356 | static 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. */
|
---|
366 | CURLcode 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 |
|
---|
386 | out:
|
---|
387 | *pwriter = result? NULL : writer;
|
---|
388 | if(result)
|
---|
389 | free(writer);
|
---|
390 | return result;
|
---|
391 | }
|
---|
392 |
|
---|
393 | void 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 |
|
---|
402 | size_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 |
|
---|
414 | static 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 |
|
---|
443 | CURLcode 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 |
|
---|
464 | struct 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 |
|
---|
475 | struct 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 |
|
---|
486 | void 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 |
|
---|
502 | CURLcode 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 |
|
---|
511 | CURLcode 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 |
|
---|
519 | void Curl_creader_def_close(struct Curl_easy *data,
|
---|
520 | struct Curl_creader *reader)
|
---|
521 | {
|
---|
522 | (void)data;
|
---|
523 | (void)reader;
|
---|
524 | }
|
---|
525 |
|
---|
526 | CURLcode 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 |
|
---|
541 | bool 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 |
|
---|
549 | curl_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 |
|
---|
556 | CURLcode 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 |
|
---|
566 | CURLcode 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 |
|
---|
574 | CURLcode 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 |
|
---|
582 | void 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 |
|
---|
590 | struct 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 |
|
---|
602 | static 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. */
|
---|
614 | static 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 |
|
---|
707 | static 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 |
|
---|
715 | static 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 |
|
---|
723 | static 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 |
|
---|
786 | static 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 |
|
---|
841 | static 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 |
|
---|
855 | CURLcode 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 |
|
---|
875 | out:
|
---|
876 | *preader = result? NULL : reader;
|
---|
877 | if(result)
|
---|
878 | free(reader);
|
---|
879 | return result;
|
---|
880 | }
|
---|
881 |
|
---|
882 | void 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 |
|
---|
890 | struct 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 |
|
---|
897 | static 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 |
|
---|
905 | static 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. */
|
---|
913 | static 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 |
|
---|
983 | static 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 |
|
---|
992 | static 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 |
|
---|
1006 | static 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 |
|
---|
1021 | static 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 |
|
---|
1049 | CURLcode 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 |
|
---|
1065 | CURLcode 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 |
|
---|
1086 | CURLcode 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 |
|
---|
1101 | CURLcode 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 |
|
---|
1123 | bool 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 |
|
---|
1134 | static 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 |
|
---|
1148 | static 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 |
|
---|
1157 | static 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 |
|
---|
1171 | CURLcode 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 |
|
---|
1184 | struct cr_buf_ctx {
|
---|
1185 | struct Curl_creader super;
|
---|
1186 | const char *buf;
|
---|
1187 | size_t blen;
|
---|
1188 | size_t index;
|
---|
1189 | };
|
---|
1190 |
|
---|
1191 | static 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 |
|
---|
1215 | static 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 |
|
---|
1223 | static 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 |
|
---|
1231 | static 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 |
|
---|
1254 | static 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 |
|
---|
1268 | CURLcode 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 |
|
---|
1287 | curl_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 |
|
---|
1293 | curl_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 |
|
---|
1301 | CURLcode 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 |
|
---|
1309 | CURLcode 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 |
|
---|
1323 | void 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 |
|
---|
1332 | struct 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 | }
|
---|