1 #ifndef HEADER_CURL_HTTP_CHUNKS_H 2 #define HEADER_CURL_HTTP_CHUNKS_H 3 /*************************************************************************** 4 * _ _ ____ _ 5 * Project ___| | | | _ \| | 6 * / __| | | | |_) | | 7 * | (__| |_| | _ <| |___ 8 * \___|\___/|_| \_\_____| 9 * 10 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 11 * 12 * This software is licensed as described in the file COPYING, which 13 * you should have received as part of this distribution. The terms 14 * are also available at https://curl.se/docs/copyright.html. 15 * 16 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 * copies of the Software, and permit persons to whom the Software is 18 * furnished to do so, under the terms of the COPYING file. 19 * 20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 * KIND, either express or implied. 22 * 23 * SPDX-License-Identifier: curl 24 * 25 ***************************************************************************/ 26 27 #ifndef CURL_DISABLE_HTTP 28 29 #include "dynbuf.h" 30 31 struct connectdata; 32 33 /* 34 * The longest possible hexadecimal number we support in a chunked transfer. 35 * Neither RFC2616 nor the later HTTP specs define a maximum chunk size. 36 * For 64-bit curl_off_t we support 16 digits. For 32-bit, 8 digits. 37 */ 38 #define CHUNK_MAXNUM_LEN (SIZEOF_CURL_OFF_T * 2) 39 40 typedef enum { 41 /* await and buffer all hexadecimal digits until we get one that is not a 42 hexadecimal digit. When done, we go CHUNK_LF */ 43 CHUNK_HEX, 44 45 /* wait for LF, ignore all else */ 46 CHUNK_LF, 47 48 /* We eat the amount of data specified. When done, we move on to the 49 POST_CR state. */ 50 CHUNK_DATA, 51 52 /* POSTLF should get a CR and then a LF and nothing else, then move back to 53 HEX as the CRLF combination marks the end of a chunk. A missing CR is no 54 big deal. */ 55 CHUNK_POSTLF, 56 57 /* Used to mark that we are out of the game. NOTE: that there is a 58 'datasize' field in the struct that will tell how many bytes that were 59 not passed to the client in the end of the last buffer! */ 60 CHUNK_STOP, 61 62 /* At this point optional trailer headers can be found, unless the next line 63 is CRLF */ 64 CHUNK_TRAILER, 65 66 /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR. 67 Next char must be a LF */ 68 CHUNK_TRAILER_CR, 69 70 /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be 71 signalled If this is an empty trailer CHUNKE_STOP will be signalled. 72 Otherwise the trailer will be broadcasted via Curl_client_write() and the 73 next state will be CHUNK_TRAILER */ 74 CHUNK_TRAILER_POSTCR, 75 76 /* Successfully de-chunked everything */ 77 CHUNK_DONE, 78 79 /* Failed on seeing a bad or not correctly terminated chunk */ 80 CHUNK_FAILED 81 } ChunkyState; 82 83 typedef enum { 84 CHUNKE_OK = 0, 85 CHUNKE_TOO_LONG_HEX = 1, 86 CHUNKE_ILLEGAL_HEX, 87 CHUNKE_BAD_CHUNK, 88 CHUNKE_BAD_ENCODING, 89 CHUNKE_OUT_OF_MEMORY, 90 CHUNKE_PASSTHRU_ERROR /* Curl_httpchunk_read() returns a CURLcode to use */ 91 } CHUNKcode; 92 93 struct Curl_chunker { 94 curl_off_t datasize; 95 ChunkyState state; 96 CHUNKcode last_code; 97 struct dynbuf trailer; /* for chunked-encoded trailer */ 98 unsigned char hexindex; 99 char hexbuffer[CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */ 100 BIT(ignore_body); /* never write response body data */ 101 }; 102 103 /* The following functions are defined in http_chunks.c */ 104 void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch, 105 bool ignore_body); 106 void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch); 107 void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch, 108 bool ignore_body); 109 110 /* 111 * Read BODY bytes in HTTP/1.1 chunked encoding from `buf` and return 112 * the amount of bytes consumed. The actual response bytes and trailer 113 * headers are written out to the client. 114 * On success, this will consume all bytes up to the end of the response, 115 * e.g. the last chunk, has been processed. 116 * @param data the transfer involved 117 * @param ch the chunker instance keeping state across calls 118 * @param buf the response data 119 * @param blen amount of bytes in `buf` 120 * @param pconsumed on successful return, the number of bytes in `buf` 121 * consumed 122 * 123 * This function always uses ASCII hex values to accommodate non-ASCII hosts. 124 * For example, 0x0d and 0x0a are used instead of '\r' and '\n'. 125 */ 126 CURLcode Curl_httpchunk_read(struct Curl_easy *data, struct Curl_chunker *ch, 127 char *buf, size_t blen, size_t *pconsumed); 128 129 /** 130 * @return TRUE iff chunked decoded has finished successfully. 131 */ 132 bool Curl_httpchunk_is_done(struct Curl_easy *data, struct Curl_chunker *ch); 133 134 extern const struct Curl_cwtype Curl_httpchunk_unencoder; 135 136 extern const struct Curl_crtype Curl_httpchunk_encoder; 137 138 /** 139 * Add a transfer-encoding "chunked" reader to the transfers reader stack 140 */ 141 CURLcode Curl_httpchunk_add_reader(struct Curl_easy *data); 142 143 #endif /* !CURL_DISABLE_HTTP */ 144 145 #endif /* HEADER_CURL_HTTP_CHUNKS_H */ 146