From: Stefan Eissing Date: Tue, 6 Feb 2024 12:55:07 +0000 (+0100) Subject: http: move headers collecting to writer X-Git-Tag: curl-8_7_0~136 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2abfa3833b01dd909ab4bd6fbb3d2b54a5e31be7;p=thirdparty%2Fcurl.git http: move headers collecting to writer - add a client writer that does "push" response headers written to the client if the headers api is enabled - remove special handling in sendf.c - needs to be installed very early on connection setup to catch CONNECT response headers Closes #12880 --- diff --git a/lib/headers.c b/lib/headers.c index 8a3264ab56..0c53dec684 100644 --- a/lib/headers.c +++ b/lib/headers.c @@ -27,6 +27,7 @@ #include "urldata.h" #include "strdup.h" #include "strcase.h" +#include "sendf.h" #include "headers.h" /* The last 3 #include files should be in this order */ @@ -337,14 +338,68 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header, } /* - * Curl_headers_init(). Init the headers subsystem. + * Curl_headers_reset(). Reset the headers subsystem. */ -static void headers_init(struct Curl_easy *data) +static void headers_reset(struct Curl_easy *data) { Curl_llist_init(&data->state.httphdrs, NULL); data->state.prevhead = NULL; } +struct hds_cw_collect_ctx { + struct Curl_cwriter super; +}; + +static CURLcode hds_cw_collect_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t blen) +{ + if((type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS)) { + unsigned char htype = (unsigned char) + (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT : + (type & CLIENTWRITE_1XX ? CURLH_1XX : + (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER : + CURLH_HEADER))); + CURLcode result = Curl_headers_push(data, buf, htype); + if(result) + return result; + } + return Curl_cwriter_write(data, writer->next, type, buf, blen); +} + +static const struct Curl_cwtype hds_cw_collect = { + "hds-collect", + NULL, + Curl_cwriter_def_init, + hds_cw_collect_write, + Curl_cwriter_def_close, + sizeof(struct hds_cw_collect_ctx) +}; + +CURLcode Curl_headers_init(struct Curl_easy *data) +{ + struct Curl_cwriter *writer; + CURLcode result; + + if(data->conn && (data->conn->handler->protocol & PROTO_FAMILY_HTTP)) { + /* avoid installing it twice */ + if(Curl_cwriter_get_by_name(data, hds_cw_collect.name)) + return CURLE_OK; + + result = Curl_cwriter_create(&writer, data, &hds_cw_collect, + CURL_CW_PROTOCOL); + if(result) + return result; + + result = Curl_cwriter_add(data, writer); + if(result) { + Curl_cwriter_free(data, writer); + return result; + } + } + return CURLE_OK; +} + /* * Curl_headers_cleanup(). Free all stored headers and associated memory. */ @@ -358,7 +413,7 @@ CURLcode Curl_headers_cleanup(struct Curl_easy *data) n = e->next; free(hs); } - headers_init(data); + headers_reset(data); return CURLE_OK; } diff --git a/lib/headers.h b/lib/headers.h index a5229ea22f..d9813388c5 100644 --- a/lib/headers.h +++ b/lib/headers.h @@ -36,6 +36,12 @@ struct Curl_header_store { char buffer[1]; /* this is the raw header blob */ }; +/* + * Initialize header collecting for a transfer. + * Will add a client writer that catches CLIENTWRITE_HEADER writes. + */ +CURLcode Curl_headers_init(struct Curl_easy *data); + /* * Curl_headers_push() gets passed a full header to store. */ @@ -48,6 +54,7 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header, CURLcode Curl_headers_cleanup(struct Curl_easy *data); #else +#define Curl_headers_init(x) CURLE_OK #define Curl_headers_push(x,y,z) CURLE_OK #define Curl_headers_cleanup(x) Curl_nop_stmt #endif diff --git a/lib/http.c b/lib/http.c index 9152055241..5b4814cf8b 100644 --- a/lib/http.c +++ b/lib/http.c @@ -73,6 +73,7 @@ #include "hostip.h" #include "dynhds.h" #include "http.h" +#include "headers.h" #include "select.h" #include "parsedate.h" /* for the week day and month names */ #include "strtoofft.h" @@ -3131,6 +3132,13 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) break; } + /* Add collecting of headers written to client. For a new connection, + * we might have done that already, but reuse + * or multiplex needs it here as well. */ + result = Curl_headers_init(data); + if(result) + goto fail; + http = data->req.p.http; DEBUGASSERT(http); diff --git a/lib/sendf.c b/lib/sendf.c index f37cee5d93..6c575083c3 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -49,7 +49,6 @@ #include "select.h" #include "strdup.h" #include "http2.h" -#include "headers.h" #include "progress.h" #include "ws.h" @@ -256,21 +255,6 @@ static CURLcode chop_write(struct Curl_easy *data, len -= chunklen; } -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API) - /* HTTP header, but not status-line */ - if((conn->handler->protocol & PROTO_FAMILY_HTTP) && - (type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) { - unsigned char htype = (unsigned char) - (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT : - (type & CLIENTWRITE_1XX ? CURLH_1XX : - (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER : - CURLH_HEADER))); - CURLcode result = Curl_headers_push(data, optr, htype); - if(result) - return result; - } -#endif - if(writeheader) { size_t wrote; @@ -674,6 +658,17 @@ CURLcode Curl_cwriter_add(struct Curl_easy *data, return CURLE_OK; } +struct Curl_cwriter *Curl_cwriter_get_by_name(struct Curl_easy *data, + const char *name) +{ + struct Curl_cwriter *writer; + for(writer = data->req.writer_stack; writer; writer = writer->next) { + if(!strcmp(name, writer->cwt->name)) + return writer; + } + return NULL; +} + void Curl_cwriter_remove_by_name(struct Curl_easy *data, const char *name) { diff --git a/lib/sendf.h b/lib/sendf.h index 4d4f01e4f5..1a4a68d8ea 100644 --- a/lib/sendf.h +++ b/lib/sendf.h @@ -151,6 +151,9 @@ CURLcode Curl_cwriter_add(struct Curl_easy *data, void Curl_cwriter_remove_by_name(struct Curl_easy *data, const char *name); +struct Curl_cwriter *Curl_cwriter_get_by_name(struct Curl_easy *data, + const char *name); + /** * Convenience method for calling `writer->do_write()` that * checks for NULL writer. diff --git a/lib/url.c b/lib/url.c index d6036c533b..21bd66b45e 100644 --- a/lib/url.c +++ b/lib/url.c @@ -3848,6 +3848,9 @@ CURLcode Curl_setup_conn(struct Curl_easy *data, if(!conn->bits.reuse) result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry, CURL_CF_SSL_DEFAULT); + if(!result) + result = Curl_headers_init(data); + /* not sure we need this flag to be passed around any more */ *protocol_done = FALSE; return result;