dynhds.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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 "dynhds.h"
  26. #include "strcase.h"
  27. #ifdef USE_NGHTTP2
  28. #include <stdint.h>
  29. #include <nghttp2/nghttp2.h>
  30. #endif /* USE_NGHTTP2 */
  31. /* The last 2 #include files should be in this order */
  32. #include "curl_memory.h"
  33. #include "memdebug.h"
  34. static struct dynhds_entry *
  35. entry_new(const char *name, size_t namelen,
  36. const char *value, size_t valuelen, int opts)
  37. {
  38. struct dynhds_entry *e;
  39. char *p;
  40. DEBUGASSERT(name);
  41. DEBUGASSERT(value);
  42. e = calloc(1, sizeof(*e) + namelen + valuelen + 2);
  43. if(!e)
  44. return NULL;
  45. e->name = p = ((char *)e) + sizeof(*e);
  46. memcpy(p, name, namelen);
  47. e->namelen = namelen;
  48. e->value = p += namelen + 1; /* leave a \0 at the end of name */
  49. memcpy(p, value, valuelen);
  50. e->valuelen = valuelen;
  51. if(opts & DYNHDS_OPT_LOWERCASE)
  52. Curl_strntolower(e->name, e->name, e->namelen);
  53. return e;
  54. }
  55. static struct dynhds_entry *
  56. entry_append(struct dynhds_entry *e,
  57. const char *value, size_t valuelen)
  58. {
  59. struct dynhds_entry *e2;
  60. size_t valuelen2 = e->valuelen + 1 + valuelen;
  61. char *p;
  62. DEBUGASSERT(value);
  63. e2 = calloc(1, sizeof(*e) + e->namelen + valuelen2 + 2);
  64. if(!e2)
  65. return NULL;
  66. e2->name = p = ((char *)e2) + sizeof(*e2);
  67. memcpy(p, e->name, e->namelen);
  68. e2->namelen = e->namelen;
  69. e2->value = p += e->namelen + 1; /* leave a \0 at the end of name */
  70. memcpy(p, e->value, e->valuelen);
  71. p += e->valuelen;
  72. p[0] = ' ';
  73. memcpy(p + 1, value, valuelen);
  74. e2->valuelen = valuelen2;
  75. return e2;
  76. }
  77. static void entry_free(struct dynhds_entry *e)
  78. {
  79. free(e);
  80. }
  81. void Curl_dynhds_init(struct dynhds *dynhds, size_t max_entries,
  82. size_t max_strs_size)
  83. {
  84. DEBUGASSERT(dynhds);
  85. DEBUGASSERT(max_strs_size);
  86. dynhds->hds = NULL;
  87. dynhds->hds_len = dynhds->hds_allc = dynhds->strs_len = 0;
  88. dynhds->max_entries = max_entries;
  89. dynhds->max_strs_size = max_strs_size;
  90. dynhds->opts = 0;
  91. }
  92. void Curl_dynhds_free(struct dynhds *dynhds)
  93. {
  94. DEBUGASSERT(dynhds);
  95. if(dynhds->hds && dynhds->hds_len) {
  96. size_t i;
  97. DEBUGASSERT(dynhds->hds);
  98. for(i = 0; i < dynhds->hds_len; ++i) {
  99. entry_free(dynhds->hds[i]);
  100. }
  101. }
  102. Curl_safefree(dynhds->hds);
  103. dynhds->hds_len = dynhds->hds_allc = dynhds->strs_len = 0;
  104. }
  105. void Curl_dynhds_reset(struct dynhds *dynhds)
  106. {
  107. DEBUGASSERT(dynhds);
  108. if(dynhds->hds_len) {
  109. size_t i;
  110. DEBUGASSERT(dynhds->hds);
  111. for(i = 0; i < dynhds->hds_len; ++i) {
  112. entry_free(dynhds->hds[i]);
  113. dynhds->hds[i] = NULL;
  114. }
  115. }
  116. dynhds->hds_len = dynhds->strs_len = 0;
  117. }
  118. size_t Curl_dynhds_count(struct dynhds *dynhds)
  119. {
  120. return dynhds->hds_len;
  121. }
  122. void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts)
  123. {
  124. dynhds->opts = opts;
  125. }
  126. struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n)
  127. {
  128. DEBUGASSERT(dynhds);
  129. return (n < dynhds->hds_len) ? dynhds->hds[n] : NULL;
  130. }
  131. struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds, const char *name,
  132. size_t namelen)
  133. {
  134. size_t i;
  135. for(i = 0; i < dynhds->hds_len; ++i) {
  136. if(dynhds->hds[i]->namelen == namelen &&
  137. curl_strnequal(dynhds->hds[i]->name, name, namelen)) {
  138. return dynhds->hds[i];
  139. }
  140. }
  141. return NULL;
  142. }
  143. struct dynhds_entry *Curl_dynhds_cget(struct dynhds *dynhds, const char *name)
  144. {
  145. return Curl_dynhds_get(dynhds, name, strlen(name));
  146. }
  147. CURLcode Curl_dynhds_add(struct dynhds *dynhds,
  148. const char *name, size_t namelen,
  149. const char *value, size_t valuelen)
  150. {
  151. struct dynhds_entry *entry = NULL;
  152. CURLcode result = CURLE_OUT_OF_MEMORY;
  153. DEBUGASSERT(dynhds);
  154. if(dynhds->max_entries && dynhds->hds_len >= dynhds->max_entries)
  155. return CURLE_OUT_OF_MEMORY;
  156. if(dynhds->strs_len + namelen + valuelen > dynhds->max_strs_size)
  157. return CURLE_OUT_OF_MEMORY;
  158. entry = entry_new(name, namelen, value, valuelen, dynhds->opts);
  159. if(!entry)
  160. goto out;
  161. if(dynhds->hds_len + 1 >= dynhds->hds_allc) {
  162. size_t nallc = dynhds->hds_len + 16;
  163. struct dynhds_entry **nhds;
  164. if(dynhds->max_entries && nallc > dynhds->max_entries)
  165. nallc = dynhds->max_entries;
  166. nhds = calloc(nallc, sizeof(struct dynhds_entry *));
  167. if(!nhds)
  168. goto out;
  169. if(dynhds->hds) {
  170. memcpy(nhds, dynhds->hds,
  171. dynhds->hds_len * sizeof(struct dynhds_entry *));
  172. Curl_safefree(dynhds->hds);
  173. }
  174. dynhds->hds = nhds;
  175. dynhds->hds_allc = nallc;
  176. }
  177. dynhds->hds[dynhds->hds_len++] = entry;
  178. entry = NULL;
  179. dynhds->strs_len += namelen + valuelen;
  180. result = CURLE_OK;
  181. out:
  182. if(entry)
  183. entry_free(entry);
  184. return result;
  185. }
  186. CURLcode Curl_dynhds_cadd(struct dynhds *dynhds,
  187. const char *name, const char *value)
  188. {
  189. return Curl_dynhds_add(dynhds, name, strlen(name), value, strlen(value));
  190. }
  191. CURLcode Curl_dynhds_h1_add_line(struct dynhds *dynhds,
  192. const char *line, size_t line_len)
  193. {
  194. const char *p;
  195. const char *name;
  196. size_t namelen;
  197. const char *value;
  198. size_t valuelen, i;
  199. if(!line || !line_len)
  200. return CURLE_OK;
  201. if((line[0] == ' ') || (line[0] == '\t')) {
  202. struct dynhds_entry *e, *e2;
  203. /* header continuation, yikes! */
  204. if(!dynhds->hds_len)
  205. return CURLE_BAD_FUNCTION_ARGUMENT;
  206. while(line_len && ISBLANK(line[0])) {
  207. ++line;
  208. --line_len;
  209. }
  210. if(!line_len)
  211. return CURLE_BAD_FUNCTION_ARGUMENT;
  212. e = dynhds->hds[dynhds->hds_len-1];
  213. e2 = entry_append(e, line, line_len);
  214. if(!e2)
  215. return CURLE_OUT_OF_MEMORY;
  216. dynhds->hds[dynhds->hds_len-1] = e2;
  217. entry_free(e);
  218. return CURLE_OK;
  219. }
  220. else {
  221. p = memchr(line, ':', line_len);
  222. if(!p)
  223. return CURLE_BAD_FUNCTION_ARGUMENT;
  224. name = line;
  225. namelen = p - line;
  226. p++; /* move past the colon */
  227. for(i = namelen + 1; i < line_len; ++i, ++p) {
  228. if(!ISBLANK(*p))
  229. break;
  230. }
  231. value = p;
  232. valuelen = line_len - i;
  233. p = memchr(value, '\r', valuelen);
  234. if(!p)
  235. p = memchr(value, '\n', valuelen);
  236. if(p)
  237. valuelen = (size_t)(p - value);
  238. return Curl_dynhds_add(dynhds, name, namelen, value, valuelen);
  239. }
  240. }
  241. CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line)
  242. {
  243. return Curl_dynhds_h1_add_line(dynhds, line, line ? strlen(line) : 0);
  244. }
  245. #ifdef UNITTESTS
  246. /* used by unit2602.c */
  247. bool Curl_dynhds_contains(struct dynhds *dynhds,
  248. const char *name, size_t namelen)
  249. {
  250. return !!Curl_dynhds_get(dynhds, name, namelen);
  251. }
  252. bool Curl_dynhds_ccontains(struct dynhds *dynhds, const char *name)
  253. {
  254. return Curl_dynhds_contains(dynhds, name, strlen(name));
  255. }
  256. size_t Curl_dynhds_count_name(struct dynhds *dynhds,
  257. const char *name, size_t namelen)
  258. {
  259. size_t n = 0;
  260. if(dynhds->hds_len) {
  261. size_t i;
  262. for(i = 0; i < dynhds->hds_len; ++i) {
  263. if((namelen == dynhds->hds[i]->namelen) &&
  264. curl_strnequal(name, dynhds->hds[i]->name, namelen))
  265. ++n;
  266. }
  267. }
  268. return n;
  269. }
  270. size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name)
  271. {
  272. return Curl_dynhds_count_name(dynhds, name, strlen(name));
  273. }
  274. CURLcode Curl_dynhds_set(struct dynhds *dynhds,
  275. const char *name, size_t namelen,
  276. const char *value, size_t valuelen)
  277. {
  278. Curl_dynhds_remove(dynhds, name, namelen);
  279. return Curl_dynhds_add(dynhds, name, namelen, value, valuelen);
  280. }
  281. size_t Curl_dynhds_remove(struct dynhds *dynhds,
  282. const char *name, size_t namelen)
  283. {
  284. size_t n = 0;
  285. if(dynhds->hds_len) {
  286. size_t i, len;
  287. for(i = 0; i < dynhds->hds_len; ++i) {
  288. if((namelen == dynhds->hds[i]->namelen) &&
  289. curl_strnequal(name, dynhds->hds[i]->name, namelen)) {
  290. ++n;
  291. --dynhds->hds_len;
  292. dynhds->strs_len -= (dynhds->hds[i]->namelen +
  293. dynhds->hds[i]->valuelen);
  294. entry_free(dynhds->hds[i]);
  295. len = dynhds->hds_len - i; /* remaining entries */
  296. if(len) {
  297. memmove(&dynhds->hds[i], &dynhds->hds[i + 1],
  298. len * sizeof(dynhds->hds[i]));
  299. }
  300. --i; /* do this index again */
  301. }
  302. }
  303. }
  304. return n;
  305. }
  306. size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name)
  307. {
  308. return Curl_dynhds_remove(dynhds, name, strlen(name));
  309. }
  310. #endif
  311. CURLcode Curl_dynhds_h1_dprint(struct dynhds *dynhds, struct dynbuf *dbuf)
  312. {
  313. CURLcode result = CURLE_OK;
  314. size_t i;
  315. if(!dynhds->hds_len)
  316. return result;
  317. for(i = 0; i < dynhds->hds_len; ++i) {
  318. result = curlx_dyn_addf(dbuf, "%.*s: %.*s\r\n",
  319. (int)dynhds->hds[i]->namelen, dynhds->hds[i]->name,
  320. (int)dynhds->hds[i]->valuelen,
  321. dynhds->hds[i]->value);
  322. if(result)
  323. break;
  324. }
  325. return result;
  326. }
  327. #ifdef USE_NGHTTP2
  328. nghttp2_nv *Curl_dynhds_to_nva(struct dynhds *dynhds, size_t *pcount)
  329. {
  330. nghttp2_nv *nva = calloc(1, sizeof(nghttp2_nv) * dynhds->hds_len);
  331. size_t i;
  332. *pcount = 0;
  333. if(!nva)
  334. return NULL;
  335. for(i = 0; i < dynhds->hds_len; ++i) {
  336. struct dynhds_entry *e = dynhds->hds[i];
  337. DEBUGASSERT(e);
  338. nva[i].name = (unsigned char *)e->name;
  339. nva[i].namelen = e->namelen;
  340. nva[i].value = (unsigned char *)e->value;
  341. nva[i].valuelen = e->valuelen;
  342. nva[i].flags = NGHTTP2_NV_FLAG_NONE;
  343. }
  344. *pcount = dynhds->hds_len;
  345. return nva;
  346. }
  347. #endif /* USE_NGHTTP2 */