curl/lib/http.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

302 lines
11 KiB
C
Raw Normal View History

#ifndef HEADER_CURL_HTTP_H
#define HEADER_CURL_HTTP_H
2002-09-03 19:52:59 +08:00
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
1999-12-29 22:20:26 +08:00
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
1999-12-29 22:20:26 +08:00
*
2002-09-03 19:52:59 +08:00
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
2020-11-04 21:02:01 +08:00
* are also available at https://curl.se/docs/copyright.html.
*
2001-01-03 17:29:33 +08:00
* 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
2002-09-03 19:52:59 +08:00
* furnished to do so, under the terms of the COPYING file.
1999-12-29 22:20:26 +08:00
*
2001-01-03 17:29:33 +08:00
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
1999-12-29 22:20:26 +08:00
*
* SPDX-License-Identifier: curl
*
2002-09-03 19:52:59 +08:00
***************************************************************************/
#include "curl_setup.h"
lib: connect/h2/h3 refactor Refactoring of connection setup and happy eyeballing. Move nghttp2. ngtcp2, quiche and msh3 into connection filters. - eyeballing cfilter that uses sub-filters for performing parallel connects - socket cfilter for all transport types, including QUIC - QUIC implementations in cfilter, can now participate in eyeballing - connection setup is more dynamic in order to adapt to what filter did really connect. Relevant to see if a SSL filter needs to be added or if SSL has already been provided - HTTP/3 test cases similar to HTTP/2 - multiuse of parallel transfers for HTTP/3, tested for ngtcp2 and quiche - Fix for data attach/detach in VTLS filters that could lead to crashes during parallel transfers. - Eliminating setup() methods in cfilters, no longer needed. - Improving Curl_conn_is_alive() to replace Curl_connalive() and integrated ssl alive checks into cfilter. - Adding CF_CNTRL_CONN_INFO_UPDATE to tell filters to update connection into and persist it at the easy handle. - Several more cfilter related cleanups and moves: - stream_weigth and dependency info is now wrapped in struct Curl_data_priority - Curl_data_priority members depend is available in HTTP2|HTTP3 - Curl_data_priority members depend on NGHTTP2 support - handling init/reset/cleanup of priority part of url.c - data->state.priority same struct, but shallow copy for compares only - PROTOPT_STREAM has been removed - Curl_conn_is_mulitplex() now available to check on capability - Adding query method to connection filters. - ngtcp2+quiche: implementing query for max concurrent transfers. - Adding is_alive and keep_alive cfilter methods. Adding DATA_SETUP event. - setting keepalive timestamp on connect - DATA_SETUP is called after the connection has been completely setup (but may not connected yet) to allow filters to initialize data members they use. - there is no socket to be had with msh3, it is unclear how select shall work - manual test via "curl --http3 https://curl.se" fail with "empty reply from server". - Various socket/conn related cleanups: - Curl_socket is now Curl_socket_open and in cf-socket.c - Curl_closesocket is now Curl_socket_close and in cf-socket.c - Curl_ssl_use has been replaced with Cur_conn_is_ssl - Curl_conn_tcp_accepted_set has been split into Curl_conn_tcp_listen_set and Curl_conn_tcp_accepted_set with a clearer purpose Closes #10141
2022-12-30 16:14:55 +08:00
#if defined(USE_MSH3) && !defined(_WIN32)
#include <pthread.h>
#endif
#include "bufq.h"
#include "dynhds.h"
#include "ws.h"
typedef enum {
HTTPREQ_GET,
HTTPREQ_POST,
HTTPREQ_POST_FORM, /* we make a difference internally */
HTTPREQ_POST_MIME, /* we make a difference internally */
HTTPREQ_PUT,
HTTPREQ_HEAD
} Curl_HttpReq;
#ifndef CURL_DISABLE_HTTP
#if defined(USE_HTTP3)
#include <stdint.h>
#endif
extern const struct Curl_handler Curl_handler_http;
#ifdef USE_SSL
extern const struct Curl_handler Curl_handler_https;
#endif
struct dynhds;
CURLcode Curl_bump_headersize(struct Curl_easy *data,
size_t delta,
bool connect_only);
/* Header specific functions */
bool Curl_compareheader(const char *headerline, /* line to check */
2002-11-28 23:48:23 +08:00
const char *header, /* header keyword _with_ colon */
const size_t hlen, /* len of the keyword in bytes */
const char *content, /* content string to find */
const size_t clen); /* len of the content in bytes */
char *Curl_copy_header_value(const char *header);
char *Curl_checkProxyheaders(struct Curl_easy *data,
const struct connectdata *conn,
const char *thisheader,
const size_t thislen);
struct HTTP; /* see below */
CURLcode Curl_add_timecondition(struct Curl_easy *data,
#ifndef USE_HYPER
struct dynbuf *req
#else
void *headers
#endif
);
CURLcode Curl_add_custom_headers(struct Curl_easy *data,
bool is_connect,
#ifndef USE_HYPER
struct dynbuf *req
#else
void *headers
#endif
);
CURLcode Curl_dynhds_add_custom(struct Curl_easy *data,
bool is_connect,
struct dynhds *hds);
void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
const char **method, Curl_HttpReq *);
CURLcode Curl_http_useragent(struct Curl_easy *data);
CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn);
CURLcode Curl_http_target(struct Curl_easy *data, struct connectdata *conn,
struct dynbuf *req);
CURLcode Curl_http_statusline(struct Curl_easy *data,
struct connectdata *conn);
CURLcode Curl_http_header(struct Curl_easy *data,
const char *hd, size_t hdlen);
CURLcode Curl_transferencode(struct Curl_easy *data);
CURLcode Curl_http_req_set_reader(struct Curl_easy *data,
Curl_HttpReq httpreq,
const char **tep);
lib: Curl_read/Curl_write clarifications - replace `Curl_read()`, `Curl_write()` and `Curl_nwrite()` to clarify when and at what level they operate - send/recv of transfer related data is now done via `Curl_xfer_send()/Curl_xfer_recv()` which no longer has socket/socketindex as parameter. It decides on the transfer setup of `conn->sockfd` and `conn->writesockfd` on which connection filter chain to operate. - send/recv on a specific connection filter chain is done via `Curl_conn_send()/Curl_conn_recv()` which get the socket index as parameter. - rename `Curl_setup_transfer()` to `Curl_xfer_setup()` for naming consistency - clarify that the special CURLE_AGAIN hangling to return `CURLE_OK` with length 0 only applies to `Curl_xfer_send()` and CURLE_AGAIN is returned by all other send() variants. - fix a bug in websocket `curl_ws_recv()` that mixed up data when it arrived in more than a single chunk (to be made into a sperate PR, also) Added as documented [in CLIENT-READER.md](https://github.com/curl/curl/blob/5b1f31dfbab8aef467c419c68aa06dc738cb75d4/docs/CLIENT-READERS.md). - old `Curl_buffer_send()` completely replaced by new `Curl_req_send()` - old `Curl_fillreadbuffer()` replaced with `Curl_client_read()` - HTTP chunked uploads are now formatted in a client reader added when needed. - FTP line-end conversions are done in a client reader added when needed. - when sending requests headers, remaining buffer space is filled with body data for sending in "one go". This is independent of the request body size. Resolves #12938 as now small and large requests have the same code path. Changes done to test cases: - test513: now fails before sending request headers as this initial "client read" triggers the setup fault. Behaves now the same as in hyper build - test547, test555, test1620: fix the length check in the lib code to only fail for reads *smaller* than expected. This was a bug in the test code that never triggered in the old implementation. Closes #12969
2024-02-15 23:22:53 +08:00
CURLcode Curl_http_req_complete(struct Curl_easy *data,
struct dynbuf *r, Curl_HttpReq httpreq);
bool Curl_use_http_1_1plus(const struct Curl_easy *data,
const struct connectdata *conn);
#ifndef CURL_DISABLE_COOKIES
CURLcode Curl_http_cookies(struct Curl_easy *data,
struct connectdata *conn,
struct dynbuf *r);
#else
#define Curl_http_cookies(a,b,c) CURLE_OK
#endif
CURLcode Curl_http_range(struct Curl_easy *data,
Curl_HttpReq httpreq);
CURLcode Curl_http_firstwrite(struct Curl_easy *data);
/* protocol-specific functions set up to be called by the main engine */
CURLcode Curl_http_setup_conn(struct Curl_easy *data,
struct connectdata *conn);
CURLcode Curl_http(struct Curl_easy *data, bool *done);
CURLcode Curl_http_done(struct Curl_easy *data, CURLcode, bool premature);
CURLcode Curl_http_connect(struct Curl_easy *data, bool *done);
int Curl_http_getsock_do(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *socks);
CURLcode Curl_http_write_resp(struct Curl_easy *data,
const char *buf, size_t blen,
bool is_eos);
CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
const char *hd, size_t hdlen,
bool is_eos);
1999-12-29 22:20:26 +08:00
/* These functions are in http.c */
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
const char *auth);
CURLcode Curl_http_auth_act(struct Curl_easy *data);
/* If only the PICKNONE bit is set, there has been a round-trip and we
selected to use no auth at all. Ie, we actively select no auth, as opposed
to not having one selected. The other CURLAUTH_* defines are present in the
public curl/curl.h header. */
#define CURLAUTH_PICKNONE (1<<30) /* don't use auth */
/* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST
data get included in the initial data chunk sent to the server. If the
data is larger than this, it will automatically get split up in multiple
system calls.
This value used to be fairly big (100K), but we must take into account that
if the server rejects the POST due for authentication reasons, this data
will always be unconditionally sent and thus it may not be larger than can
always be afforded to send twice.
It must not be greater than 64K to work on VMS.
*/
#ifndef MAX_INITIAL_POST_SIZE
#define MAX_INITIAL_POST_SIZE (64*1024)
#endif
/* EXPECT_100_THRESHOLD is the request body size limit for when libcurl will
* automatically add an "Expect: 100-continue" header in HTTP requests. When
* the size is unknown, it will always add it.
*
*/
#ifndef EXPECT_100_THRESHOLD
#define EXPECT_100_THRESHOLD (1024*1024)
#endif
/* MAX_HTTP_RESP_HEADER_SIZE is the maximum size of all response headers
combined that libcurl allows for a single HTTP response, any HTTP
version. This count includes CONNECT response headers. */
#define MAX_HTTP_RESP_HEADER_SIZE (300*1024)
bool Curl_http_exp100_is_selected(struct Curl_easy *data);
void Curl_http_exp100_got100(struct Curl_easy *data);
#endif /* CURL_DISABLE_HTTP */
/****************************************************************************
* HTTP unique setup
***************************************************************************/
struct HTTP {
/* TODO: no longer used, we should remove it from SingleRequest */
char unused;
};
CURLcode Curl_http_size(struct Curl_easy *data);
lib: replace readwrite with write_resp This clarifies the handling of server responses by folding the code for the complicated protocols into their protocol handlers. This concerns mainly HTTP and its bastard sibling RTSP. The terms "read" and "write" are often used without clear context if they refer to the connect or the client/application side of a transfer. This PR uses "read/write" for operations on the client side and "send/receive" for the connection, e.g. server side. If this is considered useful, we can revisit renaming of further methods in another PR. Curl's protocol handler `readwrite()` method been changed: ```diff - CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn, - const char *buf, size_t blen, - size_t *pconsumed, bool *readmore); + CURLcode (*write_resp)(struct Curl_easy *data, const char *buf, size_t blen, + bool is_eos, bool *done); ``` The name was changed to clarify that this writes reponse data to the client side. The parameter changes are: * `conn` removed as it always operates on `data->conn` * `pconsumed` removed as the method needs to handle all data on success * `readmore` removed as no longer necessary * `is_eos` as indicator that this is the last call for the transfer response (end-of-stream). * `done` TRUE on return iff the transfer response is to be treated as finished This change affects many files only because of updated comments in handlers that provide no implementation. The real change is that the HTTP protocol handlers now provide an implementation. The HTTP protocol handlers `write_resp()` implementation will get passed **all** raw data of a server response for the transfer. The HTTP/1.x formatted status and headers, as well as the undecoded response body. `Curl_http_write_resp_hds()` is used internally to parse the response headers and pass them on. This method is public as the RTSP protocol handler also uses it. HTTP/1.1 "chunked" transport encoding is now part of the general *content encoding* writer stack, just like other encodings. A new flag `CLIENTWRITE_EOS` was added for the last client write. This allows writers to verify that they are in a valid end state. The chunked decoder will check if it indeed has seen the last chunk. The general response handling in `transfer.c:466` happens in function `readwrite_data()`. This mainly operates now like: ``` static CURLcode readwrite_data(data, ...) { do { Curl_xfer_recv_resp(data, buf) ... Curl_xfer_write_resp(data, buf) ... } while(interested); ... } ``` All the response data handling is implemented in `Curl_xfer_write_resp()`. It calls the protocol handler's `write_resp()` implementation if available, or does the default behaviour. All raw response data needs to pass through this function. Which also means that anyone in possession of such data may call `Curl_xfer_write_resp()`. Closes #12480
2023-12-01 20:50:32 +08:00
CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
const char *buf, size_t blen,
size_t *pconsumed);
/**
* Curl_http_output_auth() setups the authentication headers for the
* host/proxy and the correct authentication
* method. data->state.authdone is set to TRUE when authentication is
* done.
*
* @param data all information about the current transfer
* @param conn all information about the current connection
* @param request pointer to the request keyword
* @param httpreq is the request type
* @param path pointer to the requested path
* @param proxytunnel boolean if this is the request setting up a "proxy
* tunnel"
*
* @returns CURLcode
*/
CURLcode
Curl_http_output_auth(struct Curl_easy *data,
struct connectdata *conn,
const char *request,
Curl_HttpReq httpreq,
const char *path,
bool proxytunnel); /* TRUE if this is the request setting
up the proxy tunnel */
/* Decode HTTP status code string. */
CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len);
/**
* All about a core HTTP request, excluding body and trailers
*/
struct httpreq {
char method[24];
char *scheme;
char *authority;
char *path;
struct dynhds headers;
struct dynhds trailers;
};
/**
* Create a HTTP request struct.
*/
CURLcode Curl_http_req_make(struct httpreq **preq,
const char *method, size_t m_len,
const char *scheme, size_t s_len,
const char *authority, size_t a_len,
const char *path, size_t p_len);
CURLcode Curl_http_req_make2(struct httpreq **preq,
const char *method, size_t m_len,
CURLU *url, const char *scheme_default);
void Curl_http_req_free(struct httpreq *req);
#define HTTP_PSEUDO_METHOD ":method"
#define HTTP_PSEUDO_SCHEME ":scheme"
#define HTTP_PSEUDO_AUTHORITY ":authority"
#define HTTP_PSEUDO_PATH ":path"
#define HTTP_PSEUDO_STATUS ":status"
/**
* Create the list of HTTP/2 headers which represent the request,
2023-08-25 19:57:53 +08:00
* using HTTP/2 pseudo headers preceding the `req->headers`.
*
* Applies the following transformations:
* - if `authority` is set, any "Host" header is removed.
* - if `authority` is unset and a "Host" header is present, use
* that as `authority` and remove "Host"
* - removes and Connection header fields as defined in rfc9113 ch. 8.2.2
* - lower-cases the header field names
*
* @param h2_headers will contain the HTTP/2 headers on success
* @param req the request to transform
* @param data the handle to lookup defaults like ' :scheme' from
*/
CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers,
struct httpreq *req, struct Curl_easy *data);
/**
* All about a core HTTP response, excluding body and trailers
*/
struct http_resp {
int status;
char *description;
struct dynhds headers;
struct dynhds trailers;
struct http_resp *prev;
};
/**
* Create a HTTP response struct.
*/
CURLcode Curl_http_resp_make(struct http_resp **presp,
int status,
const char *description);
void Curl_http_resp_free(struct http_resp *resp);
#endif /* HEADER_CURL_HTTP_H */