mirror of
https://github.com/curl/curl.git
synced 2026-08-25 23:13:38 +03:00
header api: add curl_easy_header and curl_easy_nextheader
Add test 1940 to 1946 to verify. Closes #8593
This commit is contained in:
parent
bdc664a640
commit
d1e4a67734
38 changed files with 1798 additions and 306 deletions
|
|
@ -141,6 +141,7 @@ LIB_CFILES = \
|
|||
gopher.c \
|
||||
h2h3.c \
|
||||
hash.c \
|
||||
headers.c \
|
||||
hmac.c \
|
||||
hostasyn.c \
|
||||
hostip.c \
|
||||
|
|
@ -270,6 +271,7 @@ LIB_HFILES = \
|
|||
gopher.h \
|
||||
h2h3.h \
|
||||
hash.h \
|
||||
headers.h \
|
||||
hostip.h \
|
||||
hsts.h \
|
||||
http.h \
|
||||
|
|
|
|||
319
lib/headers.c
Normal file
319
lib/headers.c
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2022, Daniel Stenberg, <daniel@haxx.se>, 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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#include "urldata.h"
|
||||
#include "strdup.h"
|
||||
#include "strcase.h"
|
||||
#include "headers.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
|
||||
/* Generate the curl_header struct for the user. This function MUST assign all
|
||||
struct fields in the output struct. */
|
||||
static void copy_header_external(struct Curl_easy *data,
|
||||
struct Curl_header_store *hs,
|
||||
size_t index,
|
||||
size_t amount,
|
||||
struct Curl_llist_element *e,
|
||||
struct curl_header **hout)
|
||||
{
|
||||
struct curl_header *h = *hout = &data->state.headerout;
|
||||
h->name = hs->name;
|
||||
h->value = hs->value;
|
||||
h->amount = amount;
|
||||
h->index = index;
|
||||
/* this will randomly OR a reverved bit for the sole purpose of making it
|
||||
impossible for applications to do == comparisons, as that would
|
||||
otherwise be very tempting and then lead the reserved bits not being
|
||||
reserved anymore. */
|
||||
h->origin = hs->type | (1<<27);
|
||||
h->anchor = e;
|
||||
}
|
||||
|
||||
/* public API */
|
||||
CURLHcode curl_easy_header(CURL *easy,
|
||||
const char *name,
|
||||
size_t nameindex,
|
||||
unsigned int type,
|
||||
int request,
|
||||
struct curl_header **hout)
|
||||
{
|
||||
struct Curl_llist_element *e;
|
||||
struct Curl_llist_element *e_pick = NULL;
|
||||
struct Curl_easy *data = easy;
|
||||
size_t match = 0;
|
||||
size_t amount = 0;
|
||||
struct Curl_header_store *hs = NULL;
|
||||
struct Curl_header_store *pick = NULL;
|
||||
if(!name || !hout || !data ||
|
||||
(type > (CURLH_HEADER|CURLH_TRAILER|CURLH_CONNECT|CURLH_1XX)) ||
|
||||
!type || (request < -1))
|
||||
return CURLHE_BAD_ARGUMENT;
|
||||
if(!Curl_llist_count(&data->state.httphdrs))
|
||||
return CURLHE_NOHEADERS; /* no headers available */
|
||||
if(request > data->state.requests)
|
||||
return CURLHE_NOREQUEST;
|
||||
if(request == -1)
|
||||
request = data->state.requests;
|
||||
|
||||
/* we need a first round to count amount of this header */
|
||||
for(e = data->state.httphdrs.head; e; e = e->next) {
|
||||
hs = e->ptr;
|
||||
if(strcasecompare(hs->name, name) &&
|
||||
(hs->type & type) &&
|
||||
(hs->request == request)) {
|
||||
amount++;
|
||||
pick = hs;
|
||||
e_pick = e;
|
||||
}
|
||||
}
|
||||
if(!amount)
|
||||
return CURLHE_MISSING;
|
||||
else if(nameindex >= amount)
|
||||
return CURLHE_BADINDEX;
|
||||
|
||||
if(nameindex == amount - 1)
|
||||
/* if the last or only ocurrance is what's asked for, then we know it */
|
||||
hs = pick;
|
||||
else {
|
||||
for(e = data->state.httphdrs.head; e; e = e->next) {
|
||||
hs = e->ptr;
|
||||
if(strcasecompare(hs->name, name) &&
|
||||
(hs->type & type) &&
|
||||
(hs->request == request) &&
|
||||
(match++ == nameindex)) {
|
||||
e_pick = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!e) /* this shouldn't happen */
|
||||
return CURLHE_MISSING;
|
||||
}
|
||||
/* this is the name we want */
|
||||
copy_header_external(data, hs, nameindex, amount, e_pick, hout);
|
||||
return CURLHE_OK;
|
||||
}
|
||||
|
||||
/* public API */
|
||||
struct curl_header *curl_easy_nextheader(CURL *easy,
|
||||
unsigned int type,
|
||||
int request,
|
||||
struct curl_header *prev)
|
||||
{
|
||||
struct Curl_easy *data = easy;
|
||||
struct Curl_llist_element *pick;
|
||||
struct Curl_llist_element *e;
|
||||
struct Curl_header_store *hs;
|
||||
struct curl_header *hout;
|
||||
size_t amount = 0;
|
||||
size_t index = 0;
|
||||
|
||||
if(request > data->state.requests)
|
||||
return NULL;
|
||||
if(request == -1)
|
||||
request = data->state.requests;
|
||||
|
||||
if(prev) {
|
||||
pick = prev->anchor;
|
||||
if(!pick)
|
||||
/* something is wrong */
|
||||
return NULL;
|
||||
pick = pick->next;
|
||||
}
|
||||
else
|
||||
pick = data->state.httphdrs.head;
|
||||
|
||||
if(pick) {
|
||||
/* make sure it is the next header of the desired type */
|
||||
do {
|
||||
hs = pick->ptr;
|
||||
if((hs->type & type) && (hs->request == request))
|
||||
break;
|
||||
} while((pick = pick->next));
|
||||
}
|
||||
|
||||
if(!pick)
|
||||
/* no more headers available */
|
||||
return NULL;
|
||||
|
||||
hs = pick->ptr;
|
||||
|
||||
/* count number of occurrences of this name within the mask and figure out
|
||||
the index for the currently selected entry */
|
||||
for(e = data->state.httphdrs.head; e; e = e->next) {
|
||||
struct Curl_header_store *check = e->ptr;
|
||||
if(strcasecompare(hs->name, check->name) &&
|
||||
(check->request == request) &&
|
||||
(check->type & type))
|
||||
amount++;
|
||||
if(e == pick)
|
||||
index = amount - 1;
|
||||
}
|
||||
|
||||
copy_header_external(data, hs, index, amount, pick, &hout);
|
||||
return hout;
|
||||
}
|
||||
|
||||
static CURLcode namevalue(char *header, size_t hlen, unsigned int type,
|
||||
char **name, char **value)
|
||||
{
|
||||
char *end = header + hlen - 1; /* point to the last byte */
|
||||
DEBUGASSERT(hlen);
|
||||
*name = header;
|
||||
|
||||
if(type == CURLH_PSEUDO) {
|
||||
if(*header != ':')
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
header++;
|
||||
}
|
||||
|
||||
/* Find the end of the header name */
|
||||
while(*header && (*header != ':'))
|
||||
++header;
|
||||
|
||||
if(*header)
|
||||
/* Skip over colon, null it */
|
||||
*header++ = 0;
|
||||
else
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
|
||||
/* skip all leading space letters */
|
||||
while(*header && ISSPACE(*header))
|
||||
header++;
|
||||
|
||||
*value = header;
|
||||
|
||||
/* skip all trailing space letters */
|
||||
while((end > header) && ISSPACE(*end))
|
||||
*end-- = 0; /* nul terminate */
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_headers_push() gets passed a full HTTP header to store. It gets called
|
||||
* immediately before the header callback. The header is CRLF terminated.
|
||||
*/
|
||||
CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
|
||||
unsigned char type)
|
||||
{
|
||||
char *value = NULL;
|
||||
char *name = NULL;
|
||||
char *end;
|
||||
size_t hlen; /* length of the incoming header */
|
||||
struct Curl_header_store *hs;
|
||||
CURLcode result = CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if((header[0] == '\r') || (header[0] == '\n'))
|
||||
/* ignore the body separator */
|
||||
return CURLE_OK;
|
||||
|
||||
end = strchr(header, '\r');
|
||||
if(!end) {
|
||||
end = strchr(header, '\n');
|
||||
if(!end)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
hlen = end - header + 1;
|
||||
|
||||
hs = calloc(1, sizeof(*hs) + hlen);
|
||||
if(!hs)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
memcpy(hs->buffer, header, hlen);
|
||||
hs->buffer[hlen] = 0; /* nul terminate */
|
||||
|
||||
result = namevalue(hs->buffer, hlen, type, &name, &value);
|
||||
if(result)
|
||||
goto fail;
|
||||
|
||||
hs->name = name;
|
||||
hs->value = value;
|
||||
hs->type = type;
|
||||
hs->request = data->state.requests;
|
||||
|
||||
/* insert this node into the list of headers */
|
||||
Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
|
||||
hs, &hs->node);
|
||||
|
||||
return CURLE_OK;
|
||||
fail:
|
||||
free(hs);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_headers_init(). Init the headers subsystem.
|
||||
*/
|
||||
static void headers_init(struct Curl_easy *data)
|
||||
{
|
||||
Curl_llist_init(&data->state.httphdrs, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_headers_cleanup(). Free all stored headers and associated memory.
|
||||
*/
|
||||
CURLcode Curl_headers_cleanup(struct Curl_easy *data)
|
||||
{
|
||||
struct Curl_llist_element *e;
|
||||
struct Curl_llist_element *n;
|
||||
|
||||
for(e = data->state.httphdrs.head; e; e = n) {
|
||||
struct Curl_header_store *hs = e->ptr;
|
||||
n = e->next;
|
||||
free(hs);
|
||||
}
|
||||
headers_init(data);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#else /* HTTP-disabled builds below */
|
||||
|
||||
CURLHcode curl_easy_header(CURL *easy,
|
||||
const char *name,
|
||||
size_t index,
|
||||
unsigned int type,
|
||||
struct curl_header **hout)
|
||||
{
|
||||
(void)easy;
|
||||
(void)name;
|
||||
(void)index;
|
||||
(void)type;
|
||||
(void)hout;
|
||||
return CURLHE_NOT_BUILT_IN;
|
||||
}
|
||||
|
||||
struct curl_header *curl_easy_nextheader(CURL *easy,
|
||||
unsigned int type,
|
||||
struct curl_header *prev)
|
||||
{
|
||||
(void)easy;
|
||||
(void)type;
|
||||
(void)prev;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
53
lib/headers.h
Normal file
53
lib/headers.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef HEADER_CURL_HEADER_H
|
||||
#define HEADER_CURL_HEADER_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, 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.
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
|
||||
struct Curl_header_store {
|
||||
struct Curl_llist_element node;
|
||||
char *name; /* points into 'buffer' */
|
||||
char *value; /* points into 'buffer */
|
||||
int request; /* 0 is the first request, then 1.. 2.. */
|
||||
unsigned char type; /* CURLH_* defines */
|
||||
char buffer[1]; /* this is the raw header blob */
|
||||
};
|
||||
|
||||
/*
|
||||
* Curl_headers_push() gets passed a full header to store.
|
||||
*/
|
||||
CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
|
||||
unsigned char type);
|
||||
|
||||
/*
|
||||
* Curl_headers_cleanup(). Free all stored headers and associated memory.
|
||||
*/
|
||||
CURLcode Curl_headers_cleanup(struct Curl_easy *data);
|
||||
|
||||
#else
|
||||
#define Curl_headers_push(x,y,z) CURLE_NOT_BUILT_IN
|
||||
#define Curl_headers_cleanup(x) Curl_nop_stmt
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_HEADER_H */
|
||||
12
lib/http.c
12
lib/http.c
|
|
@ -4020,9 +4020,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
|||
|
||||
/* now, only output this if the header AND body are requested:
|
||||
*/
|
||||
writetype = CLIENTWRITE_HEADER;
|
||||
if(data->set.include_header)
|
||||
writetype |= CLIENTWRITE_BODY;
|
||||
writetype = CLIENTWRITE_HEADER |
|
||||
(data->set.include_header ? CLIENTWRITE_BODY : 0) |
|
||||
((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
|
||||
|
||||
headerlen = Curl_dyn_len(&data->state.headerb);
|
||||
result = Curl_client_write(data, writetype,
|
||||
|
|
@ -4175,6 +4175,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
|||
* 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! */
|
||||
|
|
@ -4299,6 +4300,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
|||
result = Curl_http_statusline(data, conn);
|
||||
if(result)
|
||||
return result;
|
||||
writetype |= CLIENTWRITE_STATUS;
|
||||
}
|
||||
else {
|
||||
k->header = FALSE; /* this is not a header line */
|
||||
|
|
@ -4317,10 +4319,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
|||
/*
|
||||
* End of header-checks. Write them to the client.
|
||||
*/
|
||||
|
||||
writetype = CLIENTWRITE_HEADER;
|
||||
if(data->set.include_header)
|
||||
writetype |= CLIENTWRITE_BODY;
|
||||
if(k->httpcode/100 == 1)
|
||||
writetype |= CLIENTWRITE_1XX;
|
||||
|
||||
Curl_debug(data, CURLINFO_HEADER_IN, headp,
|
||||
Curl_dyn_len(&data->state.headerb));
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "transfer.h"
|
||||
#include "dynbuf.h"
|
||||
#include "h2h3.h"
|
||||
#include "headers.h"
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
#include "curl_memory.h"
|
||||
|
|
@ -1078,9 +1079,14 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
|
|||
/* nghttp2 guarantees :status is received first and only once, and
|
||||
value is 3 digits status code, and decode_status_code always
|
||||
succeeds. */
|
||||
char buffer[32];
|
||||
stream->status_code = decode_status_code(value, valuelen);
|
||||
DEBUGASSERT(stream->status_code != -1);
|
||||
|
||||
msnprintf(buffer, sizeof(buffer), H2H3_PSEUDO_STATUS ":%u\r",
|
||||
stream->status_code);
|
||||
result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO);
|
||||
if(result)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
result = Curl_dyn_addn(&stream->header_recvbuf, STRCONST("HTTP/2 "));
|
||||
if(result)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
|
|
|
|||
|
|
@ -221,7 +221,9 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
|
|||
tr = Curl_dyn_ptr(&conn->trailer);
|
||||
trlen = Curl_dyn_len(&conn->trailer);
|
||||
if(!data->set.http_te_skip) {
|
||||
result = Curl_client_write(data, CLIENTWRITE_HEADER, tr, trlen);
|
||||
result = Curl_client_write(data,
|
||||
CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER,
|
||||
tr, trlen);
|
||||
if(result) {
|
||||
*extrap = result;
|
||||
return CHUNKE_PASSTHRU_ERROR;
|
||||
|
|
|
|||
|
|
@ -345,6 +345,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
|
|||
/* Send the connect request to the proxy */
|
||||
result = Curl_buffer_send(req, data, &data->info.request_size, 0,
|
||||
sockindex);
|
||||
s->headerlines = 0;
|
||||
}
|
||||
if(result)
|
||||
failf(data, "Failed sending CONNECT to proxy");
|
||||
|
|
@ -480,6 +481,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
|
|||
if(byte != 0x0a)
|
||||
continue;
|
||||
|
||||
s->headerlines++;
|
||||
linep = Curl_dyn_ptr(&s->rcvbuf);
|
||||
perline = Curl_dyn_len(&s->rcvbuf); /* amount of bytes in this line */
|
||||
|
||||
|
|
@ -488,9 +490,9 @@ static CURLcode CONNECT(struct Curl_easy *data,
|
|||
|
||||
if(!data->set.suppress_connect_headers) {
|
||||
/* send the header to the callback */
|
||||
int writetype = CLIENTWRITE_HEADER;
|
||||
if(data->set.include_header)
|
||||
writetype |= CLIENTWRITE_BODY;
|
||||
int writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
|
||||
(data->set.include_header ? CLIENTWRITE_BODY : 0) |
|
||||
(s->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
|
||||
|
||||
result = Curl_client_write(data, writetype, linep, perline);
|
||||
if(result)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
|
|
@ -59,6 +59,7 @@ struct http_connect_state {
|
|||
struct dynbuf rcvbuf;
|
||||
struct dynbuf req;
|
||||
size_t nsend;
|
||||
size_t headerlines;
|
||||
enum keeponval {
|
||||
KEEPON_DONE,
|
||||
KEEPON_CONNECT,
|
||||
|
|
|
|||
|
|
@ -719,7 +719,6 @@ static CURLcode multi_done(struct Curl_easy *data,
|
|||
}
|
||||
|
||||
Curl_safefree(data->state.buffer);
|
||||
Curl_free_request_state(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
25
lib/sendf.c
25
lib/sendf.c
|
|
@ -45,6 +45,7 @@
|
|||
#include "select.h"
|
||||
#include "strdup.h"
|
||||
#include "http2.h"
|
||||
#include "headers.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
|
|
@ -580,21 +581,33 @@ static CURLcode chop_write(struct Curl_easy *data,
|
|||
len -= chunklen;
|
||||
}
|
||||
|
||||
/* HTTP header, but not status-line */
|
||||
if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
|
||||
(type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) {
|
||||
CURLcode result =
|
||||
Curl_headers_push(data, optr,
|
||||
type & CLIENTWRITE_CONNECT ? CURLH_CONNECT :
|
||||
(type & CLIENTWRITE_1XX ? CURLH_1XX :
|
||||
(type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
|
||||
CURLH_HEADER)));
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
if(writeheader) {
|
||||
size_t wrote;
|
||||
ptr = optr;
|
||||
len = olen;
|
||||
|
||||
Curl_set_in_callback(data, true);
|
||||
wrote = writeheader(ptr, 1, len, data->set.writeheader);
|
||||
wrote = writeheader(optr, 1, olen, data->set.writeheader);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
if(CURL_WRITEFUNC_PAUSE == wrote)
|
||||
/* here we pass in the HEADER bit only since if this was body as well
|
||||
then it was passed already and clearly that didn't trigger the
|
||||
pause, so this is saved for later with the HEADER bit only */
|
||||
return pausewrite(data, CLIENTWRITE_HEADER, ptr, len);
|
||||
return pausewrite(data, CLIENTWRITE_HEADER, optr, olen);
|
||||
|
||||
if(wrote != len) {
|
||||
if(wrote != olen) {
|
||||
failf(data, "Failed writing header");
|
||||
return CURLE_WRITE_ERROR;
|
||||
}
|
||||
|
|
@ -620,8 +633,6 @@ CURLcode Curl_client_write(struct Curl_easy *data,
|
|||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
|
||||
DEBUGASSERT(!(type & ~CLIENTWRITE_BOTH));
|
||||
|
||||
if(!len)
|
||||
return CURLE_OK;
|
||||
|
||||
|
|
|
|||
10
lib/sendf.h
10
lib/sendf.h
|
|
@ -7,7 +7,7 @@
|
|||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
|
|
@ -45,8 +45,12 @@ void Curl_failf(struct Curl_easy *, const char *fmt, ...);
|
|||
|
||||
#define failf Curl_failf
|
||||
|
||||
#define CLIENTWRITE_BODY (1<<0)
|
||||
#define CLIENTWRITE_HEADER (1<<1)
|
||||
#define CLIENTWRITE_BODY (1<<0)
|
||||
#define CLIENTWRITE_HEADER (1<<1)
|
||||
#define CLIENTWRITE_STATUS (1<<2) /* the first "header" is the status line */
|
||||
#define CLIENTWRITE_CONNECT (1<<3) /* a CONNECT response */
|
||||
#define CLIENTWRITE_1XX (1<<4) /* a 1xx response */
|
||||
#define CLIENTWRITE_TRAILER (1<<5) /* a trailer header */
|
||||
#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
|
||||
|
||||
CURLcode Curl_client_write(struct Curl_easy *data, int type, char *ptr,
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@
|
|||
#include "urlapi-int.h"
|
||||
#include "hsts.h"
|
||||
#include "setopt.h"
|
||||
#include "headers.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
|
|
@ -1489,6 +1490,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
|
|||
data->set.str[STRING_PROXYPASSWORD]);
|
||||
|
||||
data->req.headerbytecount = 0;
|
||||
Curl_headers_cleanup(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1533,6 +1535,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
|
|||
|
||||
DEBUGASSERT(type != FOLLOW_NONE);
|
||||
|
||||
if(type != FOLLOW_FAKE)
|
||||
data->state.requests++; /* count all real follows */
|
||||
if(type == FOLLOW_REDIR) {
|
||||
if((data->set.maxredirs != -1) &&
|
||||
(data->state.followlocation >= data->set.maxredirs)) {
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
|
|||
#include "setopt.h"
|
||||
#include "altsvc.h"
|
||||
#include "dynbuf.h"
|
||||
#include "headers.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
|
|
@ -470,6 +471,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
|
|||
/* destruct wildcard structures if it is needed */
|
||||
Curl_wildcard_dtor(&data->wildcard);
|
||||
Curl_freeset(data);
|
||||
Curl_headers_cleanup(data);
|
||||
free(data);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1343,6 +1343,7 @@ struct UrlState {
|
|||
int os_errno; /* filled in with errno whenever an error occurs */
|
||||
char *scratch; /* huge buffer[set.buffer_size*2] for upload CRLF replacing */
|
||||
long followlocation; /* redirect counter */
|
||||
int requests; /* request counter: redirects + authentication retakes */
|
||||
#ifdef HAVE_SIGNAL
|
||||
/* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */
|
||||
void (*prev_signal)(int sig);
|
||||
|
|
@ -1414,6 +1415,8 @@ struct UrlState {
|
|||
size_t trailers_bytes_sent;
|
||||
struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
|
||||
headers */
|
||||
struct Curl_llist httphdrs; /* received headers */
|
||||
struct curl_header headerout; /* for external purposes */
|
||||
#endif
|
||||
trailers_state trailers_state; /* whether we are sending trailers
|
||||
and what stage are we at */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue