httpread.c 22 KB

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