httpread.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. /*
  2. * httpread - Manage reading file(s) from HTTP/TCP socket
  3. * Author: Ted Merrill
  4. * Copyright 2008 Atheros Communications
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * Alternatively, this software may be distributed under the terms of BSD
  11. * license.
  12. *
  13. * See README and COPYING for more details.
  14. *
  15. * The files are buffered via internal callbacks from eloop, then presented to
  16. * an application callback routine when completely read into memory. May also
  17. * be used if no file is expected but just to get the header, including HTTP
  18. * replies (e.g. HTTP/1.1 200 OK etc.).
  19. *
  20. * This does not attempt to be an optimally efficient implementation, but does
  21. * attempt to be of reasonably small size and memory consumption; assuming that
  22. * only small files are to be read. A maximum file size is provided by
  23. * application and enforced.
  24. *
  25. * It is assumed that the application does not expect any of the following:
  26. * -- transfer encoding other than chunked
  27. * -- trailer fields
  28. * It is assumed that, even if the other side requested that the connection be
  29. * kept open, that we will close it (thus HTTP messages sent by application
  30. * should have the connection closed field); this is allowed by HTTP/1.1 and
  31. * simplifies things for us.
  32. *
  33. * Other limitations:
  34. * -- HTTP header may not exceed a hard-coded size.
  35. *
  36. * Notes:
  37. * This code would be massively simpler without some of the new features of
  38. * HTTP/1.1, especially chunked data.
  39. */
  40. #include "includes.h"
  41. #include "common.h"
  42. #include "eloop.h"
  43. #include "httpread.h"
  44. /* Tunable parameters */
  45. #define HTTPREAD_READBUF_SIZE 1024 /* read in chunks of this size */
  46. #define HTTPREAD_HEADER_MAX_SIZE 4096 /* max allowed for headers */
  47. #define HTTPREAD_BODYBUF_DELTA 4096 /* increase allocation by this */
  48. #if 0
  49. /* httpread_debug -- set this global variable > 0 e.g. from debugger
  50. * to enable debugs (larger numbers for more debugs)
  51. * Make this a #define of 0 to eliminate the debugging code.
  52. */
  53. int httpread_debug = 99;
  54. #else
  55. #define httpread_debug 0 /* eliminates even the debugging code */
  56. #endif
  57. /* control instance -- actual definition (opaque to application)
  58. */
  59. struct httpread {
  60. /* information from creation */
  61. int sd; /* descriptor of TCP socket to read from */
  62. void (*cb)(struct httpread *handle, void *cookie,
  63. enum httpread_event e); /* call on event */
  64. void *cookie; /* pass to callback */
  65. int max_bytes; /* maximum file size else abort it */
  66. int timeout_seconds; /* 0 or total duration timeout period */
  67. /* dynamically used information follows */
  68. int sd_registered; /* nonzero if we need to unregister socket */
  69. int to_registered; /* nonzero if we need to unregister timeout */
  70. int got_hdr; /* nonzero when header is finalized */
  71. char hdr[HTTPREAD_HEADER_MAX_SIZE+1]; /* headers stored here */
  72. int hdr_nbytes;
  73. enum httpread_hdr_type hdr_type;
  74. int version; /* 1 if we've seen 1.1 */
  75. int reply_code; /* for type REPLY, e.g. 200 for HTTP/1.1 200 OK */
  76. int got_content_length; /* true if we know content length for sure */
  77. int content_length; /* body length, iff got_content_length */
  78. int chunked; /* nonzero for chunked data */
  79. char *uri;
  80. int got_body; /* nonzero when body is finalized */
  81. char *body;
  82. int body_nbytes;
  83. int body_alloc_nbytes; /* amount allocated */
  84. int got_file; /* here when we are done */
  85. /* The following apply if data is chunked: */
  86. int in_chunk_data; /* 0=in/at header, 1=in the data or tail*/
  87. int chunk_start; /* offset in body of chunk hdr or data */
  88. int chunk_size; /* data of chunk (not hdr or ending CRLF)*/
  89. int in_trailer; /* in header fields after data (chunked only)*/
  90. enum trailer_state {
  91. trailer_line_begin = 0,
  92. trailer_empty_cr, /* empty line + CR */
  93. trailer_nonempty,
  94. trailer_nonempty_cr,
  95. } trailer_state;
  96. };
  97. /* Check words for equality, where words consist of graphical characters
  98. * delimited by whitespace
  99. * Returns nonzero if "equal" doing case insensitive comparison.
  100. */
  101. static int word_eq(char *s1, char *s2)
  102. {
  103. int c1;
  104. int c2;
  105. int end1 = 0;
  106. int end2 = 0;
  107. for (;;) {
  108. c1 = *s1++;
  109. c2 = *s2++;
  110. if (isalpha(c1) && isupper(c1))
  111. c1 = tolower(c1);
  112. if (isalpha(c2) && isupper(c2))
  113. c2 = tolower(c2);
  114. end1 = !isgraph(c1);
  115. end2 = !isgraph(c2);
  116. if (end1 || end2 || c1 != c2)
  117. break;
  118. }
  119. return end1 && end2; /* reached end of both words? */
  120. }
  121. /* convert hex to binary
  122. * Requires that c have been previously tested true with isxdigit().
  123. */
  124. static int hex_value(int c)
  125. {
  126. if (isdigit(c))
  127. return c - '0';
  128. if (islower(c))
  129. return 10 + c - 'a';
  130. return 10 + c - 'A';
  131. }
  132. static void httpread_timeout_handler(void *eloop_data, void *user_ctx);
  133. /* httpread_destroy -- if h is non-NULL, clean up
  134. * This must eventually be called by the application following
  135. * call of the application's callback and may be called
  136. * earlier if desired.
  137. */
  138. void httpread_destroy(struct httpread *h)
  139. {
  140. if (httpread_debug >= 10)
  141. wpa_printf(MSG_DEBUG, "ENTER httpread_destroy(%p)", h);
  142. if (!h)
  143. return;
  144. if (h->to_registered)
  145. eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
  146. h->to_registered = 0;
  147. if (h->sd_registered)
  148. eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
  149. h->sd_registered = 0;
  150. os_free(h->body);
  151. os_free(h->uri);
  152. os_memset(h, 0, sizeof(*h)); /* aid debugging */
  153. h->sd = -1; /* aid debugging */
  154. os_free(h);
  155. }
  156. /* httpread_timeout_handler -- called on excessive total duration
  157. */
  158. static void httpread_timeout_handler(void *eloop_data, void *user_ctx)
  159. {
  160. struct httpread *h = user_ctx;
  161. wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h);
  162. h->to_registered = 0; /* is self-cancelling */
  163. (*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT);
  164. }
  165. /* Analyze options only so far as is needed to correctly obtain the file.
  166. * The application can look at the raw header to find other options.
  167. */
  168. static int httpread_hdr_option_analyze(
  169. struct httpread *h,
  170. char *hbp /* pointer to current line in header buffer */
  171. )
  172. {
  173. if (word_eq(hbp, "CONTENT-LENGTH:")) {
  174. while (isgraph(*hbp))
  175. hbp++;
  176. while (*hbp == ' ' || *hbp == '\t')
  177. hbp++;
  178. if (!isdigit(*hbp))
  179. return -1;
  180. h->content_length = atol(hbp);
  181. h->got_content_length = 1;
  182. return 0;
  183. }
  184. if (word_eq(hbp, "TRANSFER_ENCODING:") ||
  185. word_eq(hbp, "TRANSFER-ENCODING:")) {
  186. while (isgraph(*hbp))
  187. hbp++;
  188. while (*hbp == ' ' || *hbp == '\t')
  189. hbp++;
  190. /* There should (?) be no encodings of interest
  191. * other than chunked...
  192. */
  193. if (word_eq(hbp, "CHUNKED")) {
  194. h->chunked = 1;
  195. h->in_chunk_data = 0;
  196. /* ignore possible ;<parameters> */
  197. }
  198. return 0;
  199. }
  200. /* skip anything we don't know, which is a lot */
  201. return 0;
  202. }
  203. static int httpread_hdr_analyze(struct httpread *h)
  204. {
  205. char *hbp = h->hdr; /* pointer into h->hdr */
  206. int standard_first_line = 1;
  207. /* First line is special */
  208. h->hdr_type = HTTPREAD_HDR_TYPE_UNKNOWN;
  209. if (!isgraph(*hbp))
  210. goto bad;
  211. if (os_strncmp(hbp, "HTTP/", 5) == 0) {
  212. h->hdr_type = HTTPREAD_HDR_TYPE_REPLY;
  213. standard_first_line = 0;
  214. hbp += 5;
  215. if (hbp[0] == '1' && hbp[1] == '.' &&
  216. isdigit(hbp[2]) && hbp[2] != '0')
  217. h->version = 1;
  218. while (isgraph(*hbp))
  219. hbp++;
  220. while (*hbp == ' ' || *hbp == '\t')
  221. hbp++;
  222. if (!isdigit(*hbp))
  223. goto bad;
  224. h->reply_code = atol(hbp);
  225. } else if (word_eq(hbp, "GET"))
  226. h->hdr_type = HTTPREAD_HDR_TYPE_GET;
  227. else if (word_eq(hbp, "HEAD"))
  228. h->hdr_type = HTTPREAD_HDR_TYPE_HEAD;
  229. else if (word_eq(hbp, "POST"))
  230. h->hdr_type = HTTPREAD_HDR_TYPE_POST;
  231. else if (word_eq(hbp, "PUT"))
  232. h->hdr_type = HTTPREAD_HDR_TYPE_PUT;
  233. else if (word_eq(hbp, "DELETE"))
  234. h->hdr_type = HTTPREAD_HDR_TYPE_DELETE;
  235. else if (word_eq(hbp, "TRACE"))
  236. h->hdr_type = HTTPREAD_HDR_TYPE_TRACE;
  237. else if (word_eq(hbp, "CONNECT"))
  238. h->hdr_type = HTTPREAD_HDR_TYPE_CONNECT;
  239. else if (word_eq(hbp, "NOTIFY"))
  240. h->hdr_type = HTTPREAD_HDR_TYPE_NOTIFY;
  241. else if (word_eq(hbp, "M-SEARCH"))
  242. h->hdr_type = HTTPREAD_HDR_TYPE_M_SEARCH;
  243. else if (word_eq(hbp, "M-POST"))
  244. h->hdr_type = HTTPREAD_HDR_TYPE_M_POST;
  245. else if (word_eq(hbp, "SUBSCRIBE"))
  246. h->hdr_type = HTTPREAD_HDR_TYPE_SUBSCRIBE;
  247. else if (word_eq(hbp, "UNSUBSCRIBE"))
  248. h->hdr_type = HTTPREAD_HDR_TYPE_UNSUBSCRIBE;
  249. else {
  250. }
  251. if (standard_first_line) {
  252. char *rawuri;
  253. char *uri;
  254. /* skip type */
  255. while (isgraph(*hbp))
  256. hbp++;
  257. while (*hbp == ' ' || *hbp == '\t')
  258. hbp++;
  259. /* parse uri.
  260. * Find length, allocate memory for translated
  261. * copy, then translate by changing %<hex><hex>
  262. * into represented value.
  263. */
  264. rawuri = hbp;
  265. while (isgraph(*hbp))
  266. hbp++;
  267. h->uri = os_malloc((hbp - rawuri) + 1);
  268. if (h->uri == NULL)
  269. goto bad;
  270. uri = h->uri;
  271. while (rawuri < hbp) {
  272. int c = *rawuri;
  273. if (c == '%' &&
  274. isxdigit(rawuri[1]) && isxdigit(rawuri[2])) {
  275. *uri++ = (hex_value(rawuri[1]) << 4) |
  276. hex_value(rawuri[2]);
  277. rawuri += 3;
  278. } else {
  279. *uri++ = c;
  280. rawuri++;
  281. }
  282. }
  283. *uri = 0; /* null terminate */
  284. while (isgraph(*hbp))
  285. hbp++;
  286. while (*hbp == ' ' || *hbp == '\t')
  287. hbp++;
  288. /* get version */
  289. if (0 == strncmp(hbp, "HTTP/", 5)) {
  290. hbp += 5;
  291. if (hbp[0] == '1' && hbp[1] == '.' &&
  292. isdigit(hbp[2]) && hbp[2] != '0')
  293. h->version = 1;
  294. }
  295. }
  296. /* skip rest of line */
  297. while (*hbp)
  298. if (*hbp++ == '\n')
  299. break;
  300. /* Remainder of lines are options, in any order;
  301. * or empty line to terminate
  302. */
  303. for (;;) {
  304. /* Empty line to terminate */
  305. if (hbp[0] == '\n' ||
  306. (hbp[0] == '\r' && hbp[1] == '\n'))
  307. break;
  308. if (!isgraph(*hbp))
  309. goto bad;
  310. if (httpread_hdr_option_analyze(h, hbp))
  311. goto bad;
  312. /* skip line */
  313. while (*hbp)
  314. if (*hbp++ == '\n')
  315. break;
  316. }
  317. /* chunked overrides content-length always */
  318. if (h->chunked)
  319. h->got_content_length = 0;
  320. /* For some types, we should not try to read a body
  321. * This is in addition to the application determining
  322. * that we should not read a body.
  323. */
  324. switch (h->hdr_type) {
  325. case HTTPREAD_HDR_TYPE_REPLY:
  326. /* Some codes can have a body and some not.
  327. * For now, just assume that any other than 200
  328. * do not...
  329. */
  330. if (h->reply_code != 200)
  331. h->max_bytes = 0;
  332. break;
  333. case HTTPREAD_HDR_TYPE_GET:
  334. case HTTPREAD_HDR_TYPE_HEAD:
  335. /* in practice it appears that it is assumed
  336. * that GETs have a body length of 0... ?
  337. */
  338. if (h->chunked == 0 && h->got_content_length == 0)
  339. h->max_bytes = 0;
  340. break;
  341. case HTTPREAD_HDR_TYPE_POST:
  342. case HTTPREAD_HDR_TYPE_PUT:
  343. case HTTPREAD_HDR_TYPE_DELETE:
  344. case HTTPREAD_HDR_TYPE_TRACE:
  345. case HTTPREAD_HDR_TYPE_CONNECT:
  346. case HTTPREAD_HDR_TYPE_NOTIFY:
  347. case HTTPREAD_HDR_TYPE_M_SEARCH:
  348. case HTTPREAD_HDR_TYPE_M_POST:
  349. case HTTPREAD_HDR_TYPE_SUBSCRIBE:
  350. case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
  351. default:
  352. break;
  353. }
  354. return 0;
  355. bad:
  356. /* Error */
  357. return -1;
  358. }
  359. /* httpread_read_handler -- called when socket ready to read
  360. *
  361. * Note: any extra data we read past end of transmitted file is ignored;
  362. * if we were to support keeping connections open for multiple files then
  363. * this would have to be addressed.
  364. */
  365. static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx)
  366. {
  367. struct httpread *h = sock_ctx;
  368. int nread;
  369. char *rbp; /* pointer into read buffer */
  370. char *hbp; /* pointer into header buffer */
  371. char *bbp; /* pointer into body buffer */
  372. char readbuf[HTTPREAD_READBUF_SIZE]; /* temp use to read into */
  373. if (httpread_debug >= 20)
  374. wpa_printf(MSG_DEBUG, "ENTER httpread_read_handler(%p)", h);
  375. /* read some at a time, then search for the interal
  376. * boundaries between header and data and etc.
  377. */
  378. nread = read(h->sd, readbuf, sizeof(readbuf));
  379. if (nread < 0)
  380. goto bad;
  381. if (nread == 0) {
  382. /* end of transmission... this may be normal
  383. * or may be an error... in some cases we can't
  384. * tell which so we must assume it is normal then.
  385. */
  386. if (!h->got_hdr) {
  387. /* Must at least have completed header */
  388. wpa_printf(MSG_DEBUG, "httpread premature eof(%p)", h);
  389. goto bad;
  390. }
  391. if (h->chunked || h->got_content_length) {
  392. /* Premature EOF; e.g. dropped connection */
  393. wpa_printf(MSG_DEBUG,
  394. "httpread premature eof(%p) %d/%d",
  395. h, h->body_nbytes,
  396. h->content_length);
  397. goto bad;
  398. }
  399. /* No explicit length, hopefully we have all the data
  400. * although dropped connections can cause false
  401. * end
  402. */
  403. if (httpread_debug >= 10)
  404. wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h);
  405. h->got_body = 1;
  406. goto got_file;
  407. }
  408. rbp = readbuf;
  409. /* Header consists of text lines (terminated by both CR and LF)
  410. * and an empty line (CR LF only).
  411. */
  412. if (!h->got_hdr) {
  413. hbp = h->hdr + h->hdr_nbytes;
  414. /* add to headers until:
  415. * -- we run out of data in read buffer
  416. * -- or, we run out of header buffer room
  417. * -- or, we get double CRLF in headers
  418. */
  419. for (;;) {
  420. if (nread == 0)
  421. goto get_more;
  422. if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) {
  423. goto bad;
  424. }
  425. *hbp++ = *rbp++;
  426. nread--;
  427. h->hdr_nbytes++;
  428. if (h->hdr_nbytes >= 4 &&
  429. hbp[-1] == '\n' &&
  430. hbp[-2] == '\r' &&
  431. hbp[-3] == '\n' &&
  432. hbp[-4] == '\r' ) {
  433. h->got_hdr = 1;
  434. *hbp = 0; /* null terminate */
  435. break;
  436. }
  437. }
  438. /* here we've just finished reading the header */
  439. if (httpread_hdr_analyze(h)) {
  440. wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h);
  441. goto bad;
  442. }
  443. if (h->max_bytes == 0) {
  444. if (httpread_debug >= 10)
  445. wpa_printf(MSG_DEBUG,
  446. "httpread no body hdr end(%p)", h);
  447. goto got_file;
  448. }
  449. if (h->got_content_length && h->content_length == 0) {
  450. if (httpread_debug >= 10)
  451. wpa_printf(MSG_DEBUG,
  452. "httpread zero content length(%p)",
  453. h);
  454. goto got_file;
  455. }
  456. }
  457. /* Certain types of requests never have data and so
  458. * must be specially recognized.
  459. */
  460. if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) ||
  461. !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) ||
  462. !os_strncasecmp(h->hdr, "HEAD", 4) ||
  463. !os_strncasecmp(h->hdr, "GET", 3)) {
  464. if (!h->got_body) {
  465. if (httpread_debug >= 10)
  466. wpa_printf(MSG_DEBUG,
  467. "httpread NO BODY for sp. type");
  468. }
  469. h->got_body = 1;
  470. goto got_file;
  471. }
  472. /* Data can be just plain binary data, or if "chunked"
  473. * consists of chunks each with a header, ending with
  474. * an ending header.
  475. */
  476. if (nread == 0)
  477. goto get_more;
  478. if (!h->got_body) {
  479. /* Here to get (more of) body */
  480. /* ensure we have enough room for worst case for body
  481. * plus a null termination character
  482. */
  483. if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) {
  484. char *new_body;
  485. int new_alloc_nbytes;
  486. if (h->body_nbytes >= h->max_bytes)
  487. goto bad;
  488. new_alloc_nbytes = h->body_alloc_nbytes +
  489. HTTPREAD_BODYBUF_DELTA;
  490. /* For content-length case, the first time
  491. * through we allocate the whole amount
  492. * we need.
  493. */
  494. if (h->got_content_length &&
  495. new_alloc_nbytes < (h->content_length + 1))
  496. new_alloc_nbytes = h->content_length + 1;
  497. if ((new_body = os_realloc(h->body, new_alloc_nbytes))
  498. == NULL)
  499. goto bad;
  500. h->body = new_body;
  501. h->body_alloc_nbytes = new_alloc_nbytes;
  502. }
  503. /* add bytes */
  504. bbp = h->body + h->body_nbytes;
  505. for (;;) {
  506. int ncopy;
  507. /* See if we need to stop */
  508. if (h->chunked && h->in_chunk_data == 0) {
  509. /* in chunk header */
  510. char *cbp = h->body + h->chunk_start;
  511. if (bbp-cbp >= 2 && bbp[-2] == '\r' &&
  512. bbp[-1] == '\n') {
  513. /* end of chunk hdr line */
  514. /* hdr line consists solely
  515. * of a hex numeral and CFLF
  516. */
  517. if (!isxdigit(*cbp))
  518. goto bad;
  519. h->chunk_size = strtoul(cbp, NULL, 16);
  520. /* throw away chunk header
  521. * so we have only real data
  522. */
  523. h->body_nbytes = h->chunk_start;
  524. bbp = cbp;
  525. if (h->chunk_size == 0) {
  526. /* end of chunking */
  527. /* trailer follows */
  528. h->in_trailer = 1;
  529. if (httpread_debug >= 20)
  530. wpa_printf(
  531. MSG_DEBUG,
  532. "httpread end chunks(%p)", h);
  533. break;
  534. }
  535. h->in_chunk_data = 1;
  536. /* leave chunk_start alone */
  537. }
  538. } else if (h->chunked) {
  539. /* in chunk data */
  540. if ((h->body_nbytes - h->chunk_start) ==
  541. (h->chunk_size + 2)) {
  542. /* end of chunk reached,
  543. * new chunk starts
  544. */
  545. /* check chunk ended w/ CRLF
  546. * which we'll throw away
  547. */
  548. if (bbp[-1] == '\n' &&
  549. bbp[-2] == '\r') {
  550. } else
  551. goto bad;
  552. h->body_nbytes -= 2;
  553. bbp -= 2;
  554. h->chunk_start = h->body_nbytes;
  555. h->in_chunk_data = 0;
  556. h->chunk_size = 0; /* just in case */
  557. }
  558. } else if (h->got_content_length &&
  559. h->body_nbytes >= h->content_length) {
  560. h->got_body = 1;
  561. if (httpread_debug >= 10)
  562. wpa_printf(
  563. MSG_DEBUG,
  564. "httpread got content(%p)", h);
  565. goto got_file;
  566. }
  567. if (nread <= 0)
  568. break;
  569. /* Now transfer. Optimize using memcpy where we can. */
  570. if (h->chunked && h->in_chunk_data) {
  571. /* copy up to remainder of chunk data
  572. * plus the required CR+LF at end
  573. */
  574. ncopy = (h->chunk_start + h->chunk_size + 2) -
  575. h->body_nbytes;
  576. } else if (h->chunked) {
  577. /*in chunk header -- don't optimize */
  578. *bbp++ = *rbp++;
  579. nread--;
  580. h->body_nbytes++;
  581. continue;
  582. } else if (h->got_content_length) {
  583. ncopy = h->content_length - h->body_nbytes;
  584. } else {
  585. ncopy = nread;
  586. }
  587. /* Note: should never be 0 */
  588. if (ncopy > nread)
  589. ncopy = nread;
  590. os_memcpy(bbp, rbp, ncopy);
  591. bbp += ncopy;
  592. h->body_nbytes += ncopy;
  593. rbp += ncopy;
  594. nread -= ncopy;
  595. } /* body copy loop */
  596. } /* !got_body */
  597. if (h->chunked && h->in_trailer) {
  598. /* If "chunked" then there is always a trailer,
  599. * consisting of zero or more non-empty lines
  600. * ending with CR LF and then an empty line w/ CR LF.
  601. * We do NOT support trailers except to skip them --
  602. * this is supported (generally) by the http spec.
  603. */
  604. bbp = h->body + h->body_nbytes;
  605. for (;;) {
  606. int c;
  607. if (nread <= 0)
  608. break;
  609. c = *rbp++;
  610. nread--;
  611. switch (h->trailer_state) {
  612. case trailer_line_begin:
  613. if (c == '\r')
  614. h->trailer_state = trailer_empty_cr;
  615. else
  616. h->trailer_state = trailer_nonempty;
  617. break;
  618. case trailer_empty_cr:
  619. /* end empty line */
  620. if (c == '\n') {
  621. h->trailer_state = trailer_line_begin;
  622. h->in_trailer = 0;
  623. if (httpread_debug >= 10)
  624. wpa_printf(
  625. MSG_DEBUG,
  626. "httpread got content(%p)", h);
  627. h->got_body = 1;
  628. goto got_file;
  629. }
  630. h->trailer_state = trailer_nonempty;
  631. break;
  632. case trailer_nonempty:
  633. if (c == '\r')
  634. h->trailer_state = trailer_nonempty_cr;
  635. break;
  636. case trailer_nonempty_cr:
  637. if (c == '\n')
  638. h->trailer_state = trailer_line_begin;
  639. else
  640. h->trailer_state = trailer_nonempty;
  641. break;
  642. }
  643. }
  644. }
  645. goto get_more;
  646. bad:
  647. /* Error */
  648. wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h);
  649. (*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR);
  650. return;
  651. get_more:
  652. return;
  653. got_file:
  654. if (httpread_debug >= 10)
  655. wpa_printf(MSG_DEBUG,
  656. "httpread got file %d bytes type %d",
  657. h->body_nbytes, h->hdr_type);
  658. /* Null terminate for convenience of some applications */
  659. if (h->body)
  660. h->body[h->body_nbytes] = 0; /* null terminate */
  661. h->got_file = 1;
  662. /* Assume that we do NOT support keeping connection alive,
  663. * and just in case somehow we don't get destroyed right away,
  664. * unregister now.
  665. */
  666. if (h->sd_registered)
  667. eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
  668. h->sd_registered = 0;
  669. /* The application can destroy us whenever they feel like...
  670. * cancel timeout.
  671. */
  672. if (h->to_registered)
  673. eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
  674. h->to_registered = 0;
  675. (*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY);
  676. }
  677. /* httpread_create -- start a new reading session making use of eloop.
  678. * The new instance will use the socket descriptor for reading (until
  679. * it gets a file and not after) but will not close the socket, even
  680. * when the instance is destroyed (the application must do that).
  681. * Return NULL on error.
  682. *
  683. * Provided that httpread_create successfully returns a handle,
  684. * the callback fnc is called to handle httpread_event events.
  685. * The caller should do destroy on any errors or unknown events.
  686. *
  687. * Pass max_bytes == 0 to not read body at all (required for e.g.
  688. * reply to HEAD request).
  689. */
  690. struct httpread * httpread_create(
  691. int sd, /* descriptor of TCP socket to read from */
  692. void (*cb)(struct httpread *handle, void *cookie,
  693. enum httpread_event e), /* call on event */
  694. void *cookie, /* pass to callback */
  695. int max_bytes, /* maximum body size else abort it */
  696. int timeout_seconds /* 0; or total duration timeout period */
  697. )
  698. {
  699. struct httpread *h = NULL;
  700. h = os_zalloc(sizeof(*h));
  701. if (h == NULL)
  702. goto fail;
  703. h->sd = sd;
  704. h->cb = cb;
  705. h->cookie = cookie;
  706. h->max_bytes = max_bytes;
  707. h->timeout_seconds = timeout_seconds;
  708. if (timeout_seconds > 0) {
  709. if (eloop_register_timeout(timeout_seconds, 0,
  710. httpread_timeout_handler,
  711. NULL, h)) {
  712. /* No way to recover (from malloc failure) */
  713. goto fail;
  714. }
  715. h->to_registered = 1;
  716. }
  717. if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler,
  718. NULL, h)) {
  719. /* No way to recover (from malloc failure) */
  720. goto fail;
  721. }
  722. h->sd_registered = 1;
  723. return h;
  724. fail:
  725. /* Error */
  726. httpread_destroy(h);
  727. return NULL;
  728. }
  729. /* httpread_hdr_type_get -- When file is ready, returns header type. */
  730. enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h)
  731. {
  732. return h->hdr_type;
  733. }
  734. /* httpread_uri_get -- When file is ready, uri_get returns (translated) URI
  735. * or possibly NULL (which would be an error).
  736. */
  737. char * httpread_uri_get(struct httpread *h)
  738. {
  739. return h->uri;
  740. }
  741. /* httpread_reply_code_get -- When reply is ready, returns reply code */
  742. int httpread_reply_code_get(struct httpread *h)
  743. {
  744. return h->reply_code;
  745. }
  746. /* httpread_length_get -- When file is ready, returns file length. */
  747. int httpread_length_get(struct httpread *h)
  748. {
  749. return h->body_nbytes;
  750. }
  751. /* httpread_data_get -- When file is ready, returns file content
  752. * with null byte appened.
  753. * Might return NULL in some error condition.
  754. */
  755. void * httpread_data_get(struct httpread *h)
  756. {
  757. return h->body ? h->body : "";
  758. }
  759. /* httpread_hdr_get -- When file is ready, returns header content
  760. * with null byte appended.
  761. * Might return NULL in some error condition.
  762. */
  763. char * httpread_hdr_get(struct httpread *h)
  764. {
  765. return h->hdr;
  766. }
  767. /* httpread_hdr_line_get -- When file is ready, returns pointer
  768. * to line within header content matching the given tag
  769. * (after the tag itself and any spaces/tabs).
  770. *
  771. * The tag should end with a colon for reliable matching.
  772. *
  773. * If not found, returns NULL;
  774. */
  775. char * httpread_hdr_line_get(struct httpread *h, const char *tag)
  776. {
  777. int tag_len = os_strlen(tag);
  778. char *hdr = h->hdr;
  779. hdr = os_strchr(hdr, '\n');
  780. if (hdr == NULL)
  781. return NULL;
  782. hdr++;
  783. for (;;) {
  784. if (!os_strncasecmp(hdr, tag, tag_len)) {
  785. hdr += tag_len;
  786. while (*hdr == ' ' || *hdr == '\t')
  787. hdr++;
  788. return hdr;
  789. }
  790. hdr = os_strchr(hdr, '\n');
  791. if (hdr == NULL)
  792. return NULL;
  793. hdr++;
  794. }
  795. }