diff --git a/lib/api.c b/lib/api.c index 39147417ba..15e3789861 100644 --- a/lib/api.c +++ b/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, diff --git a/lib/api.h b/lib/api.h index c6810a392e..642a09879e 100644 --- a/lib/api.h +++ b/lib/api.h @@ -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) \ diff --git a/lib/headers.c b/lib/headers.c index 3bc9c3aceb..a6416b0f07 100644 --- a/lib/headers.c +++ b/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 { diff --git a/lib/urldata.h b/lib/urldata.h index b2798eb4f2..6e17adcf43 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -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 diff --git a/tests/libtest/lib1940.c b/tests/libtest/lib1940.c index a0fea9264f..8fbafd5fed 100644 --- a/tests/libtest/lib1940.c +++ b/tests/libtest/lib1940.c @@ -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();