mirror of
https://github.com/curl/curl.git
synced 2026-08-25 14:33:44 +03:00
header api: add guards
Add API guards for curl_easy_header and curl_easy_nextheader. urldata.h: remove prevhead member as not used Closes #22530
This commit is contained in:
parent
743096a496
commit
e9b291cf9b
5 changed files with 190 additions and 96 deletions
20
lib/api.c
20
lib/api.c
|
|
@ -43,6 +43,8 @@ static const struct Curl_eapi_fn_props eapi_fn_props[CURL_EAPI_FN_LAST] = {
|
|||
{ CURL_EAPI_FN_easy_cleanup, 1, 0, 0, 0 },
|
||||
{ CURL_EAPI_FN_easy_duphandle, 0, 1, 0, 0 },
|
||||
{ CURL_EAPI_FN_easy_getinfo, 0, 1, 0, 0 },
|
||||
{ CURL_EAPI_FN_easy_header, 0, 1, 0, 0 },
|
||||
{ CURL_EAPI_FN_easy_nextheader, 0, 1, 0, 0 },
|
||||
{ CURL_EAPI_FN_easy_pause, 0, 1, 1, 0 },
|
||||
{ CURL_EAPI_FN_easy_perform_ev, 0, 0, 0, 1 },
|
||||
{ CURL_EAPI_FN_easy_perform, 0, 0, 0, 1 },
|
||||
|
|
@ -303,6 +305,24 @@ void Curl_eapi_leave(struct Curl_eapi_guard *guard)
|
|||
}
|
||||
}
|
||||
|
||||
CURLHcode Curl_eapi_hcode(CURLcode result)
|
||||
{
|
||||
switch(result) {
|
||||
case CURLE_OK:
|
||||
return CURLHE_OK;
|
||||
case CURLE_BAD_FUNCTION_ARGUMENT:
|
||||
return CURLHE_BAD_ARGUMENT;
|
||||
case CURLE_OUT_OF_MEMORY:
|
||||
return CURLHE_OUT_OF_MEMORY;
|
||||
case CURLE_NOT_BUILT_IN:
|
||||
return CURLHE_NOT_BUILT_IN;
|
||||
default:
|
||||
/* Unfortunately, we cannot convert RECURSIVE_API_CALL,
|
||||
* but since the header API is reentrant, this should not happen. */
|
||||
return CURLHE_BAD_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
bool Curl_mapi_enter(struct Curl_mapi_guard *guard,
|
||||
CURLM *m,
|
||||
Curl_mapi_fn fn,
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ typedef enum {
|
|||
CURL_EAPI_FN_easy_cleanup,
|
||||
CURL_EAPI_FN_easy_duphandle,
|
||||
CURL_EAPI_FN_easy_getinfo,
|
||||
CURL_EAPI_FN_easy_header,
|
||||
CURL_EAPI_FN_easy_nextheader,
|
||||
CURL_EAPI_FN_easy_pause,
|
||||
CURL_EAPI_FN_easy_perform_ev,
|
||||
CURL_EAPI_FN_easy_perform,
|
||||
|
|
@ -151,6 +153,9 @@ bool Curl_eapi_enter(struct Curl_eapi_guard *guard,
|
|||
CURLcode *presult);
|
||||
void Curl_eapi_leave(struct Curl_eapi_guard *guard);
|
||||
|
||||
/* Convert an EAPI failure to a header API result */
|
||||
CURLHcode Curl_eapi_hcode(CURLcode result);
|
||||
|
||||
/* Curl_eapi_enter() checks for curl being NULL, but windows compiler
|
||||
* analyzers do not realize this. *sigh* */
|
||||
#define CURL_EAPI_ENTER(g, curl, fn, r) \
|
||||
|
|
|
|||
219
lib/headers.c
219
lib/headers.c
|
|
@ -59,62 +59,84 @@ CURLHcode curl_easy_header(CURL *curl,
|
|||
int request,
|
||||
struct curl_header **hout)
|
||||
{
|
||||
struct Curl_llist_node *e;
|
||||
struct Curl_llist_node *e_pick = NULL;
|
||||
struct Curl_easy *data = curl;
|
||||
size_t match = 0;
|
||||
size_t amount = 0;
|
||||
struct Curl_header_store *hs = NULL;
|
||||
struct Curl_header_store *pick = NULL;
|
||||
if(!name || !hout || !data ||
|
||||
(origin > (CURLH_HEADER | CURLH_TRAILER | CURLH_CONNECT | CURLH_1XX |
|
||||
CURLH_PSEUDO)) || !origin || (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;
|
||||
struct Curl_eapi_guard guard;
|
||||
CURLHcode hresult = CURLHE_OK;
|
||||
CURLcode result;
|
||||
|
||||
/* we need a first round to count amount of this header */
|
||||
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
|
||||
hs = Curl_node_elem(e);
|
||||
if(curl_strequal(hs->name, name) &&
|
||||
(hs->type & origin) &&
|
||||
(hs->request == request)) {
|
||||
amount++;
|
||||
pick = hs;
|
||||
e_pick = e;
|
||||
if(CURL_EAPI_ENTER(&guard, curl, easy_header, &result)) {
|
||||
struct Curl_easy *data = curl;
|
||||
struct Curl_llist_node *e;
|
||||
struct Curl_llist_node *e_pick = NULL;
|
||||
size_t match = 0;
|
||||
size_t amount = 0;
|
||||
struct Curl_header_store *hs = NULL;
|
||||
struct Curl_header_store *pick = NULL;
|
||||
if(!name || !hout || !data ||
|
||||
(origin > (CURLH_HEADER | CURLH_TRAILER | CURLH_CONNECT | CURLH_1XX |
|
||||
CURLH_PSEUDO)) || !origin || (request < -1)) {
|
||||
hresult = CURLHE_BAD_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if(!amount)
|
||||
return CURLHE_MISSING;
|
||||
else if(nameindex >= amount)
|
||||
return CURLHE_BADINDEX;
|
||||
if(!Curl_llist_count(&data->state.httphdrs)) {
|
||||
hresult = CURLHE_NOHEADERS; /* no headers available */
|
||||
goto out;
|
||||
}
|
||||
if(request > data->state.requests) {
|
||||
hresult = CURLHE_NOREQUEST;
|
||||
goto out;
|
||||
}
|
||||
if(request == -1)
|
||||
request = data->state.requests;
|
||||
|
||||
if(nameindex == amount - 1)
|
||||
/* if the last or only occurrence is what's asked for, then we know it */
|
||||
hs = pick;
|
||||
else {
|
||||
/* we need a first round to count amount of this header */
|
||||
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
|
||||
hs = Curl_node_elem(e);
|
||||
if(curl_strequal(hs->name, name) &&
|
||||
(hs->type & origin) &&
|
||||
(hs->request == request) &&
|
||||
(match++ == nameindex)) {
|
||||
(hs->request == request)) {
|
||||
amount++;
|
||||
pick = hs;
|
||||
e_pick = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!e) /* this should not happen */
|
||||
return CURLHE_MISSING;
|
||||
if(!amount)
|
||||
hresult = CURLHE_MISSING;
|
||||
else if(nameindex >= amount)
|
||||
hresult = CURLHE_BADINDEX;
|
||||
if(hresult)
|
||||
goto out;
|
||||
|
||||
if(nameindex == amount - 1)
|
||||
/* if the last or only occurrence is what's asked for, then we know it */
|
||||
hs = pick;
|
||||
else {
|
||||
for(e = Curl_llist_head(&data->state.httphdrs); e;
|
||||
e = Curl_node_next(e)) {
|
||||
hs = Curl_node_elem(e);
|
||||
if(curl_strequal(hs->name, name) &&
|
||||
(hs->type & origin) &&
|
||||
(hs->request == request) &&
|
||||
(match++ == nameindex)) {
|
||||
e_pick = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!e) { /* this should not happen */
|
||||
hresult = CURLHE_MISSING;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* this is the name we want */
|
||||
copy_header_external(hs, nameindex, amount, e_pick,
|
||||
&data->state.headerout[0]);
|
||||
*hout = &data->state.headerout[0];
|
||||
hresult = CURLHE_OK;
|
||||
}
|
||||
/* this is the name we want */
|
||||
copy_header_external(hs, nameindex, amount, e_pick,
|
||||
&data->state.headerout[0]);
|
||||
*hout = &data->state.headerout[0];
|
||||
return CURLHE_OK;
|
||||
out:
|
||||
CURL_EAPI_LEAVE(&guard);
|
||||
if(result)
|
||||
hresult = Curl_eapi_hcode(result);
|
||||
return hresult;
|
||||
}
|
||||
|
||||
/* public API */
|
||||
|
|
@ -123,59 +145,68 @@ struct curl_header *curl_easy_nextheader(CURL *curl,
|
|||
int request,
|
||||
struct curl_header *prev)
|
||||
{
|
||||
struct Curl_easy *data = curl;
|
||||
struct Curl_llist_node *pick;
|
||||
struct Curl_llist_node *e;
|
||||
struct Curl_header_store *hs;
|
||||
size_t amount = 0;
|
||||
size_t index = 0;
|
||||
struct Curl_eapi_guard guard;
|
||||
struct curl_header *hd = NULL;
|
||||
CURLcode result;
|
||||
|
||||
if(request > data->state.requests)
|
||||
return NULL;
|
||||
if(request == -1)
|
||||
request = data->state.requests;
|
||||
if(CURL_EAPI_ENTER(&guard, curl, easy_nextheader, &result)) {
|
||||
struct Curl_easy *data = curl;
|
||||
struct Curl_llist_node *pick;
|
||||
struct Curl_llist_node *e;
|
||||
struct Curl_header_store *hs;
|
||||
size_t amount = 0;
|
||||
size_t index = 0;
|
||||
|
||||
if(prev) {
|
||||
pick = prev->anchor;
|
||||
if(!pick)
|
||||
/* something is wrong */
|
||||
return NULL;
|
||||
pick = Curl_node_next(pick);
|
||||
}
|
||||
else
|
||||
pick = Curl_llist_head(&data->state.httphdrs);
|
||||
if(request > data->state.requests)
|
||||
goto out;
|
||||
if(request == -1)
|
||||
request = data->state.requests;
|
||||
|
||||
if(pick) {
|
||||
/* make sure it is the next header of the desired type */
|
||||
do {
|
||||
hs = Curl_node_elem(pick);
|
||||
if((hs->type & origin) && (hs->request == request))
|
||||
break;
|
||||
if(prev) {
|
||||
pick = prev->anchor;
|
||||
if(!pick)
|
||||
/* something is wrong */
|
||||
goto out;
|
||||
pick = Curl_node_next(pick);
|
||||
} while(pick);
|
||||
}
|
||||
else
|
||||
pick = Curl_llist_head(&data->state.httphdrs);
|
||||
|
||||
if(pick) {
|
||||
/* make sure it is the next header of the desired type */
|
||||
do {
|
||||
hs = Curl_node_elem(pick);
|
||||
if((hs->type & origin) && (hs->request == request))
|
||||
break;
|
||||
pick = Curl_node_next(pick);
|
||||
} while(pick);
|
||||
}
|
||||
|
||||
if(!pick)
|
||||
/* no more headers available */
|
||||
goto out;
|
||||
|
||||
hs = Curl_node_elem(pick);
|
||||
|
||||
/* count number of occurrences of this name within the mask and figure out
|
||||
the index for the currently selected entry */
|
||||
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
|
||||
struct Curl_header_store *check = Curl_node_elem(e);
|
||||
if(curl_strequal(hs->name, check->name) &&
|
||||
(check->request == request) &&
|
||||
(check->type & origin))
|
||||
amount++;
|
||||
if(e == pick)
|
||||
index = amount - 1;
|
||||
}
|
||||
|
||||
copy_header_external(hs, index, amount, pick,
|
||||
&data->state.headerout[1]);
|
||||
hd = &data->state.headerout[1];
|
||||
}
|
||||
|
||||
if(!pick)
|
||||
/* no more headers available */
|
||||
return NULL;
|
||||
|
||||
hs = Curl_node_elem(pick);
|
||||
|
||||
/* count number of occurrences of this name within the mask and figure out
|
||||
the index for the currently selected entry */
|
||||
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
|
||||
struct Curl_header_store *check = Curl_node_elem(e);
|
||||
if(curl_strequal(hs->name, check->name) &&
|
||||
(check->request == request) &&
|
||||
(check->type & origin))
|
||||
amount++;
|
||||
if(e == pick)
|
||||
index = amount - 1;
|
||||
}
|
||||
|
||||
copy_header_external(hs, index, amount, pick,
|
||||
&data->state.headerout[1]);
|
||||
return &data->state.headerout[1];
|
||||
out:
|
||||
CURL_EAPI_LEAVE(&guard);
|
||||
return hd;
|
||||
}
|
||||
|
||||
static CURLcode namevalue(char *header, size_t hlen, unsigned int type,
|
||||
|
|
@ -271,7 +302,6 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
|
|||
|
||||
/* insert this node into the list of headers */
|
||||
Curl_llist_append(&data->state.httphdrs, hs, &hs->node);
|
||||
data->state.prevhead = hs;
|
||||
}
|
||||
else {
|
||||
failf(data, "Invalid response header");
|
||||
|
|
@ -286,7 +316,6 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
|
|||
static void headers_reset(struct Curl_easy *data)
|
||||
{
|
||||
Curl_llist_init(&data->state.httphdrs, NULL);
|
||||
data->state.prevhead = NULL;
|
||||
}
|
||||
|
||||
struct hds_cw_collect_ctx {
|
||||
|
|
|
|||
|
|
@ -630,7 +630,6 @@ struct UrlState {
|
|||
headers */
|
||||
struct Curl_llist httphdrs; /* received headers */
|
||||
struct curl_header headerout[2]; /* for external purposes */
|
||||
struct Curl_header_store *prevhead; /* the latest added header */
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_COOKIES
|
||||
struct curl_slist *cookielist; /* list of cookie files set by
|
||||
|
|
|
|||
|
|
@ -68,6 +68,45 @@ static void t1940_showem(CURL *curl, int header_request, unsigned int type)
|
|||
}
|
||||
}
|
||||
|
||||
static CURLHcode t1940_negative(CURL *curl, int req_index)
|
||||
{
|
||||
struct curl_header *hd1, *hd2;
|
||||
CURLHcode result;
|
||||
|
||||
result = curl_easy_header(NULL, "x", 0, CURLH_HEADER, -1, &hd1);
|
||||
if(result != CURLHE_BAD_ARGUMENT)
|
||||
return result;
|
||||
|
||||
result = curl_easy_header(curl, NULL, 0, CURLH_HEADER, -1, &hd1);
|
||||
if(result != CURLHE_BAD_ARGUMENT)
|
||||
return result;
|
||||
|
||||
result = curl_easy_header(curl, "x", 0, CURLH_HEADER, -1, NULL);
|
||||
if(result != CURLHE_BAD_ARGUMENT)
|
||||
return result;
|
||||
|
||||
result = curl_easy_header(curl, "x", 0, 0, -1, &hd1);
|
||||
if(result != CURLHE_BAD_ARGUMENT)
|
||||
return result;
|
||||
|
||||
result = curl_easy_header(curl, "date", 0, CURLH_HEADER, req_index, &hd1);
|
||||
if(result != CURLHE_OK)
|
||||
return result;
|
||||
if(!hd1)
|
||||
return CURLHE_NOHEADERS;
|
||||
|
||||
/* Should give the first header */
|
||||
hd2 = curl_easy_nextheader(curl, CURLH_HEADER, -1, NULL);
|
||||
if(!hd2)
|
||||
return CURLHE_BADINDEX;
|
||||
|
||||
hd2 = curl_easy_nextheader(NULL, CURLH_HEADER, -1, hd1);
|
||||
if(hd2) /* should not work */
|
||||
return CURLHE_BADINDEX;
|
||||
|
||||
return CURLHE_OK;
|
||||
}
|
||||
|
||||
static CURLcode test_lib1940(const char *URL)
|
||||
{
|
||||
CURL *curl = NULL;
|
||||
|
|
@ -106,6 +145,8 @@ static CURLcode test_lib1940(const char *URL)
|
|||
t1940_showem(curl, header_request, CURLH_1XX);
|
||||
t1940_showem(curl, header_request, CURLH_TRAILER);
|
||||
|
||||
result = (CURLcode)t1940_negative(curl, header_request);
|
||||
|
||||
test_cleanup:
|
||||
curl_easy_cleanup(curl);
|
||||
curl_global_cleanup();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue