1
0

headers.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <[email protected]>, 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. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. #include "curl_setup.h"
  25. #include "urldata.h"
  26. #include "sendf.h"
  27. #include "curl_trc.h"
  28. #include "headers.h"
  29. #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API)
  30. /* Generate the curl_header struct for the user. This function MUST assign all
  31. struct fields in the output struct. */
  32. static void copy_header_external(struct Curl_header_store *hs,
  33. size_t index,
  34. size_t amount,
  35. struct Curl_llist_node *e,
  36. struct curl_header *hout)
  37. {
  38. struct curl_header *h = hout;
  39. h->name = hs->name;
  40. h->value = hs->value;
  41. h->amount = amount;
  42. h->index = index;
  43. /* this will randomly OR a reserved bit for the sole purpose of making it
  44. impossible for applications to do == comparisons, as that would otherwise
  45. be tempting and then lead to the reserved bits not being reserved
  46. anymore. */
  47. h->origin = (unsigned int)(hs->type | (1 << 27));
  48. h->anchor = e;
  49. }
  50. /* public API */
  51. CURLHcode curl_easy_header(CURL *easy,
  52. const char *name,
  53. size_t nameindex,
  54. unsigned int type,
  55. int request,
  56. struct curl_header **hout)
  57. {
  58. struct Curl_llist_node *e;
  59. struct Curl_llist_node *e_pick = NULL;
  60. struct Curl_easy *data = easy;
  61. size_t match = 0;
  62. size_t amount = 0;
  63. struct Curl_header_store *hs = NULL;
  64. struct Curl_header_store *pick = NULL;
  65. if(!name || !hout || !data ||
  66. (type > (CURLH_HEADER | CURLH_TRAILER | CURLH_CONNECT | CURLH_1XX |
  67. CURLH_PSEUDO)) || !type || (request < -1))
  68. return CURLHE_BAD_ARGUMENT;
  69. if(!Curl_llist_count(&data->state.httphdrs))
  70. return CURLHE_NOHEADERS; /* no headers available */
  71. if(request > data->state.requests)
  72. return CURLHE_NOREQUEST;
  73. if(request == -1)
  74. request = data->state.requests;
  75. /* we need a first round to count amount of this header */
  76. for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
  77. hs = Curl_node_elem(e);
  78. if(curl_strequal(hs->name, name) &&
  79. (hs->type & type) &&
  80. (hs->request == request)) {
  81. amount++;
  82. pick = hs;
  83. e_pick = e;
  84. }
  85. }
  86. if(!amount)
  87. return CURLHE_MISSING;
  88. else if(nameindex >= amount)
  89. return CURLHE_BADINDEX;
  90. if(nameindex == amount - 1)
  91. /* if the last or only occurrence is what's asked for, then we know it */
  92. hs = pick;
  93. else {
  94. for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
  95. hs = Curl_node_elem(e);
  96. if(curl_strequal(hs->name, name) &&
  97. (hs->type & type) &&
  98. (hs->request == request) &&
  99. (match++ == nameindex)) {
  100. e_pick = e;
  101. break;
  102. }
  103. }
  104. if(!e) /* this should not happen */
  105. return CURLHE_MISSING;
  106. }
  107. /* this is the name we want */
  108. copy_header_external(hs, nameindex, amount, e_pick,
  109. &data->state.headerout[0]);
  110. *hout = &data->state.headerout[0];
  111. return CURLHE_OK;
  112. }
  113. /* public API */
  114. struct curl_header *curl_easy_nextheader(CURL *easy,
  115. unsigned int type,
  116. int request,
  117. struct curl_header *prev)
  118. {
  119. struct Curl_easy *data = easy;
  120. struct Curl_llist_node *pick;
  121. struct Curl_llist_node *e;
  122. struct Curl_header_store *hs;
  123. size_t amount = 0;
  124. size_t index = 0;
  125. if(request > data->state.requests)
  126. return NULL;
  127. if(request == -1)
  128. request = data->state.requests;
  129. if(prev) {
  130. pick = prev->anchor;
  131. if(!pick)
  132. /* something is wrong */
  133. return NULL;
  134. pick = Curl_node_next(pick);
  135. }
  136. else
  137. pick = Curl_llist_head(&data->state.httphdrs);
  138. if(pick) {
  139. /* make sure it is the next header of the desired type */
  140. do {
  141. hs = Curl_node_elem(pick);
  142. if((hs->type & type) && (hs->request == request))
  143. break;
  144. pick = Curl_node_next(pick);
  145. } while(pick);
  146. }
  147. if(!pick)
  148. /* no more headers available */
  149. return NULL;
  150. hs = Curl_node_elem(pick);
  151. /* count number of occurrences of this name within the mask and figure out
  152. the index for the currently selected entry */
  153. for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
  154. struct Curl_header_store *check = Curl_node_elem(e);
  155. if(curl_strequal(hs->name, check->name) &&
  156. (check->request == request) &&
  157. (check->type & type))
  158. amount++;
  159. if(e == pick)
  160. index = amount - 1;
  161. }
  162. copy_header_external(hs, index, amount, pick,
  163. &data->state.headerout[1]);
  164. return &data->state.headerout[1];
  165. }
  166. static CURLcode namevalue(char *header, size_t hlen, unsigned int type,
  167. char **name, char **value)
  168. {
  169. char *end = header + hlen - 1; /* point to the last byte */
  170. DEBUGASSERT(hlen);
  171. *name = header;
  172. if(type == CURLH_PSEUDO) {
  173. if(*header != ':')
  174. return CURLE_BAD_FUNCTION_ARGUMENT;
  175. header++;
  176. }
  177. /* Find the end of the header name */
  178. while(*header && (*header != ':'))
  179. ++header;
  180. if(*header)
  181. /* Skip over colon, null it */
  182. *header++ = 0;
  183. else
  184. return CURLE_BAD_FUNCTION_ARGUMENT;
  185. /* skip all leading blank letters */
  186. while(ISBLANK(*header))
  187. header++;
  188. *value = header;
  189. /* skip all trailing space letters */
  190. while((end > header) && ISBLANK(*end))
  191. *end-- = 0; /* null-terminate */
  192. return CURLE_OK;
  193. }
  194. /*
  195. * Curl_headers_push() gets passed a full HTTP header to store. It gets called
  196. * immediately before the header callback. The header is CRLF, CR or LF
  197. * terminated.
  198. */
  199. CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
  200. size_t hlen, /* length of header */
  201. unsigned char type)
  202. {
  203. char *value = NULL;
  204. char *name = NULL;
  205. struct Curl_header_store *hs;
  206. CURLcode result = CURLE_OUT_OF_MEMORY;
  207. const size_t ilen = hlen;
  208. if((header[0] == '\r') || (header[0] == '\n'))
  209. /* ignore the body separator */
  210. return CURLE_OK;
  211. /* trim off newline characters */
  212. if(hlen && (header[hlen - 1] == '\n'))
  213. hlen--;
  214. if(hlen && (header[hlen - 1] == '\r'))
  215. hlen--;
  216. if(hlen == ilen)
  217. /* neither CR nor LF as terminator is not a valid header */
  218. return CURLE_WEIRD_SERVER_REPLY;
  219. if(ISBLANK(header[0])) {
  220. /* pass leading blanks */
  221. while(hlen && ISBLANK(*header)) {
  222. header++;
  223. hlen--;
  224. }
  225. if(!hlen)
  226. return CURLE_WEIRD_SERVER_REPLY;
  227. }
  228. if(Curl_llist_count(&data->state.httphdrs) >= MAX_HTTP_RESP_HEADER_COUNT) {
  229. failf(data, "Too many response headers, %d is max",
  230. MAX_HTTP_RESP_HEADER_COUNT);
  231. return CURLE_TOO_LARGE;
  232. }
  233. hs = curlx_calloc(1, sizeof(*hs) + hlen);
  234. if(!hs)
  235. return CURLE_OUT_OF_MEMORY;
  236. memcpy(hs->buffer, header, hlen);
  237. hs->buffer[hlen] = 0; /* null-terminate */
  238. result = namevalue(hs->buffer, hlen, type, &name, &value);
  239. if(!result) {
  240. hs->name = name;
  241. hs->value = value;
  242. hs->type = type;
  243. hs->request = data->state.requests;
  244. /* insert this node into the list of headers */
  245. Curl_llist_append(&data->state.httphdrs, hs, &hs->node);
  246. data->state.prevhead = hs;
  247. }
  248. else {
  249. failf(data, "Invalid response header");
  250. curlx_free(hs);
  251. }
  252. return result;
  253. }
  254. /*
  255. * Curl_headers_reset(). Reset the headers subsystem.
  256. */
  257. static void headers_reset(struct Curl_easy *data)
  258. {
  259. Curl_llist_init(&data->state.httphdrs, NULL);
  260. data->state.prevhead = NULL;
  261. }
  262. struct hds_cw_collect_ctx {
  263. struct Curl_cwriter super;
  264. };
  265. static CURLcode hds_cw_collect_write(struct Curl_easy *data,
  266. struct Curl_cwriter *writer, int type,
  267. const char *buf, size_t blen)
  268. {
  269. if((type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS)) {
  270. unsigned char htype = (unsigned char)
  271. (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT :
  272. (type & CLIENTWRITE_1XX ? CURLH_1XX :
  273. (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
  274. CURLH_HEADER)));
  275. CURLcode result = Curl_headers_push(data, buf, blen, htype);
  276. CURL_TRC_WRITE(data, "header_collect pushed(type=%x, len=%zu) -> %d",
  277. htype, blen, result);
  278. if(result)
  279. return result;
  280. }
  281. return Curl_cwriter_write(data, writer->next, type, buf, blen);
  282. }
  283. static const struct Curl_cwtype hds_cw_collect = {
  284. "hds-collect",
  285. NULL,
  286. Curl_cwriter_def_init,
  287. hds_cw_collect_write,
  288. Curl_cwriter_def_close,
  289. sizeof(struct hds_cw_collect_ctx)
  290. };
  291. CURLcode Curl_headers_init(struct Curl_easy *data)
  292. {
  293. struct Curl_cwriter *writer;
  294. CURLcode result;
  295. if(data->conn && (data->conn->handler->protocol & PROTO_FAMILY_HTTP)) {
  296. /* avoid installing it twice */
  297. if(Curl_cwriter_get_by_name(data, hds_cw_collect.name))
  298. return CURLE_OK;
  299. result = Curl_cwriter_create(&writer, data, &hds_cw_collect,
  300. CURL_CW_PROTOCOL);
  301. if(result)
  302. return result;
  303. result = Curl_cwriter_add(data, writer);
  304. if(result) {
  305. Curl_cwriter_free(data, writer);
  306. return result;
  307. }
  308. }
  309. return CURLE_OK;
  310. }
  311. /*
  312. * Curl_headers_cleanup(). Free all stored headers and associated memory.
  313. */
  314. CURLcode Curl_headers_cleanup(struct Curl_easy *data)
  315. {
  316. struct Curl_llist_node *e;
  317. struct Curl_llist_node *n;
  318. for(e = Curl_llist_head(&data->state.httphdrs); e; e = n) {
  319. struct Curl_header_store *hs = Curl_node_elem(e);
  320. n = Curl_node_next(e);
  321. curlx_free(hs);
  322. }
  323. headers_reset(data);
  324. return CURLE_OK;
  325. }
  326. #else /* HTTP-disabled builds below */
  327. CURLHcode curl_easy_header(CURL *easy,
  328. const char *name,
  329. size_t index,
  330. unsigned int origin,
  331. int request,
  332. struct curl_header **hout)
  333. {
  334. (void)easy;
  335. (void)name;
  336. (void)index;
  337. (void)origin;
  338. (void)request;
  339. (void)hout;
  340. return CURLHE_NOT_BUILT_IN;
  341. }
  342. struct curl_header *curl_easy_nextheader(CURL *easy,
  343. unsigned int type,
  344. int request,
  345. struct curl_header *prev)
  346. {
  347. (void)easy;
  348. (void)type;
  349. (void)request;
  350. (void)prev;
  351. return NULL;
  352. }
  353. #endif