lib: add Curl_xfer_write_resp_hd
Add method in protocol handlers to allow writing of a single, 0-terminated header line. Avoids parsing and copying these lines. Closes #13165
This commit is contained in:
Родитель
c296abd42d
Коммит
8dd81bd5db
|
@ -171,7 +171,7 @@ static int hyper_each_header(void *userdata,
|
|||
len = Curl_dyn_len(&data->state.headerb);
|
||||
headp = Curl_dyn_ptr(&data->state.headerb);
|
||||
|
||||
result = Curl_http_header(data, data->conn, headp, len);
|
||||
result = Curl_http_header(data, headp, len);
|
||||
if(result) {
|
||||
data->state.hresult = result;
|
||||
return HYPER_ITER_BREAK;
|
||||
|
|
|
@ -80,6 +80,7 @@ const struct Curl_handler Curl_handler_rtmp = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
rtmp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_RTMP, /* defport */
|
||||
|
@ -103,6 +104,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
rtmp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_RTMPT, /* defport */
|
||||
|
@ -126,6 +128,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
rtmp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_RTMP, /* defport */
|
||||
|
@ -149,6 +152,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
rtmp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_RTMPT, /* defport */
|
||||
|
@ -172,6 +176,7 @@ const struct Curl_handler Curl_handler_rtmps = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
rtmp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_RTMPS, /* defport */
|
||||
|
@ -195,6 +200,7 @@ const struct Curl_handler Curl_handler_rtmpts = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
rtmp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_RTMPS, /* defport */
|
||||
|
|
|
@ -90,6 +90,7 @@ const struct Curl_handler Curl_handler_dict = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ZERO_NULL, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_DICT, /* defport */
|
||||
|
|
|
@ -115,6 +115,7 @@ const struct Curl_handler Curl_handler_file = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
file_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
0, /* defport */
|
||||
|
|
|
@ -177,6 +177,7 @@ const struct Curl_handler Curl_handler_ftp = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ftp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_FTP, /* defport */
|
||||
|
@ -208,6 +209,7 @@ const struct Curl_handler Curl_handler_ftps = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ftp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_FTPS, /* defport */
|
||||
|
|
|
@ -76,6 +76,7 @@ const struct Curl_handler Curl_handler_gopher = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ZERO_NULL, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_GOPHER, /* defport */
|
||||
|
@ -100,6 +101,7 @@ const struct Curl_handler Curl_handler_gophers = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ZERO_NULL, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_GOPHER, /* defport */
|
||||
|
|
663
lib/http.c
663
lib/http.c
|
@ -100,7 +100,7 @@
|
|||
* Forward declarations.
|
||||
*/
|
||||
|
||||
static bool http_should_fail(struct Curl_easy *data);
|
||||
static bool http_should_fail(struct Curl_easy *data, int httpcode);
|
||||
static bool http_exp100_is_waiting(struct Curl_easy *data);
|
||||
static CURLcode http_exp100_add_reader(struct Curl_easy *data);
|
||||
static void http_exp100_send_anyway(struct Curl_easy *data);
|
||||
|
@ -123,6 +123,7 @@ const struct Curl_handler Curl_handler_http = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ZERO_NULL, /* disconnect */
|
||||
Curl_http_write_resp, /* write_resp */
|
||||
Curl_http_write_resp_hd, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_HTTP, /* defport */
|
||||
|
@ -151,6 +152,7 @@ const struct Curl_handler Curl_handler_https = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ZERO_NULL, /* disconnect */
|
||||
Curl_http_write_resp, /* write_resp */
|
||||
Curl_http_write_resp_hd, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_HTTPS, /* defport */
|
||||
|
@ -243,8 +245,6 @@ char *Curl_copy_header_value(const char *header)
|
|||
while(*start && ISSPACE(*start))
|
||||
start++;
|
||||
|
||||
/* data is in the host encoding so
|
||||
use '\r' and '\n' instead of 0x0d and 0x0a */
|
||||
end = strchr(start, '\r');
|
||||
if(!end)
|
||||
end = strchr(start, '\n');
|
||||
|
@ -565,7 +565,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
|
|||
data->state.authhost.done = TRUE;
|
||||
}
|
||||
}
|
||||
if(http_should_fail(data)) {
|
||||
if(http_should_fail(data, data->req.httpcode)) {
|
||||
failf(data, "The requested URL returned error: %d",
|
||||
data->req.httpcode);
|
||||
result = CURLE_HTTP_RETURNED_ERROR;
|
||||
|
@ -1006,21 +1006,18 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
|
|||
}
|
||||
|
||||
/**
|
||||
* http_should_fail() determines whether an HTTP response has gotten us
|
||||
* http_should_fail() determines whether an HTTP response code has gotten us
|
||||
* into an error state or not.
|
||||
*
|
||||
* @retval FALSE communications should continue
|
||||
*
|
||||
* @retval TRUE communications should not continue
|
||||
*/
|
||||
static bool http_should_fail(struct Curl_easy *data)
|
||||
static bool http_should_fail(struct Curl_easy *data, int httpcode)
|
||||
{
|
||||
int httpcode;
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(data->conn);
|
||||
|
||||
httpcode = data->req.httpcode;
|
||||
|
||||
/*
|
||||
** If we haven't been asked to fail on error,
|
||||
** don't fail.
|
||||
|
@ -2836,9 +2833,10 @@ checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
|
|||
/*
|
||||
* Curl_http_header() parses a single response header.
|
||||
*/
|
||||
CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
|
||||
char *hd, size_t hdlen)
|
||||
CURLcode Curl_http_header(struct Curl_easy *data,
|
||||
const char *hd, size_t hdlen)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
CURLcode result;
|
||||
struct SingleRequest *k = &data->req;
|
||||
const char *v;
|
||||
|
@ -2848,7 +2846,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
|
|||
case 'A':
|
||||
#ifndef CURL_DISABLE_ALTSVC
|
||||
v = (data->asi &&
|
||||
((conn->handler->flags & PROTOPT_SSL) ||
|
||||
((data->conn->handler->flags & PROTOPT_SSL) ||
|
||||
#ifdef CURLDEBUG
|
||||
/* allow debug builds to circumvent the HTTPS restriction */
|
||||
getenv("CURL_ALTSVC_HTTP")
|
||||
|
@ -3306,12 +3304,11 @@ CURLcode Curl_http_size(struct Curl_easy *data)
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode verify_header(struct Curl_easy *data)
|
||||
static CURLcode verify_header(struct Curl_easy *data,
|
||||
const char *hd, size_t hdlen)
|
||||
{
|
||||
struct SingleRequest *k = &data->req;
|
||||
const char *header = Curl_dyn_ptr(&data->state.headerb);
|
||||
size_t hlen = Curl_dyn_len(&data->state.headerb);
|
||||
char *ptr = memchr(header, 0x00, hlen);
|
||||
char *ptr = memchr(hd, 0x00, hdlen);
|
||||
if(ptr) {
|
||||
/* this is bad, bail out */
|
||||
failf(data, "Nul byte in header");
|
||||
|
@ -3320,11 +3317,11 @@ static CURLcode verify_header(struct Curl_easy *data)
|
|||
if(k->headerline < 2)
|
||||
/* the first "header" is the status-line and it has no colon */
|
||||
return CURLE_OK;
|
||||
if(((header[0] == ' ') || (header[0] == '\t')) && k->headerline > 2)
|
||||
if(((hd[0] == ' ') || (hd[0] == '\t')) && k->headerline > 2)
|
||||
/* line folding, can't happen on line 2 */
|
||||
;
|
||||
else {
|
||||
ptr = memchr(header, ':', hlen);
|
||||
ptr = memchr(hd, ':', hdlen);
|
||||
if(!ptr) {
|
||||
/* this is bad, bail out */
|
||||
failf(data, "Header without colon");
|
||||
|
@ -3369,7 +3366,6 @@ static CURLcode http_on_response(struct Curl_easy *data,
|
|||
struct connectdata *conn = data->conn;
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SingleRequest *k = &data->req;
|
||||
bool switch_to_h2 = FALSE;
|
||||
|
||||
(void)buf; /* not used without HTTP2 enabled */
|
||||
*pconsumed = 0;
|
||||
|
@ -3388,96 +3384,92 @@ static CURLcode http_on_response(struct Curl_easy *data,
|
|||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
else if(k->httpcode < 200) {
|
||||
/* "A user agent MAY ignore unexpected 1xx status responses." */
|
||||
/* "A user agent MAY ignore unexpected 1xx status responses."
|
||||
* By default, we expect to get more responses after this one. */
|
||||
k->header = TRUE;
|
||||
k->headerline = 0; /* restart the header line counter */
|
||||
|
||||
switch(k->httpcode) {
|
||||
case 100:
|
||||
/*
|
||||
* We have made an HTTP PUT or POST and this is 1.1-lingo
|
||||
* that tells us that the server is OK with this and ready
|
||||
* to receive the data.
|
||||
* However, we'll get more headers now so we must get
|
||||
* back into the header-parsing state!
|
||||
*/
|
||||
k->header = TRUE;
|
||||
k->headerline = 0; /* restart the header line counter */
|
||||
|
||||
/* if we did wait for this do enable write now! */
|
||||
Curl_http_exp100_got100(data);
|
||||
break;
|
||||
case 101:
|
||||
if(conn->httpversion == 11) {
|
||||
/* Switching Protocols only allowed from HTTP/1.1 */
|
||||
if(k->upgr101 == UPGR101_H2) {
|
||||
/* Switching to HTTP/2 */
|
||||
infof(data, "Received 101, Switching to HTTP/2");
|
||||
k->upgr101 = UPGR101_RECEIVED;
|
||||
|
||||
/* we'll get more headers (HTTP/2 response) */
|
||||
k->header = TRUE;
|
||||
k->headerline = 0; /* restart the header line counter */
|
||||
switch_to_h2 = TRUE;
|
||||
}
|
||||
#ifdef USE_WEBSOCKETS
|
||||
else if(k->upgr101 == UPGR101_WS) {
|
||||
/* verify the response */
|
||||
result = Curl_ws_accept(data, buf, blen);
|
||||
if(result)
|
||||
return result;
|
||||
k->header = FALSE; /* no more header to parse! */
|
||||
*pconsumed += blen; /* ws accept handled the data */
|
||||
blen = 0;
|
||||
if(data->set.connect_only)
|
||||
k->keepon &= ~KEEP_RECV; /* read no more content */
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
/* Not switching to another protocol */
|
||||
k->header = FALSE; /* no more header to parse! */
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Switching Protocols only allowed from HTTP/1.1 */
|
||||
if(conn->httpversion != 11) {
|
||||
/* invalid for other HTTP versions */
|
||||
failf(data, "unexpected 101 response code");
|
||||
return CURLE_WEIRD_SERVER_REPLY;
|
||||
}
|
||||
if(k->upgr101 == UPGR101_H2) {
|
||||
/* Switching to HTTP/2, where we will get more responses */
|
||||
infof(data, "Received 101, Switching to HTTP/2");
|
||||
k->upgr101 = UPGR101_RECEIVED;
|
||||
/* We expect more response from HTTP/2 later */
|
||||
k->header = TRUE;
|
||||
k->headerline = 0; /* restart the header line counter */
|
||||
/* Any remaining `buf` bytes are already HTTP/2 and passed to
|
||||
* be processed. */
|
||||
result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
|
||||
if(result)
|
||||
return result;
|
||||
*pconsumed += blen;
|
||||
}
|
||||
#ifdef USE_WEBSOCKETS
|
||||
else if(k->upgr101 == UPGR101_WS) {
|
||||
/* verify the response. Any passed `buf` bytes are already in
|
||||
* WebSockets format and taken in by the protocol handler. */
|
||||
result = Curl_ws_accept(data, buf, blen);
|
||||
if(result)
|
||||
return result;
|
||||
*pconsumed += blen; /* ws accept handled the data */
|
||||
k->header = FALSE; /* we will not get more responses */
|
||||
if(data->set.connect_only)
|
||||
k->keepon &= ~KEEP_RECV; /* read no more content */
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
/* We silently accept this as the final response.
|
||||
* TODO: this looks, uhm, wrong. What are we switching to if we
|
||||
* did not ask for an Upgrade? Maybe the application provided an
|
||||
* `Upgrade: xxx` header? */
|
||||
k->header = FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* the status code 1xx indicates a provisional response, so
|
||||
we'll get another set of headers */
|
||||
k->header = TRUE;
|
||||
k->headerline = 0; /* restart the header line counter */
|
||||
/* The server may send us other 1xx responses, like informative
|
||||
* 103. This have no influence on request processing and we expect
|
||||
* to receive a final response eventually. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* k->httpcode >= 200, final response */
|
||||
k->header = FALSE;
|
||||
|
||||
if(k->upgr101 == UPGR101_H2) {
|
||||
/* A requested upgrade was denied, poke the multi handle to possibly
|
||||
allow a pending pipewait to continue */
|
||||
Curl_multi_connchanged(data->multi);
|
||||
}
|
||||
|
||||
if((k->size == -1) && !k->chunk && !conn->bits.close &&
|
||||
(conn->httpversion == 11) &&
|
||||
!(conn->handler->protocol & CURLPROTO_RTSP) &&
|
||||
data->state.httpreq != HTTPREQ_HEAD) {
|
||||
/* On HTTP 1.1, when connection is not to get closed, but no
|
||||
Content-Length nor Transfer-Encoding chunked have been
|
||||
received, according to RFC2616 section 4.4 point 5, we
|
||||
assume that the server will close the connection to
|
||||
signal the end of the document. */
|
||||
infof(data, "no chunk, no close, no size. Assume close to "
|
||||
"signal end");
|
||||
streamclose(conn, "HTTP: No end-of-message indicator");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if(!k->header) {
|
||||
result = Curl_http_size(data);
|
||||
if(result)
|
||||
return result;
|
||||
/* k->httpcode >= 200, final response */
|
||||
k->header = FALSE;
|
||||
|
||||
if(k->upgr101 == UPGR101_H2) {
|
||||
/* A requested upgrade was denied, poke the multi handle to possibly
|
||||
allow a pending pipewait to continue */
|
||||
Curl_multi_connchanged(data->multi);
|
||||
}
|
||||
|
||||
if((k->size == -1) && !k->chunk && !conn->bits.close &&
|
||||
(conn->httpversion == 11) &&
|
||||
!(conn->handler->protocol & CURLPROTO_RTSP) &&
|
||||
data->state.httpreq != HTTPREQ_HEAD) {
|
||||
/* On HTTP 1.1, when connection is not to get closed, but no
|
||||
Content-Length nor Transfer-Encoding chunked have been
|
||||
received, according to RFC2616 section 4.4 point 5, we
|
||||
assume that the server will close the connection to
|
||||
signal the end of the document. */
|
||||
infof(data, "no chunk, no close, no size. Assume close to "
|
||||
"signal end");
|
||||
streamclose(conn, "HTTP: No end-of-message indicator");
|
||||
}
|
||||
|
||||
/* At this point we have some idea about the fate of the connection.
|
||||
|
@ -3511,31 +3503,25 @@ static CURLcode http_on_response(struct Curl_easy *data,
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When all the headers have been parsed, see if we should give
|
||||
* up and return an error.
|
||||
*/
|
||||
if(http_should_fail(data)) {
|
||||
failf(data, "The requested URL returned error: %d",
|
||||
k->httpcode);
|
||||
return CURLE_HTTP_RETURNED_ERROR;
|
||||
}
|
||||
|
||||
#ifdef USE_WEBSOCKETS
|
||||
/* All non-101 HTTP status codes are bad when wanting to upgrade to
|
||||
websockets */
|
||||
/* All >=200 HTTP status codes are errors when wanting websockets */
|
||||
if(data->req.upgr101 == UPGR101_WS) {
|
||||
failf(data, "Refused WebSockets upgrade: %d", k->httpcode);
|
||||
return CURLE_HTTP_RETURNED_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check if this response means the transfer errored. */
|
||||
if(http_should_fail(data, data->req.httpcode)) {
|
||||
failf(data, "The requested URL returned error: %d",
|
||||
k->httpcode);
|
||||
return CURLE_HTTP_RETURNED_ERROR;
|
||||
}
|
||||
|
||||
/* Curl_http_auth_act() checks what authentication methods
|
||||
* that are available and decides which one (if any) to
|
||||
* use. It will set 'newurl' if an auth method was picked. */
|
||||
result = Curl_http_auth_act(data);
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
|
@ -3606,65 +3592,244 @@ static CURLcode http_on_response(struct Curl_easy *data,
|
|||
infof(data, "Keep sending data to get tossed away");
|
||||
k->keepon |= KEEP_SEND;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(!k->header) {
|
||||
/*
|
||||
* really end-of-headers.
|
||||
*
|
||||
* If we requested a "no body", this is a good time to get
|
||||
* out and return home.
|
||||
/* This is the last response that we will got for the current request.
|
||||
* Check on the body size and determine if the response is complete.
|
||||
*/
|
||||
result = Curl_http_size(data);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* If we requested a "no body", this is a good time to get
|
||||
* out and return home.
|
||||
*/
|
||||
if(data->req.no_body)
|
||||
k->download_done = TRUE;
|
||||
|
||||
/* If max download size is *zero* (nothing) we already have
|
||||
nothing and can safely return ok now! But for HTTP/2, we'd
|
||||
like to call http2_handle_stream_close to properly close a
|
||||
stream. In order to do this, we keep reading until we
|
||||
close the stream. */
|
||||
if(0 == k->maxdownload
|
||||
&& !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
|
||||
&& !Curl_conn_is_http3(data, conn, FIRSTSOCKET))
|
||||
k->download_done = TRUE;
|
||||
|
||||
/* final response without error, prepare to receive the body */
|
||||
return Curl_http_firstwrite(data);
|
||||
}
|
||||
|
||||
static CURLcode http_rw_hd(struct Curl_easy *data,
|
||||
const char *hd, size_t hdlen,
|
||||
const char *buf_remain, size_t blen,
|
||||
size_t *pconsumed)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SingleRequest *k = &data->req;
|
||||
int writetype;
|
||||
|
||||
*pconsumed = 0;
|
||||
if((0x0a == *hd) || (0x0d == *hd)) {
|
||||
/* Empty header line means end of headers! */
|
||||
size_t consumed;
|
||||
|
||||
/* now, only output this if the header AND body are requested:
|
||||
*/
|
||||
if(data->req.no_body)
|
||||
k->download_done = TRUE;
|
||||
Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
|
||||
|
||||
/* If max download size is *zero* (nothing) we already have
|
||||
nothing and can safely return ok now! But for HTTP/2, we'd
|
||||
like to call http2_handle_stream_close to properly close a
|
||||
stream. In order to do this, we keep reading until we
|
||||
close the stream. */
|
||||
if(0 == k->maxdownload
|
||||
&& !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
|
||||
&& !Curl_conn_is_http3(data, conn, FIRSTSOCKET))
|
||||
k->download_done = TRUE;
|
||||
}
|
||||
writetype = CLIENTWRITE_HEADER |
|
||||
((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
|
||||
|
||||
if(switch_to_h2) {
|
||||
/* Having handled the headers, we can do the HTTP/2 switch.
|
||||
* Any remaining `buf` bytes are already HTTP/2 and passed to
|
||||
* be processed. */
|
||||
result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
|
||||
result = Curl_client_write(data, writetype, hd, hdlen);
|
||||
if(result)
|
||||
return result;
|
||||
*pconsumed += blen;
|
||||
|
||||
result = Curl_bump_headersize(data, hdlen, FALSE);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
data->req.deductheadercount =
|
||||
(100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
|
||||
|
||||
/* analyze the response to find out what to do. */
|
||||
/* Caveat: we clear anything in the header brigade, because a
|
||||
* response might switch HTTP version which may call use recursively.
|
||||
* Not nice, but that is currently the way of things. */
|
||||
Curl_dyn_reset(&data->state.headerb);
|
||||
result = http_on_response(data, buf_remain, blen, &consumed);
|
||||
if(result)
|
||||
return result;
|
||||
*pconsumed += consumed;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks for special headers coming up.
|
||||
*/
|
||||
|
||||
writetype = CLIENTWRITE_HEADER;
|
||||
if(!k->headerline++) {
|
||||
/* This is the first header, it MUST be the error code line
|
||||
or else we consider this to be the body right away! */
|
||||
bool fine_statusline = FALSE;
|
||||
|
||||
k->httpversion = 0; /* Don't know yet */
|
||||
if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
|
||||
/*
|
||||
* https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
|
||||
*
|
||||
* The response code is always a three-digit number in HTTP as the spec
|
||||
* says. We allow any three-digit number here, but we cannot make
|
||||
* guarantees on future behaviors since it isn't within the protocol.
|
||||
*/
|
||||
const char *p = hd;
|
||||
|
||||
while(*p && ISBLANK(*p))
|
||||
p++;
|
||||
if(!strncmp(p, "HTTP/", 5)) {
|
||||
p += 5;
|
||||
switch(*p) {
|
||||
case '1':
|
||||
p++;
|
||||
if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) {
|
||||
if(ISBLANK(p[2])) {
|
||||
k->httpversion = 10 + (p[1] - '0');
|
||||
p += 3;
|
||||
if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
|
||||
k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
|
||||
(p[2] - '0');
|
||||
p += 3;
|
||||
if(ISSPACE(*p))
|
||||
fine_statusline = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!fine_statusline) {
|
||||
failf(data, "Unsupported HTTP/1 subversion in response");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
break;
|
||||
case '2':
|
||||
case '3':
|
||||
if(!ISBLANK(p[1]))
|
||||
break;
|
||||
k->httpversion = (*p - '0') * 10;
|
||||
p += 2;
|
||||
if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
|
||||
k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
|
||||
(p[2] - '0');
|
||||
p += 3;
|
||||
if(!ISSPACE(*p))
|
||||
break;
|
||||
fine_statusline = TRUE;
|
||||
}
|
||||
break;
|
||||
default: /* unsupported */
|
||||
failf(data, "Unsupported HTTP version in response");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
||||
if(!fine_statusline) {
|
||||
/* If user has set option HTTP200ALIASES,
|
||||
compare header line against list of aliases
|
||||
*/
|
||||
statusline check = checkhttpprefix(data, hd, hdlen);
|
||||
if(check == STATUS_DONE) {
|
||||
fine_statusline = TRUE;
|
||||
k->httpcode = 200;
|
||||
k->httpversion = 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(data->conn->handler->protocol & CURLPROTO_RTSP) {
|
||||
const char *p = hd;
|
||||
while(*p && ISBLANK(*p))
|
||||
p++;
|
||||
if(!strncmp(p, "RTSP/", 5)) {
|
||||
p += 5;
|
||||
if(ISDIGIT(*p)) {
|
||||
p++;
|
||||
if((p[0] == '.') && ISDIGIT(p[1])) {
|
||||
if(ISBLANK(p[2])) {
|
||||
p += 3;
|
||||
if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
|
||||
k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
|
||||
(p[2] - '0');
|
||||
p += 3;
|
||||
if(ISSPACE(*p)) {
|
||||
fine_statusline = TRUE;
|
||||
k->httpversion = 11; /* RTSP acts like HTTP 1.1 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!fine_statusline)
|
||||
return CURLE_WEIRD_SERVER_REPLY;
|
||||
}
|
||||
}
|
||||
|
||||
if(fine_statusline) {
|
||||
result = Curl_http_statusline(data, data->conn);
|
||||
if(result)
|
||||
return result;
|
||||
writetype |= CLIENTWRITE_STATUS;
|
||||
}
|
||||
else {
|
||||
k->header = FALSE; /* this is not a header line */
|
||||
return CURLE_WEIRD_SERVER_REPLY;
|
||||
}
|
||||
}
|
||||
|
||||
result = verify_header(data, hd, hdlen);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = Curl_http_header(data, hd, hdlen);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/*
|
||||
* Taken in one (more) header. Write it to the client.
|
||||
*/
|
||||
Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
|
||||
|
||||
if(k->httpcode/100 == 1)
|
||||
writetype |= CLIENTWRITE_1XX;
|
||||
result = Curl_client_write(data, writetype, hd, hdlen);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = Curl_bump_headersize(data, hdlen, FALSE);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read any HTTP header lines from the server and pass them to the client app.
|
||||
*/
|
||||
static CURLcode http_rw_headers(struct Curl_easy *data,
|
||||
const char *buf, size_t blen,
|
||||
size_t *pconsumed)
|
||||
static CURLcode http_parse_headers(struct Curl_easy *data,
|
||||
const char *buf, size_t blen,
|
||||
size_t *pconsumed)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SingleRequest *k = &data->req;
|
||||
char *hd;
|
||||
size_t hdlen;
|
||||
char *end_ptr;
|
||||
bool leftover_body = FALSE;
|
||||
|
||||
/* header line within buffer loop */
|
||||
*pconsumed = 0;
|
||||
do {
|
||||
size_t line_length;
|
||||
int writetype;
|
||||
|
||||
/* data is in network encoding so use 0x0a instead of '\n' */
|
||||
end_ptr = memchr(buf, 0x0a, blen);
|
||||
while(blen && k->header) {
|
||||
size_t consumed;
|
||||
|
||||
end_ptr = memchr(buf, '\n', blen);
|
||||
if(!end_ptr) {
|
||||
/* Not a complete header line within buffer, append the data to
|
||||
the end of the headerbuff. */
|
||||
|
@ -3700,14 +3865,13 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
|
|||
}
|
||||
|
||||
/* decrease the size of the remaining (supposed) header line */
|
||||
line_length = (end_ptr - buf) + 1;
|
||||
result = Curl_dyn_addn(&data->state.headerb, buf, line_length);
|
||||
consumed = (end_ptr - buf) + 1;
|
||||
result = Curl_dyn_addn(&data->state.headerb, buf, consumed);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
blen -= line_length;
|
||||
buf += line_length;
|
||||
*pconsumed += line_length;
|
||||
blen -= consumed;
|
||||
buf += consumed;
|
||||
*pconsumed += consumed;
|
||||
|
||||
/****
|
||||
* We now have a FULL header line in 'headerb'.
|
||||
|
@ -3735,195 +3899,21 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
|
|||
}
|
||||
}
|
||||
|
||||
/* headers are in network encoding so use 0x0a and 0x0d instead of '\n'
|
||||
and '\r' */
|
||||
hd = Curl_dyn_ptr(&data->state.headerb);
|
||||
hdlen = Curl_dyn_len(&data->state.headerb);
|
||||
if((0x0a == *hd) || (0x0d == *hd)) {
|
||||
/* Empty header line means end of headers! */
|
||||
size_t consumed;
|
||||
|
||||
/* now, only output this if the header AND body are requested:
|
||||
*/
|
||||
Curl_debug(data, CURLINFO_HEADER_IN, hd, hdlen);
|
||||
|
||||
writetype = CLIENTWRITE_HEADER |
|
||||
((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
|
||||
|
||||
result = Curl_client_write(data, writetype, hd, hdlen);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = Curl_bump_headersize(data, hdlen, FALSE);
|
||||
if(result)
|
||||
return result;
|
||||
/* We are done with this line. We reset because response
|
||||
* processing might switch to HTTP/2 and that might call us
|
||||
* directly again. */
|
||||
Curl_dyn_reset(&data->state.headerb);
|
||||
|
||||
data->req.deductheadercount =
|
||||
(100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
|
||||
|
||||
/* analyze the response to find out what to do */
|
||||
result = http_on_response(data, buf, blen, &consumed);
|
||||
if(result)
|
||||
return result;
|
||||
*pconsumed += consumed;
|
||||
result = http_rw_hd(data, Curl_dyn_ptr(&data->state.headerb),
|
||||
Curl_dyn_len(&data->state.headerb),
|
||||
buf, blen, &consumed);
|
||||
/* We are done with this line. We reset because response
|
||||
* processing might switch to HTTP/2 and that might call us
|
||||
* directly again. */
|
||||
Curl_dyn_reset(&data->state.headerb);
|
||||
if(consumed) {
|
||||
blen -= consumed;
|
||||
buf += consumed;
|
||||
|
||||
if(!k->header || !blen)
|
||||
goto out; /* exit header line loop */
|
||||
|
||||
continue;
|
||||
*pconsumed += consumed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks for special headers coming up.
|
||||
*/
|
||||
|
||||
writetype = CLIENTWRITE_HEADER;
|
||||
if(!k->headerline++) {
|
||||
/* This is the first header, it MUST be the error code line
|
||||
or else we consider this to be the body right away! */
|
||||
bool fine_statusline = FALSE;
|
||||
|
||||
k->httpversion = 0; /* Don't know yet */
|
||||
if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
|
||||
/*
|
||||
* https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
|
||||
*
|
||||
* The response code is always a three-digit number in HTTP as the spec
|
||||
* says. We allow any three-digit number here, but we cannot make
|
||||
* guarantees on future behaviors since it isn't within the protocol.
|
||||
*/
|
||||
char *p = hd;
|
||||
|
||||
while(*p && ISBLANK(*p))
|
||||
p++;
|
||||
if(!strncmp(p, "HTTP/", 5)) {
|
||||
p += 5;
|
||||
switch(*p) {
|
||||
case '1':
|
||||
p++;
|
||||
if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) {
|
||||
if(ISBLANK(p[2])) {
|
||||
k->httpversion = 10 + (p[1] - '0');
|
||||
p += 3;
|
||||
if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
|
||||
k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
|
||||
(p[2] - '0');
|
||||
p += 3;
|
||||
if(ISSPACE(*p))
|
||||
fine_statusline = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!fine_statusline) {
|
||||
failf(data, "Unsupported HTTP/1 subversion in response");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
break;
|
||||
case '2':
|
||||
case '3':
|
||||
if(!ISBLANK(p[1]))
|
||||
break;
|
||||
k->httpversion = (*p - '0') * 10;
|
||||
p += 2;
|
||||
if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
|
||||
k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
|
||||
(p[2] - '0');
|
||||
p += 3;
|
||||
if(!ISSPACE(*p))
|
||||
break;
|
||||
fine_statusline = TRUE;
|
||||
}
|
||||
break;
|
||||
default: /* unsupported */
|
||||
failf(data, "Unsupported HTTP version in response");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
||||
if(!fine_statusline) {
|
||||
/* If user has set option HTTP200ALIASES,
|
||||
compare header line against list of aliases
|
||||
*/
|
||||
statusline check = checkhttpprefix(data, hd, hdlen);
|
||||
if(check == STATUS_DONE) {
|
||||
fine_statusline = TRUE;
|
||||
k->httpcode = 200;
|
||||
k->httpversion = 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(conn->handler->protocol & CURLPROTO_RTSP) {
|
||||
char *p = hd;
|
||||
while(*p && ISBLANK(*p))
|
||||
p++;
|
||||
if(!strncmp(p, "RTSP/", 5)) {
|
||||
p += 5;
|
||||
if(ISDIGIT(*p)) {
|
||||
p++;
|
||||
if((p[0] == '.') && ISDIGIT(p[1])) {
|
||||
if(ISBLANK(p[2])) {
|
||||
p += 3;
|
||||
if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
|
||||
k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
|
||||
(p[2] - '0');
|
||||
p += 3;
|
||||
if(ISSPACE(*p)) {
|
||||
fine_statusline = TRUE;
|
||||
k->httpversion = 11; /* RTSP acts like HTTP 1.1 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!fine_statusline)
|
||||
return CURLE_WEIRD_SERVER_REPLY;
|
||||
}
|
||||
}
|
||||
|
||||
if(fine_statusline) {
|
||||
result = Curl_http_statusline(data, conn);
|
||||
if(result)
|
||||
return result;
|
||||
writetype |= CLIENTWRITE_STATUS;
|
||||
}
|
||||
else {
|
||||
k->header = FALSE; /* this is not a header line */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result = verify_header(data);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = Curl_http_header(data, conn, hd, hdlen);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/*
|
||||
* Taken in one (more) header. Write it to the client.
|
||||
*/
|
||||
Curl_debug(data, CURLINFO_HEADER_IN, hd, hdlen);
|
||||
|
||||
if(k->httpcode/100 == 1)
|
||||
writetype |= CLIENTWRITE_1XX;
|
||||
result = Curl_client_write(data, writetype, hd, hdlen);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = Curl_bump_headersize(data, hdlen, FALSE);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
Curl_dyn_reset(&data->state.headerb);
|
||||
}
|
||||
while(blen);
|
||||
|
||||
/* We might have reached the end of the header part here, but
|
||||
there might be a non-header part left in the end of the read
|
||||
|
@ -3935,6 +3925,22 @@ out:
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
|
||||
const char *hd, size_t hdlen,
|
||||
bool is_eos)
|
||||
{
|
||||
CURLcode result;
|
||||
size_t consumed;
|
||||
char tmp = 0;
|
||||
|
||||
result = http_rw_hd(data, hd, hdlen, &tmp, 0, &consumed);
|
||||
if(!result && is_eos) {
|
||||
result = Curl_client_write(data, (CLIENTWRITE_BODY|CLIENTWRITE_EOS),
|
||||
&tmp, 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* HTTP protocol `write_resp` implementation. Will parse headers
|
||||
* when not done yet and otherwise return without consuming data.
|
||||
|
@ -3950,11 +3956,8 @@ CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
|
|||
else {
|
||||
CURLcode result;
|
||||
|
||||
result = http_rw_headers(data, buf, blen, pconsumed);
|
||||
result = http_parse_headers(data, buf, blen, pconsumed);
|
||||
if(!result && !data->req.header) {
|
||||
/* we have successfully finished parsing the HEADERs */
|
||||
result = Curl_http_firstwrite(data);
|
||||
|
||||
if(!data->req.no_body && Curl_dyn_len(&data->state.headerb)) {
|
||||
/* leftover from parsing something that turned out not
|
||||
* to be a header, only happens if we allow for
|
||||
|
|
|
@ -102,8 +102,8 @@ 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, struct connectdata *conn,
|
||||
char *headp, size_t hdlen);
|
||||
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,
|
||||
|
@ -134,6 +134,9 @@ int Curl_http_getsock_do(struct Curl_easy *data, struct connectdata *conn,
|
|||
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);
|
||||
|
||||
/* These functions are in http.c */
|
||||
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
|
||||
|
|
52
lib/http2.c
52
lib/http2.c
|
@ -127,6 +127,7 @@ struct cf_h2_ctx {
|
|||
struct bufq inbufq; /* network input */
|
||||
struct bufq outbufq; /* network output */
|
||||
struct bufc_pool stream_bufcp; /* spares for stream buffers */
|
||||
struct dynbuf scratch; /* scratch buffer for temp use */
|
||||
|
||||
size_t drain_total; /* sum of all stream's UrlState drain */
|
||||
uint32_t max_concurrent_streams;
|
||||
|
@ -153,6 +154,7 @@ static void cf_h2_ctx_clear(struct cf_h2_ctx *ctx)
|
|||
Curl_bufq_free(&ctx->inbufq);
|
||||
Curl_bufq_free(&ctx->outbufq);
|
||||
Curl_bufcp_free(&ctx->stream_bufcp);
|
||||
Curl_dyn_free(&ctx->scratch);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->call_data = save;
|
||||
}
|
||||
|
@ -408,6 +410,7 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf,
|
|||
Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES);
|
||||
Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0);
|
||||
Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0);
|
||||
Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
|
||||
ctx->last_stream_id = 2147483647;
|
||||
|
||||
rc = nghttp2_session_callbacks_new(&cbs);
|
||||
|
@ -945,14 +948,6 @@ fail:
|
|||
return rv;
|
||||
}
|
||||
|
||||
static CURLcode recvbuf_write_hds(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const char *buf, size_t blen)
|
||||
{
|
||||
(void)cf;
|
||||
return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
|
||||
}
|
||||
|
||||
static CURLcode on_stream_frame(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const nghttp2_frame *frame)
|
||||
|
@ -1008,7 +1003,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
|
|||
stream->status_code = -1;
|
||||
}
|
||||
|
||||
result = recvbuf_write_hds(cf, data, STRCONST("\r\n"));
|
||||
result = Curl_xfer_write_resp_hd(data, STRCONST("\r\n"), stream->closed);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
|
@ -1359,6 +1354,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
|
|||
void *userp)
|
||||
{
|
||||
struct Curl_cfilter *cf = userp;
|
||||
struct cf_h2_ctx *ctx = cf->ctx;
|
||||
struct h2_stream_ctx *stream;
|
||||
struct Curl_easy *data_s;
|
||||
int32_t stream_id = frame->hd.stream_id;
|
||||
|
@ -1468,14 +1464,15 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
|
|||
result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO);
|
||||
if(result)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
result = recvbuf_write_hds(cf, data_s, STRCONST("HTTP/2 "));
|
||||
if(result)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
result = recvbuf_write_hds(cf, data_s, (const char *)value, valuelen);
|
||||
if(result)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
/* the space character after the status code is mandatory */
|
||||
result = recvbuf_write_hds(cf, data_s, STRCONST(" \r\n"));
|
||||
Curl_dyn_reset(&ctx->scratch);
|
||||
result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/2 "));
|
||||
if(!result)
|
||||
result = Curl_dyn_addn(&ctx->scratch, value, valuelen);
|
||||
if(!result)
|
||||
result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
|
||||
if(!result)
|
||||
result = Curl_xfer_write_resp_hd(data_s, Curl_dyn_ptr(&ctx->scratch),
|
||||
Curl_dyn_len(&ctx->scratch), FALSE);
|
||||
if(result)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
/* if we receive data for another handle, wake that up */
|
||||
|
@ -1490,16 +1487,17 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
|
|||
/* nghttp2 guarantees that namelen > 0, and :status was already
|
||||
received, and this is not pseudo-header field . */
|
||||
/* convert to an HTTP1-style header */
|
||||
result = recvbuf_write_hds(cf, data_s, (const char *)name, namelen);
|
||||
if(result)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
result = recvbuf_write_hds(cf, data_s, STRCONST(": "));
|
||||
if(result)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
result = recvbuf_write_hds(cf, data_s, (const char *)value, valuelen);
|
||||
if(result)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
result = recvbuf_write_hds(cf, data_s, STRCONST("\r\n"));
|
||||
Curl_dyn_reset(&ctx->scratch);
|
||||
result = Curl_dyn_addn(&ctx->scratch, (const char *)name, namelen);
|
||||
if(!result)
|
||||
result = Curl_dyn_addn(&ctx->scratch, STRCONST(": "));
|
||||
if(!result)
|
||||
result = Curl_dyn_addn(&ctx->scratch, (const char *)value, valuelen);
|
||||
if(!result)
|
||||
result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
|
||||
if(!result)
|
||||
result = Curl_xfer_write_resp_hd(data_s, Curl_dyn_ptr(&ctx->scratch),
|
||||
Curl_dyn_len(&ctx->scratch), FALSE);
|
||||
if(result)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
/* if we receive data for another handle, wake that up */
|
||||
|
|
|
@ -131,6 +131,7 @@ const struct Curl_handler Curl_handler_imap = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
imap_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_IMAP, /* defport */
|
||||
|
@ -160,6 +161,7 @@ const struct Curl_handler Curl_handler_imaps = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
imap_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_IMAPS, /* defport */
|
||||
|
|
|
@ -178,6 +178,7 @@ const struct Curl_handler Curl_handler_ldap = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ZERO_NULL, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_LDAP, /* defport */
|
||||
|
@ -206,6 +207,7 @@ const struct Curl_handler Curl_handler_ldaps = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ZERO_NULL, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_LDAPS, /* defport */
|
||||
|
|
|
@ -89,6 +89,7 @@ const struct Curl_handler Curl_handler_mqtt = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ZERO_NULL, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_MQTT, /* defport */
|
||||
|
|
|
@ -131,6 +131,7 @@ const struct Curl_handler Curl_handler_ldap = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
oldap_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_LDAP, /* defport */
|
||||
|
@ -159,6 +160,7 @@ const struct Curl_handler Curl_handler_ldaps = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
oldap_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_LDAPS, /* defport */
|
||||
|
|
|
@ -126,6 +126,7 @@ const struct Curl_handler Curl_handler_pop3 = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
pop3_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_POP3, /* defport */
|
||||
|
@ -155,6 +156,7 @@ const struct Curl_handler Curl_handler_pop3s = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
pop3_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_POP3S, /* defport */
|
||||
|
@ -1450,7 +1452,7 @@ static CURLcode pop3_parse_custom_request(struct Curl_easy *data)
|
|||
* This function scans the body after the end-of-body and writes everything
|
||||
* until the end is found.
|
||||
*/
|
||||
CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread)
|
||||
CURLcode Curl_pop3_write(struct Curl_easy *data, const char *str, size_t nread)
|
||||
{
|
||||
/* This code could be made into a special function in the handler struct */
|
||||
CURLcode result = CURLE_OK;
|
||||
|
|
|
@ -92,6 +92,7 @@ extern const struct Curl_handler Curl_handler_pop3s;
|
|||
|
||||
/* This function scans the body after the end-of-body and writes everything
|
||||
* until the end is found */
|
||||
CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread);
|
||||
CURLcode Curl_pop3_write(struct Curl_easy *data,
|
||||
const char *str, size_t nread);
|
||||
|
||||
#endif /* HEADER_CURL_POP3_H */
|
||||
|
|
|
@ -266,7 +266,7 @@ static CURLcode req_set_upload_done(struct Curl_easy *data)
|
|||
else if(data->req.writebytecount)
|
||||
infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
|
||||
" bytes", data->req.writebytecount);
|
||||
else
|
||||
else if(!data->req.download_done)
|
||||
infof(data, Curl_creader_total_length(data)?
|
||||
"We are completely uploaded and fine" :
|
||||
"Request completely sent off");
|
||||
|
|
17
lib/rtsp.c
17
lib/rtsp.c
|
@ -93,7 +93,7 @@ static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
|
|||
static
|
||||
CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len);
|
||||
static
|
||||
CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport);
|
||||
CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -114,6 +114,7 @@ const struct Curl_handler Curl_handler_rtsp = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
rtsp_disconnect, /* disconnect */
|
||||
rtsp_rtp_write_resp, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
rtsp_conncheck, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_RTSP, /* defport */
|
||||
|
@ -913,12 +914,12 @@ CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len)
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
|
||||
CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
|
||||
{
|
||||
if(checkprefix("CSeq:", header)) {
|
||||
long CSeq = 0;
|
||||
char *endp;
|
||||
char *p = &header[5];
|
||||
const char *p = &header[5];
|
||||
while(ISBLANK(*p))
|
||||
p++;
|
||||
CSeq = strtol(p, &endp, 10);
|
||||
|
@ -933,8 +934,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
|
|||
}
|
||||
}
|
||||
else if(checkprefix("Session:", header)) {
|
||||
char *start;
|
||||
char *end;
|
||||
const char *start, *end;
|
||||
size_t idlen;
|
||||
|
||||
/* Find the first non-space letter */
|
||||
|
@ -989,14 +989,13 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
|
|||
}
|
||||
|
||||
static
|
||||
CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport)
|
||||
CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport)
|
||||
{
|
||||
/* If we receive multiple Transport response-headers, the linterleaved
|
||||
channels of each response header is recorded and used together for
|
||||
subsequent data validity checks.*/
|
||||
/* e.g.: ' RTP/AVP/TCP;unicast;interleaved=5-6' */
|
||||
char *start;
|
||||
char *end;
|
||||
const char *start, *end;
|
||||
start = transport;
|
||||
while(start && *start) {
|
||||
while(*start && ISBLANK(*start) )
|
||||
|
@ -1005,7 +1004,7 @@ CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport)
|
|||
if(checkprefix("interleaved=", start)) {
|
||||
long chan1, chan2, chan;
|
||||
char *endp;
|
||||
char *p = start + 12;
|
||||
const char *p = start + 12;
|
||||
chan1 = strtol(p, &endp, 10);
|
||||
if(p != endp && chan1 >= 0 && chan1 <= 255) {
|
||||
unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
extern const struct Curl_handler Curl_handler_rtsp;
|
||||
|
||||
CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header);
|
||||
CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header);
|
||||
|
||||
#else
|
||||
/* disabled */
|
||||
|
|
|
@ -273,6 +273,7 @@ const struct Curl_handler Curl_handler_smb = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
smb_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_SMB, /* defport */
|
||||
|
@ -300,6 +301,7 @@ const struct Curl_handler Curl_handler_smbs = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
smb_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_SMBS, /* defport */
|
||||
|
|
|
@ -132,6 +132,7 @@ const struct Curl_handler Curl_handler_smtp = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
smtp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_SMTP, /* defport */
|
||||
|
@ -161,6 +162,7 @@ const struct Curl_handler Curl_handler_smtps = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
smtp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_SMTPS, /* defport */
|
||||
|
|
|
@ -187,6 +187,7 @@ const struct Curl_handler Curl_handler_telnet = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ZERO_NULL, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_TELNET, /* defport */
|
||||
|
|
|
@ -182,6 +182,7 @@ const struct Curl_handler Curl_handler_tftp = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
tftp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_TFTP, /* defport */
|
||||
|
|
|
@ -1156,7 +1156,7 @@ void Curl_xfer_setup(
|
|||
}
|
||||
|
||||
CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
|
||||
char *buf, size_t blen,
|
||||
const char *buf, size_t blen,
|
||||
bool is_eos)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
@ -1195,6 +1195,18 @@ CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
|
|||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
|
||||
const char *hd0, size_t hdlen, bool is_eos)
|
||||
{
|
||||
if(data->conn->handler->write_resp_hd) {
|
||||
/* protocol handlers offering this function take full responsibility
|
||||
* for writing all received download data to the client. */
|
||||
return data->conn->handler->write_resp_hd(data, hd0, hdlen, is_eos);
|
||||
}
|
||||
/* No special handling by protocol handler, write as response bytes */
|
||||
return Curl_xfer_write_resp(data, hd0, hdlen, is_eos);
|
||||
}
|
||||
|
||||
CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature)
|
||||
{
|
||||
(void)premature;
|
||||
|
|
|
@ -62,12 +62,20 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc);
|
|||
* @param blen the amount of bytes in `buf`
|
||||
* @param is_eos TRUE iff the connection indicates this to be the last
|
||||
* bytes of the response
|
||||
* @param done on returnm, TRUE iff the response is complete
|
||||
*/
|
||||
CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
|
||||
char *buf, size_t blen,
|
||||
const char *buf, size_t blen,
|
||||
bool is_eos);
|
||||
|
||||
/**
|
||||
* Write a single "header" line from a server response.
|
||||
* @param hd0 the 0-terminated, single header line
|
||||
* @param hdlen the length of the header line
|
||||
* @param is_eos TRUE iff this is the end of the response
|
||||
*/
|
||||
CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
|
||||
const char *hd0, size_t hdlen, bool is_eos);
|
||||
|
||||
/* This sets up a forthcoming transfer */
|
||||
void Curl_xfer_setup(struct Curl_easy *data,
|
||||
int sockindex, /* socket index to read from or -1 */
|
||||
|
|
|
@ -701,12 +701,18 @@ struct Curl_handler {
|
|||
CURLcode (*disconnect)(struct Curl_easy *, struct connectdata *,
|
||||
bool dead_connection);
|
||||
|
||||
/* If used, this function gets called from transfer.c:readwrite_data() to
|
||||
/* If used, this function gets called from transfer.c to
|
||||
allow the protocol to do extra handling in writing response to
|
||||
the client. */
|
||||
CURLcode (*write_resp)(struct Curl_easy *data, const char *buf, size_t blen,
|
||||
bool is_eos);
|
||||
|
||||
/* If used, this function gets called from transfer.c to
|
||||
allow the protocol to do extra handling in writing a single response
|
||||
header line to the client. */
|
||||
CURLcode (*write_resp_hd)(struct Curl_easy *data,
|
||||
const char *hd, size_t hdlen, bool is_eos);
|
||||
|
||||
/* This function can perform various checks on the connection. See
|
||||
CONNCHECK_* for more information about the checks that can be performed,
|
||||
and CONNRESULT_* for the results that can be returned. */
|
||||
|
|
|
@ -130,6 +130,7 @@ struct cf_ngtcp2_ctx {
|
|||
struct curltime handshake_at; /* time connect handshake finished */
|
||||
struct curltime reconnect_at; /* time the next attempt should start */
|
||||
struct bufc_pool stream_bufcp; /* chunk pool for streams */
|
||||
struct dynbuf scratch; /* temp buffer for header construction */
|
||||
size_t max_stream_window; /* max flow window for one stream */
|
||||
uint64_t max_idle_ms; /* max idle time for QUIC connection */
|
||||
int qlogfd;
|
||||
|
@ -765,12 +766,6 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t sid,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static CURLcode write_resp_hds(struct Curl_easy *data,
|
||||
const char *buf, size_t blen)
|
||||
{
|
||||
return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
|
||||
}
|
||||
|
||||
static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
|
||||
const uint8_t *buf, size_t blen,
|
||||
void *user_data, void *stream_user_data)
|
||||
|
@ -835,7 +830,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid,
|
|||
if(!stream)
|
||||
return 0;
|
||||
/* add a CRLF only if we've received some headers */
|
||||
result = write_resp_hds(data, "\r\n", 2);
|
||||
result = Curl_xfer_write_resp_hd(data, STRCONST("\r\n"), stream->closed);
|
||||
if(result) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -855,6 +850,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
|
|||
void *user_data, void *stream_user_data)
|
||||
{
|
||||
struct Curl_cfilter *cf = user_data;
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
curl_int64_t stream_id = (curl_int64_t)sid;
|
||||
nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
|
||||
nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
|
||||
|
@ -872,17 +868,23 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
|
|||
return 0;
|
||||
|
||||
if(token == NGHTTP3_QPACK_TOKEN__STATUS) {
|
||||
char line[14]; /* status line is always 13 characters long */
|
||||
size_t ncopy;
|
||||
|
||||
result = Curl_http_decode_status(&stream->status_code,
|
||||
(const char *)h3val.base, h3val.len);
|
||||
if(result)
|
||||
return -1;
|
||||
ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
|
||||
stream->status_code);
|
||||
CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] status: %s", stream_id, line);
|
||||
result = write_resp_hds(data, line, ncopy);
|
||||
Curl_dyn_reset(&ctx->scratch);
|
||||
result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/3 "));
|
||||
if(!result)
|
||||
result = Curl_dyn_addn(&ctx->scratch,
|
||||
(const char *)h3val.base, h3val.len);
|
||||
if(!result)
|
||||
result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
|
||||
if(!result)
|
||||
result = Curl_xfer_write_resp_hd(data, Curl_dyn_ptr(&ctx->scratch),
|
||||
Curl_dyn_len(&ctx->scratch), FALSE);
|
||||
CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] status: %s",
|
||||
stream_id, Curl_dyn_ptr(&ctx->scratch));
|
||||
if(result) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -892,19 +894,19 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
|
|||
CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] header: %.*s: %.*s",
|
||||
stream_id, (int)h3name.len, h3name.base,
|
||||
(int)h3val.len, h3val.base);
|
||||
result = write_resp_hds(data, (const char *)h3name.base, h3name.len);
|
||||
if(result) {
|
||||
return -1;
|
||||
}
|
||||
result = write_resp_hds(data, ": ", 2);
|
||||
if(result) {
|
||||
return -1;
|
||||
}
|
||||
result = write_resp_hds(data, (const char *)h3val.base, h3val.len);
|
||||
if(result) {
|
||||
return -1;
|
||||
}
|
||||
result = write_resp_hds(data, "\r\n", 2);
|
||||
Curl_dyn_reset(&ctx->scratch);
|
||||
result = Curl_dyn_addn(&ctx->scratch,
|
||||
(const char *)h3name.base, h3name.len);
|
||||
if(!result)
|
||||
result = Curl_dyn_addn(&ctx->scratch, STRCONST(": "));
|
||||
if(!result)
|
||||
result = Curl_dyn_addn(&ctx->scratch,
|
||||
(const char *)h3val.base, h3val.len);
|
||||
if(!result)
|
||||
result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
|
||||
if(!result)
|
||||
result = Curl_xfer_write_resp_hd(data, Curl_dyn_ptr(&ctx->scratch),
|
||||
Curl_dyn_len(&ctx->scratch), FALSE);
|
||||
if(result) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -1857,6 +1859,7 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
|
|||
if(ctx->qconn)
|
||||
ngtcp2_conn_del(ctx->qconn);
|
||||
Curl_bufcp_free(&ctx->stream_bufcp);
|
||||
Curl_dyn_free(&ctx->scratch);
|
||||
Curl_ssl_peer_cleanup(&ctx->peer);
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
@ -1994,6 +1997,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
|
|||
ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
|
||||
Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
|
||||
H3_STREAM_POOL_SPARES);
|
||||
Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
|
||||
|
||||
result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
|
||||
if(result)
|
||||
|
|
|
@ -162,6 +162,7 @@ const struct Curl_handler Curl_handler_scp = {
|
|||
myssh_getsock, /* perform_getsock */
|
||||
scp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_SSH, /* defport */
|
||||
|
@ -189,6 +190,7 @@ const struct Curl_handler Curl_handler_sftp = {
|
|||
myssh_getsock, /* perform_getsock */
|
||||
sftp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_SSH, /* defport */
|
||||
|
|
|
@ -139,6 +139,7 @@ const struct Curl_handler Curl_handler_scp = {
|
|||
ssh_getsock, /* perform_getsock */
|
||||
scp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ssh_attach, /* attach */
|
||||
PORT_SSH, /* defport */
|
||||
|
@ -168,6 +169,7 @@ const struct Curl_handler Curl_handler_sftp = {
|
|||
ssh_getsock, /* perform_getsock */
|
||||
sftp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ssh_attach, /* attach */
|
||||
PORT_SSH, /* defport */
|
||||
|
|
|
@ -94,6 +94,7 @@ const struct Curl_handler Curl_handler_scp = {
|
|||
wssh_getsock, /* perform_getsock */
|
||||
wscp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_SSH, /* defport */
|
||||
|
@ -123,6 +124,7 @@ const struct Curl_handler Curl_handler_sftp = {
|
|||
wssh_getsock, /* perform_getsock */
|
||||
wsftp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_SSH, /* defport */
|
||||
|
|
2
lib/ws.c
2
lib/ws.c
|
@ -1199,6 +1199,7 @@ const struct Curl_handler Curl_handler_ws = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ws_disconnect, /* disconnect */
|
||||
Curl_http_write_resp, /* write_resp */
|
||||
Curl_http_write_resp_hd, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_HTTP, /* defport */
|
||||
|
@ -1224,6 +1225,7 @@ const struct Curl_handler Curl_handler_wss = {
|
|||
ZERO_NULL, /* perform_getsock */
|
||||
ws_disconnect, /* disconnect */
|
||||
Curl_http_write_resp, /* write_resp */
|
||||
Curl_http_write_resp_hd, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
PORT_HTTPS, /* defport */
|
||||
|
|
Загрузка…
Ссылка в новой задаче