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 | 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 |
|
---|
97 | static 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 |
|
---|
108 | static 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 |
|
---|
119 | void 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 |
|
---|
128 | void 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 |
|
---|
144 | CURLcode 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 |
|
---|
166 | bool Curl_creader_will_rewind(struct Curl_easy *data)
|
---|
167 | {
|
---|
168 | return data->req.rewind_read;
|
---|
169 | }
|
---|
170 |
|
---|
171 | void 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. */
|
---|
177 | CURLcode 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 |
|
---|
186 | CURLcode 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 |
|
---|
194 | CURLcode 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 |
|
---|
201 | void Curl_cwriter_def_close(struct Curl_easy *data,
|
---|
202 | struct Curl_cwriter *writer)
|
---|
203 | {
|
---|
204 | (void) data;
|
---|
205 | (void) writer;
|
---|
206 | }
|
---|
207 |
|
---|
208 | static 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 |
|
---|
230 | struct 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. */
|
---|
236 | static 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 |
|
---|
349 | static 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. */
|
---|
360 | static 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 |
|
---|
370 | static 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. */
|
---|
380 | CURLcode 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 |
|
---|
400 | out:
|
---|
401 | *pwriter = result ? NULL : writer;
|
---|
402 | if(result)
|
---|
403 | free(writer);
|
---|
404 | return result;
|
---|
405 | }
|
---|
406 |
|
---|
407 | void 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 |
|
---|
416 | size_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 |
|
---|
428 | static 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 |
|
---|
457 | CURLcode 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 |
|
---|
478 | struct 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 |
|
---|
489 | struct 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 |
|
---|
500 | void 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 |
|
---|
516 | bool Curl_cwriter_is_paused(struct Curl_easy *data)
|
---|
517 | {
|
---|
518 | return Curl_cw_out_is_paused(data);
|
---|
519 | }
|
---|
520 |
|
---|
521 | CURLcode Curl_cwriter_unpause(struct Curl_easy *data)
|
---|
522 | {
|
---|
523 | return Curl_cw_out_unpause(data);
|
---|
524 | }
|
---|
525 |
|
---|
526 | CURLcode 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 |
|
---|
537 | CURLcode 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 |
|
---|
545 | void Curl_creader_def_close(struct Curl_easy *data,
|
---|
546 | struct Curl_creader *reader)
|
---|
547 | {
|
---|
548 | (void)data;
|
---|
549 | (void)reader;
|
---|
550 | }
|
---|
551 |
|
---|
552 | CURLcode 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 |
|
---|
567 | bool 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 |
|
---|
575 | curl_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 |
|
---|
582 | CURLcode 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 |
|
---|
592 | CURLcode 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 |
|
---|
600 | CURLcode 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 |
|
---|
608 | bool 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 |
|
---|
616 | void 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 |
|
---|
624 | struct 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 |
|
---|
637 | static 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. */
|
---|
649 | static 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 |
|
---|
747 | static 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 |
|
---|
755 | static 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 |
|
---|
763 | static 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 |
|
---|
826 | static 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 |
|
---|
880 | static 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 |
|
---|
889 | static 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 |
|
---|
897 | static 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 |
|
---|
912 | CURLcode 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 |
|
---|
932 | out:
|
---|
933 | *preader = result ? NULL : reader;
|
---|
934 | if(result)
|
---|
935 | free(reader);
|
---|
936 | return result;
|
---|
937 | }
|
---|
938 |
|
---|
939 | void 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 |
|
---|
947 | struct 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 |
|
---|
955 | static 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 |
|
---|
963 | static 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. */
|
---|
971 | static 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 |
|
---|
1050 | out:
|
---|
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 |
|
---|
1056 | static 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 |
|
---|
1065 | static 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 |
|
---|
1080 | static 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 |
|
---|
1095 | static 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 |
|
---|
1123 | CURLcode 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);
|
---|
1137 | out:
|
---|
1138 | CURL_TRC_READ(data, "add fread reader, len=%"FMT_OFF_T " -> %d",
|
---|
1139 | len, result);
|
---|
1140 | return result;
|
---|
1141 | }
|
---|
1142 |
|
---|
1143 | CURLcode 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 |
|
---|
1164 | CURLcode 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 |
|
---|
1179 | CURLcode 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 |
|
---|
1203 | bool 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 |
|
---|
1216 | static 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 |
|
---|
1230 | static 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 |
|
---|
1239 | static 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 |
|
---|
1254 | CURLcode 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 |
|
---|
1267 | struct cr_buf_ctx {
|
---|
1268 | struct Curl_creader super;
|
---|
1269 | const char *buf;
|
---|
1270 | size_t blen;
|
---|
1271 | size_t index;
|
---|
1272 | };
|
---|
1273 |
|
---|
1274 | static 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 |
|
---|
1300 | static 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 |
|
---|
1308 | static 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 |
|
---|
1316 | static 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 |
|
---|
1339 | static 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 |
|
---|
1354 | CURLcode 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);
|
---|
1371 | out:
|
---|
1372 | CURL_TRC_READ(data, "add buf reader, len=%zu -> %d", blen, result);
|
---|
1373 | return result;
|
---|
1374 | }
|
---|
1375 |
|
---|
1376 | curl_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 |
|
---|
1382 | curl_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 |
|
---|
1390 | CURLcode 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 |
|
---|
1398 | CURLcode 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 |
|
---|
1412 | bool 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 |
|
---|
1424 | void 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 |
|
---|
1433 | struct 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 | }
|
---|