#ifndef HEADER_CURL_HTTP_CHUNKS_H #define HEADER_CURL_HTTP_CHUNKS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ #ifndef CURL_DISABLE_HTTP #include "dynbuf.h" struct connectdata; /* * The longest possible hexadecimal number we support in a chunked transfer. * Neither RFC2616 nor the later HTTP specs define a maximum chunk size. * For 64 bit curl_off_t we support 16 digits. For 32 bit, 8 digits. */ #define CHUNK_MAXNUM_LEN (SIZEOF_CURL_OFF_T * 2) typedef enum { /* await and buffer all hexadecimal digits until we get one that isn't a hexadecimal digit. When done, we go CHUNK_LF */ CHUNK_HEX, /* wait for LF, ignore all else */ CHUNK_LF, /* We eat the amount of data specified. When done, we move on to the POST_CR state. */ CHUNK_DATA, /* POSTLF should get a CR and then a LF and nothing else, then move back to HEX as the CRLF combination marks the end of a chunk. A missing CR is no big deal. */ CHUNK_POSTLF, /* Used to mark that we're out of the game. NOTE: that there's a 'datasize' field in the struct that will tell how many bytes that were not passed to the client in the end of the last buffer! */ CHUNK_STOP, /* At this point optional trailer headers can be found, unless the next line is CRLF */ CHUNK_TRAILER, /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR. Next char must be a LF */ CHUNK_TRAILER_CR, /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be signalled If this is an empty trailer CHUNKE_STOP will be signalled. Otherwise the trailer will be broadcasted via Curl_client_write() and the next state will be CHUNK_TRAILER */ CHUNK_TRAILER_POSTCR, /* Successfully de-chunked everything */ CHUNK_DONE, /* Failed on seeing a bad or not correctly terminated chunk */ CHUNK_FAILED } ChunkyState; typedef enum { CHUNKE_OK = 0, CHUNKE_TOO_LONG_HEX = 1, CHUNKE_ILLEGAL_HEX, CHUNKE_BAD_CHUNK, CHUNKE_BAD_ENCODING, CHUNKE_OUT_OF_MEMORY, CHUNKE_PASSTHRU_ERROR /* Curl_httpchunk_read() returns a CURLcode to use */ } CHUNKcode; struct Curl_chunker { curl_off_t datasize; ChunkyState state; CHUNKcode last_code; struct dynbuf trailer; /* for chunked-encoded trailer */ unsigned char hexindex; char hexbuffer[CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */ BIT(ignore_body); /* never write response body data */ }; /* The following functions are defined in http_chunks.c */ void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch, bool ignore_body); void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch); void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch, bool ignore_body); /* * Read BODY bytes in HTTP/1.1 chunked encoding from `buf` and return * the amount of bytes consumed. The actual response bytes and trailer * headers are written out to the client. * On success, this will consume all bytes up to the end of the response, * e.g. the last chunk, has been processed. * @param data the transfer involved * @param ch the chunker instance keeping state across calls * @param buf the response data * @param blen amount of bytes in `buf` * @param pconsumed on successful return, the number of bytes in `buf` * consumed * * This function always uses ASCII hex values to accommodate non-ASCII hosts. * For example, 0x0d and 0x0a are used instead of '\r' and '\n'. */ CURLcode Curl_httpchunk_read(struct Curl_easy *data, struct Curl_chunker *ch, char *buf, size_t blen, size_t *pconsumed); /** * @return TRUE iff chunked decoded has finished successfully. */ bool Curl_httpchunk_is_done(struct Curl_easy *data, struct Curl_chunker *ch); extern const struct Curl_cwtype Curl_httpchunk_unencoder; extern const struct Curl_crtype Curl_httpchunk_encoder; /** * Add a transfer-encoding "chunked" reader to the transfers reader stack */ CURLcode Curl_httpchunk_add_reader(struct Curl_easy *data); #endif /* !CURL_DISABLE_HTTP */ #endif /* HEADER_CURL_HTTP_CHUNKS_H */