diff options
Diffstat (limited to 'Utilities/cmcurl/lib/headers.c')
-rw-r--r-- | Utilities/cmcurl/lib/headers.c | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/Utilities/cmcurl/lib/headers.c b/Utilities/cmcurl/lib/headers.c new file mode 100644 index 0000000..226c696 --- /dev/null +++ b/Utilities/cmcurl/lib/headers.c @@ -0,0 +1,324 @@ +/*************************************************************************** + * _ _ ____ _ + * 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" + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_HEADERS_API) + +/* 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 reserved bit for the sole purpose of making it + impossible for applications to do == comparisons, as that would otherwise + be very tempting and then lead to 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 occurrence 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; + pick = pick->next; + } while(pick); + } + + 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 origin, + int request, + struct curl_header **hout) +{ + (void)easy; + (void)name; + (void)index; + (void)origin; + (void)request; + (void)hout; + return CURLHE_NOT_BUILT_IN; +} + +struct curl_header *curl_easy_nextheader(CURL *easy, + unsigned int type, + int request, + struct curl_header *prev) +{ + (void)easy; + (void)type; + (void)request; + (void)prev; + return NULL; +} +#endif |