2
0

headers.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. ***************************************************************************/
  22. #include "curl_setup.h"
  23. #include "urldata.h"
  24. #include "strdup.h"
  25. #include "strcase.h"
  26. #include "headers.h"
  27. /* The last 3 #include files should be in this order */
  28. #include "curl_printf.h"
  29. #include "curl_memory.h"
  30. #include "memdebug.h"
  31. #if !defined(CURL_DISABLE_HTTP) && defined(USE_HEADERS_API)
  32. /* Generate the curl_header struct for the user. This function MUST assign all
  33. struct fields in the output struct. */
  34. static void copy_header_external(struct Curl_easy *data,
  35. struct Curl_header_store *hs,
  36. size_t index,
  37. size_t amount,
  38. struct Curl_llist_element *e,
  39. struct curl_header **hout)
  40. {
  41. struct curl_header *h = *hout = &data->state.headerout;
  42. h->name = hs->name;
  43. h->value = hs->value;
  44. h->amount = amount;
  45. h->index = index;
  46. /* this will randomly OR a reserved bit for the sole purpose of making it
  47. impossible for applications to do == comparisons, as that would otherwise
  48. be very tempting and then lead to the reserved bits not being reserved
  49. anymore. */
  50. h->origin = hs->type | (1<<27);
  51. h->anchor = e;
  52. }
  53. /* public API */
  54. CURLHcode curl_easy_header(CURL *easy,
  55. const char *name,
  56. size_t nameindex,
  57. unsigned int type,
  58. int request,
  59. struct curl_header **hout)
  60. {
  61. struct Curl_llist_element *e;
  62. struct Curl_llist_element *e_pick = NULL;
  63. struct Curl_easy *data = easy;
  64. size_t match = 0;
  65. size_t amount = 0;
  66. struct Curl_header_store *hs = NULL;
  67. struct Curl_header_store *pick = NULL;
  68. if(!name || !hout || !data ||
  69. (type > (CURLH_HEADER|CURLH_TRAILER|CURLH_CONNECT|CURLH_1XX)) ||
  70. !type || (request < -1))
  71. return CURLHE_BAD_ARGUMENT;
  72. if(!Curl_llist_count(&data->state.httphdrs))
  73. return CURLHE_NOHEADERS; /* no headers available */
  74. if(request > data->state.requests)
  75. return CURLHE_NOREQUEST;
  76. if(request == -1)
  77. request = data->state.requests;
  78. /* we need a first round to count amount of this header */
  79. for(e = data->state.httphdrs.head; e; e = e->next) {
  80. hs = e->ptr;
  81. if(strcasecompare(hs->name, name) &&
  82. (hs->type & type) &&
  83. (hs->request == request)) {
  84. amount++;
  85. pick = hs;
  86. e_pick = e;
  87. }
  88. }
  89. if(!amount)
  90. return CURLHE_MISSING;
  91. else if(nameindex >= amount)
  92. return CURLHE_BADINDEX;
  93. if(nameindex == amount - 1)
  94. /* if the last or only occurrence is what's asked for, then we know it */
  95. hs = pick;
  96. else {
  97. for(e = data->state.httphdrs.head; e; e = e->next) {
  98. hs = e->ptr;
  99. if(strcasecompare(hs->name, name) &&
  100. (hs->type & type) &&
  101. (hs->request == request) &&
  102. (match++ == nameindex)) {
  103. e_pick = e;
  104. break;
  105. }
  106. }
  107. if(!e) /* this shouldn't happen */
  108. return CURLHE_MISSING;
  109. }
  110. /* this is the name we want */
  111. copy_header_external(data, hs, nameindex, amount, e_pick, hout);
  112. return CURLHE_OK;
  113. }
  114. /* public API */
  115. struct curl_header *curl_easy_nextheader(CURL *easy,
  116. unsigned int type,
  117. int request,
  118. struct curl_header *prev)
  119. {
  120. struct Curl_easy *data = easy;
  121. struct Curl_llist_element *pick;
  122. struct Curl_llist_element *e;
  123. struct Curl_header_store *hs;
  124. struct curl_header *hout;
  125. size_t amount = 0;
  126. size_t index = 0;
  127. if(request > data->state.requests)
  128. return NULL;
  129. if(request == -1)
  130. request = data->state.requests;
  131. if(prev) {
  132. pick = prev->anchor;
  133. if(!pick)
  134. /* something is wrong */
  135. return NULL;
  136. pick = pick->next;
  137. }
  138. else
  139. pick = data->state.httphdrs.head;
  140. if(pick) {
  141. /* make sure it is the next header of the desired type */
  142. do {
  143. hs = pick->ptr;
  144. if((hs->type & type) && (hs->request == request))
  145. break;
  146. pick = pick->next;
  147. } while(pick);
  148. }
  149. if(!pick)
  150. /* no more headers available */
  151. return NULL;
  152. hs = pick->ptr;
  153. /* count number of occurrences of this name within the mask and figure out
  154. the index for the currently selected entry */
  155. for(e = data->state.httphdrs.head; e; e = e->next) {
  156. struct Curl_header_store *check = e->ptr;
  157. if(strcasecompare(hs->name, check->name) &&
  158. (check->request == request) &&
  159. (check->type & type))
  160. amount++;
  161. if(e == pick)
  162. index = amount - 1;
  163. }
  164. copy_header_external(data, hs, index, amount, pick, &hout);
  165. return hout;
  166. }
  167. static CURLcode namevalue(char *header, size_t hlen, unsigned int type,
  168. char **name, char **value)
  169. {
  170. char *end = header + hlen - 1; /* point to the last byte */
  171. DEBUGASSERT(hlen);
  172. *name = header;
  173. if(type == CURLH_PSEUDO) {
  174. if(*header != ':')
  175. return CURLE_BAD_FUNCTION_ARGUMENT;
  176. header++;
  177. }
  178. /* Find the end of the header name */
  179. while(*header && (*header != ':'))
  180. ++header;
  181. if(*header)
  182. /* Skip over colon, null it */
  183. *header++ = 0;
  184. else
  185. return CURLE_BAD_FUNCTION_ARGUMENT;
  186. /* skip all leading space letters */
  187. while(*header && ISSPACE(*header))
  188. header++;
  189. *value = header;
  190. /* skip all trailing space letters */
  191. while((end > header) && ISSPACE(*end))
  192. *end-- = 0; /* nul terminate */
  193. return CURLE_OK;
  194. }
  195. /*
  196. * Curl_headers_push() gets passed a full HTTP header to store. It gets called
  197. * immediately before the header callback. The header is CRLF terminated.
  198. */
  199. CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
  200. unsigned char type)
  201. {
  202. char *value = NULL;
  203. char *name = NULL;
  204. char *end;
  205. size_t hlen; /* length of the incoming header */
  206. struct Curl_header_store *hs;
  207. CURLcode result = CURLE_OUT_OF_MEMORY;
  208. if((header[0] == '\r') || (header[0] == '\n'))
  209. /* ignore the body separator */
  210. return CURLE_OK;
  211. end = strchr(header, '\r');
  212. if(!end) {
  213. end = strchr(header, '\n');
  214. if(!end)
  215. return CURLE_BAD_FUNCTION_ARGUMENT;
  216. }
  217. hlen = end - header + 1;
  218. hs = calloc(1, sizeof(*hs) + hlen);
  219. if(!hs)
  220. return CURLE_OUT_OF_MEMORY;
  221. memcpy(hs->buffer, header, hlen);
  222. hs->buffer[hlen] = 0; /* nul terminate */
  223. result = namevalue(hs->buffer, hlen, type, &name, &value);
  224. if(result)
  225. goto fail;
  226. hs->name = name;
  227. hs->value = value;
  228. hs->type = type;
  229. hs->request = data->state.requests;
  230. /* insert this node into the list of headers */
  231. Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
  232. hs, &hs->node);
  233. return CURLE_OK;
  234. fail:
  235. free(hs);
  236. return result;
  237. }
  238. /*
  239. * Curl_headers_init(). Init the headers subsystem.
  240. */
  241. static void headers_init(struct Curl_easy *data)
  242. {
  243. Curl_llist_init(&data->state.httphdrs, NULL);
  244. }
  245. /*
  246. * Curl_headers_cleanup(). Free all stored headers and associated memory.
  247. */
  248. CURLcode Curl_headers_cleanup(struct Curl_easy *data)
  249. {
  250. struct Curl_llist_element *e;
  251. struct Curl_llist_element *n;
  252. for(e = data->state.httphdrs.head; e; e = n) {
  253. struct Curl_header_store *hs = e->ptr;
  254. n = e->next;
  255. free(hs);
  256. }
  257. headers_init(data);
  258. return CURLE_OK;
  259. }
  260. #else /* HTTP-disabled builds below */
  261. CURLHcode curl_easy_header(CURL *easy,
  262. const char *name,
  263. size_t index,
  264. unsigned int origin,
  265. int request,
  266. struct curl_header **hout)
  267. {
  268. (void)easy;
  269. (void)name;
  270. (void)index;
  271. (void)origin;
  272. (void)request;
  273. (void)hout;
  274. return CURLHE_NOT_BUILT_IN;
  275. }
  276. struct curl_header *curl_easy_nextheader(CURL *easy,
  277. unsigned int type,
  278. int request,
  279. struct curl_header *prev)
  280. {
  281. (void)easy;
  282. (void)type;
  283. (void)request;
  284. (void)prev;
  285. return NULL;
  286. }
  287. #endif