18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * httpread - Manage reading file(s) from HTTP/TCP socket 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Author: Ted Merrill 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright 2008 Atheros Communications 58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 7c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The files are buffered via internal callbacks from eloop, then presented to 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * an application callback routine when completely read into memory. May also 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * be used if no file is expected but just to get the header, including HTTP 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * replies (e.g. HTTP/1.1 200 OK etc.). 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This does not attempt to be an optimally efficient implementation, but does 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * attempt to be of reasonably small size and memory consumption; assuming that 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * only small files are to be read. A maximum file size is provided by 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * application and enforced. 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * It is assumed that the application does not expect any of the following: 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- transfer encoding other than chunked 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- trailer fields 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * It is assumed that, even if the other side requested that the connection be 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * kept open, that we will close it (thus HTTP messages sent by application 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * should have the connection closed field); this is allowed by HTTP/1.1 and 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * simplifies things for us. 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Other limitations: 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- HTTP header may not exceed a hard-coded size. 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notes: 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This code would be massively simpler without some of the new features of 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * HTTP/1.1, especially chunked data. 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h" 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "httpread.h" 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Tunable parameters */ 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define HTTPREAD_READBUF_SIZE 1024 /* read in chunks of this size */ 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define HTTPREAD_HEADER_MAX_SIZE 4096 /* max allowed for headers */ 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define HTTPREAD_BODYBUF_DELTA 4096 /* increase allocation by this */ 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* control instance -- actual definition (opaque to application) 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct httpread { 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* information from creation */ 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sd; /* descriptor of TCP socket to read from */ 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void (*cb)(struct httpread *handle, void *cookie, 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum httpread_event e); /* call on event */ 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void *cookie; /* pass to callback */ 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int max_bytes; /* maximum file size else abort it */ 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int timeout_seconds; /* 0 or total duration timeout period */ 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* dynamically used information follows */ 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int got_hdr; /* nonzero when header is finalized */ 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char hdr[HTTPREAD_HEADER_MAX_SIZE+1]; /* headers stored here */ 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int hdr_nbytes; 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum httpread_hdr_type hdr_type; 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int version; /* 1 if we've seen 1.1 */ 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int reply_code; /* for type REPLY, e.g. 200 for HTTP/1.1 200 OK */ 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int got_content_length; /* true if we know content length for sure */ 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int content_length; /* body length, iff got_content_length */ 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int chunked; /* nonzero for chunked data */ 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *uri; 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int got_body; /* nonzero when body is finalized */ 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *body; 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int body_nbytes; 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int body_alloc_nbytes; /* amount allocated */ 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int got_file; /* here when we are done */ 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* The following apply if data is chunked: */ 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int in_chunk_data; /* 0=in/at header, 1=in the data or tail*/ 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int chunk_start; /* offset in body of chunk hdr or data */ 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int chunk_size; /* data of chunk (not hdr or ending CRLF)*/ 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int in_trailer; /* in header fields after data (chunked only)*/ 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum trailer_state { 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt trailer_line_begin = 0, 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt trailer_empty_cr, /* empty line + CR */ 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt trailer_nonempty, 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt trailer_nonempty_cr, 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } trailer_state; 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Check words for equality, where words consist of graphical characters 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * delimited by whitespace 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns nonzero if "equal" doing case insensitive comparison. 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int word_eq(char *s1, char *s2) 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int c1; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int c2; 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int end1 = 0; 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int end2 = 0; 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (;;) { 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c1 = *s1++; 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c2 = *s2++; 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (isalpha(c1) && isupper(c1)) 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c1 = tolower(c1); 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (isalpha(c2) && isupper(c2)) 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c2 = tolower(c2); 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end1 = !isgraph(c1); 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end2 = !isgraph(c2); 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end1 || end2 || c1 != c2) 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return end1 && end2; /* reached end of both words? */ 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void httpread_timeout_handler(void *eloop_data, void *user_ctx); 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* httpread_destroy -- if h is non-NULL, clean up 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This must eventually be called by the application following 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * call of the application's callback and may be called 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * earlier if desired. 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid httpread_destroy(struct httpread *h) 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 129cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, "httpread_destroy(%p)", h); 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!h) 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 133fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt eloop_cancel_timeout(httpread_timeout_handler, NULL, h); 134fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt eloop_unregister_sock(h->sd, EVENT_TYPE_READ); 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(h->body); 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(h->uri); 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(h, 0, sizeof(*h)); /* aid debugging */ 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->sd = -1; /* aid debugging */ 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(h); 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* httpread_timeout_handler -- called on excessive total duration 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void httpread_timeout_handler(void *eloop_data, void *user_ctx) 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct httpread *h = user_ctx; 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h); 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT); 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Analyze options only so far as is needed to correctly obtain the file. 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The application can look at the raw header to find other options. 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int httpread_hdr_option_analyze( 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct httpread *h, 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *hbp /* pointer to current line in header buffer */ 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ) 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (word_eq(hbp, "CONTENT-LENGTH:")) { 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (isgraph(*hbp)) 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp++; 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (*hbp == ' ' || *hbp == '\t') 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp++; 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!isdigit(*hbp)) 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->content_length = atol(hbp); 169cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt if (h->content_length < 0 || h->content_length > h->max_bytes) { 170cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 171cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt "httpread: Unacceptable Content-Length %d", 172cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt h->content_length); 173cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt return -1; 174cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt } 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->got_content_length = 1; 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (word_eq(hbp, "TRANSFER_ENCODING:") || 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt word_eq(hbp, "TRANSFER-ENCODING:")) { 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (isgraph(*hbp)) 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp++; 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (*hbp == ' ' || *hbp == '\t') 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp++; 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* There should (?) be no encodings of interest 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * other than chunked... 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (word_eq(hbp, "CHUNKED")) { 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->chunked = 1; 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->in_chunk_data = 0; 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* ignore possible ;<parameters> */ 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* skip anything we don't know, which is a lot */ 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int httpread_hdr_analyze(struct httpread *h) 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *hbp = h->hdr; /* pointer into h->hdr */ 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int standard_first_line = 1; 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* First line is special */ 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_UNKNOWN; 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!isgraph(*hbp)) 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_strncmp(hbp, "HTTP/", 5) == 0) { 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_REPLY; 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt standard_first_line = 0; 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp += 5; 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hbp[0] == '1' && hbp[1] == '.' && 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt isdigit(hbp[2]) && hbp[2] != '0') 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->version = 1; 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (isgraph(*hbp)) 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp++; 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (*hbp == ' ' || *hbp == '\t') 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp++; 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!isdigit(*hbp)) 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->reply_code = atol(hbp); 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (word_eq(hbp, "GET")) 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_GET; 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (word_eq(hbp, "HEAD")) 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_HEAD; 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (word_eq(hbp, "POST")) 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_POST; 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (word_eq(hbp, "PUT")) 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_PUT; 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (word_eq(hbp, "DELETE")) 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_DELETE; 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (word_eq(hbp, "TRACE")) 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_TRACE; 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (word_eq(hbp, "CONNECT")) 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_CONNECT; 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (word_eq(hbp, "NOTIFY")) 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_NOTIFY; 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (word_eq(hbp, "M-SEARCH")) 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_M_SEARCH; 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (word_eq(hbp, "M-POST")) 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_M_POST; 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (word_eq(hbp, "SUBSCRIBE")) 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_SUBSCRIBE; 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (word_eq(hbp, "UNSUBSCRIBE")) 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_type = HTTPREAD_HDR_TYPE_UNSUBSCRIBE; 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else { 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (standard_first_line) { 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *rawuri; 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *uri; 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* skip type */ 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (isgraph(*hbp)) 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp++; 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (*hbp == ' ' || *hbp == '\t') 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp++; 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* parse uri. 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Find length, allocate memory for translated 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * copy, then translate by changing %<hex><hex> 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * into represented value. 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rawuri = hbp; 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (isgraph(*hbp)) 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp++; 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->uri = os_malloc((hbp - rawuri) + 1); 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->uri == NULL) 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt uri = h->uri; 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (rawuri < hbp) { 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int c = *rawuri; 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (c == '%' && 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt isxdigit(rawuri[1]) && isxdigit(rawuri[2])) { 273fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt *uri++ = hex2byte(rawuri + 1); 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rawuri += 3; 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *uri++ = c; 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rawuri++; 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *uri = 0; /* null terminate */ 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (*hbp == ' ' || *hbp == '\t') 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp++; 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* get version */ 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (0 == strncmp(hbp, "HTTP/", 5)) { 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp += 5; 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hbp[0] == '1' && hbp[1] == '.' && 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt isdigit(hbp[2]) && hbp[2] != '0') 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->version = 1; 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* skip rest of line */ 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (*hbp) 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*hbp++ == '\n') 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Remainder of lines are options, in any order; 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * or empty line to terminate 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (;;) { 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Empty line to terminate */ 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hbp[0] == '\n' || 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (hbp[0] == '\r' && hbp[1] == '\n')) 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!isgraph(*hbp)) 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (httpread_hdr_option_analyze(h, hbp)) 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* skip line */ 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (*hbp) 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*hbp++ == '\n') 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* chunked overrides content-length always */ 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->chunked) 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->got_content_length = 0; 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* For some types, we should not try to read a body 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This is in addition to the application determining 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * that we should not read a body. 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (h->hdr_type) { 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_REPLY: 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Some codes can have a body and some not. 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * For now, just assume that any other than 200 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * do not... 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->reply_code != 200) 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->max_bytes = 0; 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_GET: 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_HEAD: 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* in practice it appears that it is assumed 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * that GETs have a body length of 0... ? 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->chunked == 0 && h->got_content_length == 0) 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->max_bytes = 0; 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_POST: 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_PUT: 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_DELETE: 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_TRACE: 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_CONNECT: 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_NOTIFY: 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_M_SEARCH: 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_M_POST: 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_SUBSCRIBE: 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HTTPREAD_HDR_TYPE_UNSUBSCRIBE: 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtbad: 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Error */ 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* httpread_read_handler -- called when socket ready to read 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Note: any extra data we read past end of transmitted file is ignored; 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * if we were to support keeping connections open for multiple files then 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * this would have to be addressed. 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx) 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct httpread *h = sock_ctx; 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int nread; 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *rbp; /* pointer into read buffer */ 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *hbp; /* pointer into header buffer */ 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *bbp; /* pointer into body buffer */ 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char readbuf[HTTPREAD_READBUF_SIZE]; /* temp use to read into */ 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* read some at a time, then search for the interal 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * boundaries between header and data and etc. 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 379cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, "httpread: Trying to read more data(%p)", h); 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nread = read(h->sd, readbuf, sizeof(readbuf)); 381cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt if (nread < 0) { 382cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, "httpread failed: %s", strerror(errno)); 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 384cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt } 385cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_hexdump_ascii(MSG_MSGDUMP, "httpread - read", readbuf, nread); 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nread == 0) { 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* end of transmission... this may be normal 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * or may be an error... in some cases we can't 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * tell which so we must assume it is normal then. 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!h->got_hdr) { 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Must at least have completed header */ 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "httpread premature eof(%p)", h); 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->chunked || h->got_content_length) { 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Premature EOF; e.g. dropped connection */ 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "httpread premature eof(%p) %d/%d", 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h, h->body_nbytes, 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->content_length); 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* No explicit length, hopefully we have all the data 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * although dropped connections can cause false 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * end 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 408cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h); 409623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt h->got_body = 1; 410623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt goto got_file; 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rbp = readbuf; 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Header consists of text lines (terminated by both CR and LF) 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * and an empty line (CR LF only). 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!h->got_hdr) { 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp = h->hdr + h->hdr_nbytes; 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* add to headers until: 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- we run out of data in read buffer 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- or, we run out of header buffer room 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- or, we get double CRLF in headers 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (;;) { 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nread == 0) 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto get_more; 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) { 428cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 429cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt "httpread: Too long header"); 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *hbp++ = *rbp++; 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nread--; 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->hdr_nbytes++; 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->hdr_nbytes >= 4 && 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp[-1] == '\n' && 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp[-2] == '\r' && 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp[-3] == '\n' && 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hbp[-4] == '\r' ) { 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->got_hdr = 1; 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *hbp = 0; /* null terminate */ 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* here we've just finished reading the header */ 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (httpread_hdr_analyze(h)) { 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h); 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->max_bytes == 0) { 451cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, "httpread no body hdr end(%p)", 452cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt h); 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto got_file; 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->got_content_length && h->content_length == 0) { 456cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 457cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt "httpread zero content length(%p)", h); 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto got_file; 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Certain types of requests never have data and so 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * must be specially recognized. 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) || 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) || 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !os_strncasecmp(h->hdr, "HEAD", 4) || 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !os_strncasecmp(h->hdr, "GET", 3)) { 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!h->got_body) { 470cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, "httpread NO BODY for sp. type"); 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->got_body = 1; 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto got_file; 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Data can be just plain binary data, or if "chunked" 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * consists of chunks each with a header, ending with 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * an ending header. 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nread == 0) 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto get_more; 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!h->got_body) { 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Here to get (more of) body */ 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* ensure we have enough room for worst case for body 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * plus a null termination character 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) { 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *new_body; 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int new_alloc_nbytes; 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 491cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt if (h->body_nbytes >= h->max_bytes) { 492cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 493cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt "httpread: body_nbytes=%d >= max_bytes=%d", 494cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt h->body_nbytes, h->max_bytes); 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 496cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt } 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt new_alloc_nbytes = h->body_alloc_nbytes + 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HTTPREAD_BODYBUF_DELTA; 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* For content-length case, the first time 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * through we allocate the whole amount 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * we need. 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->got_content_length && 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt new_alloc_nbytes < (h->content_length + 1)) 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt new_alloc_nbytes = h->content_length + 1; 506cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt if (new_alloc_nbytes < h->body_alloc_nbytes || 507d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt new_alloc_nbytes > h->max_bytes + 508d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt HTTPREAD_BODYBUF_DELTA) { 509cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 510d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt "httpread: Unacceptable body length %d (body_alloc_nbytes=%u max_bytes=%u)", 511d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt new_alloc_nbytes, 512d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt h->body_alloc_nbytes, 513d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt h->max_bytes); 514cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt goto bad; 515cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt } 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((new_body = os_realloc(h->body, new_alloc_nbytes)) 517cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt == NULL) { 518cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 519cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt "httpread: Failed to reallocate buffer (len=%d)", 520cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt new_alloc_nbytes); 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 522cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt } 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->body = new_body; 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->body_alloc_nbytes = new_alloc_nbytes; 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* add bytes */ 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bbp = h->body + h->body_nbytes; 5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (;;) { 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ncopy; 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* See if we need to stop */ 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->chunked && h->in_chunk_data == 0) { 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* in chunk header */ 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *cbp = h->body + h->chunk_start; 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bbp-cbp >= 2 && bbp[-2] == '\r' && 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bbp[-1] == '\n') { 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* end of chunk hdr line */ 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* hdr line consists solely 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * of a hex numeral and CFLF 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 541cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt if (!isxdigit(*cbp)) { 542cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 543cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt "httpread: Unexpected chunk header value (not a hex digit)"); 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 545cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt } 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->chunk_size = strtoul(cbp, NULL, 16); 547cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt if (h->chunk_size < 0 || 548cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt h->chunk_size > h->max_bytes) { 549cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 550cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt "httpread: Invalid chunk size %d", 551cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt h->chunk_size); 552cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt goto bad; 553cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt } 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* throw away chunk header 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * so we have only real data 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->body_nbytes = h->chunk_start; 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bbp = cbp; 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->chunk_size == 0) { 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* end of chunking */ 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* trailer follows */ 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->in_trailer = 1; 563cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 564cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt "httpread end chunks(%p)", 565cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt h); 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->in_chunk_data = 1; 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* leave chunk_start alone */ 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (h->chunked) { 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* in chunk data */ 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((h->body_nbytes - h->chunk_start) == 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (h->chunk_size + 2)) { 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* end of chunk reached, 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * new chunk starts 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* check chunk ended w/ CRLF 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * which we'll throw away 5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bbp[-1] == '\n' && 5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bbp[-2] == '\r') { 583cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt } else { 584cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 585cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt "httpread: Invalid chunk end"); 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 587cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt } 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->body_nbytes -= 2; 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bbp -= 2; 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->chunk_start = h->body_nbytes; 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->in_chunk_data = 0; 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->chunk_size = 0; /* just in case */ 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (h->got_content_length && 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->body_nbytes >= h->content_length) { 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->got_body = 1; 597cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 598cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt "httpread got content(%p)", h); 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto got_file; 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nread <= 0) 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Now transfer. Optimize using memcpy where we can. */ 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->chunked && h->in_chunk_data) { 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* copy up to remainder of chunk data 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * plus the required CR+LF at end 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ncopy = (h->chunk_start + h->chunk_size + 2) - 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->body_nbytes; 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (h->chunked) { 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /*in chunk header -- don't optimize */ 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *bbp++ = *rbp++; 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nread--; 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->body_nbytes++; 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (h->got_content_length) { 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ncopy = h->content_length - h->body_nbytes; 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ncopy = nread; 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Note: should never be 0 */ 622cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt if (ncopy < 0) { 623cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 624cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt "httpread: Invalid ncopy=%d", ncopy); 625cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt goto bad; 626cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt } 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ncopy > nread) 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ncopy = nread; 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(bbp, rbp, ncopy); 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bbp += ncopy; 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->body_nbytes += ncopy; 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rbp += ncopy; 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nread -= ncopy; 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } /* body copy loop */ 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } /* !got_body */ 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->chunked && h->in_trailer) { 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* If "chunked" then there is always a trailer, 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * consisting of zero or more non-empty lines 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ending with CR LF and then an empty line w/ CR LF. 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * We do NOT support trailers except to skip them -- 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * this is supported (generally) by the http spec. 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (;;) { 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int c; 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nread <= 0) 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c = *rbp++; 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nread--; 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (h->trailer_state) { 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case trailer_line_begin: 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (c == '\r') 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->trailer_state = trailer_empty_cr; 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->trailer_state = trailer_nonempty; 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case trailer_empty_cr: 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* end empty line */ 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (c == '\n') { 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->trailer_state = trailer_line_begin; 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->in_trailer = 0; 661cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, 662cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt "httpread got content(%p)", 663cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt h); 6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->got_body = 1; 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto got_file; 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->trailer_state = trailer_nonempty; 6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case trailer_nonempty: 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (c == '\r') 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->trailer_state = trailer_nonempty_cr; 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case trailer_nonempty_cr: 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (c == '\n') 6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->trailer_state = trailer_line_begin; 6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->trailer_state = trailer_nonempty; 6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto get_more; 6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtbad: 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Error */ 6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h); 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR); 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtget_more: 691cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, "httpread: get more (%p)", h); 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtgot_file: 695cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_printf(MSG_DEBUG, "httpread got file %d bytes type %d", 696cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt h->body_nbytes, h->hdr_type); 697cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt wpa_hexdump_ascii(MSG_MSGDUMP, "httpread: body", 698cc00d5dc8483e32158b2ba61ea44b0c38d790ed7Dmitry Shmidt h->body, h->body_nbytes); 6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Null terminate for convenience of some applications */ 7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h->body) 7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->body[h->body_nbytes] = 0; /* null terminate */ 7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->got_file = 1; 7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Assume that we do NOT support keeping connection alive, 7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * and just in case somehow we don't get destroyed right away, 7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * unregister now. 7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 707fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt eloop_unregister_sock(h->sd, EVENT_TYPE_READ); 7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* The application can destroy us whenever they feel like... 7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * cancel timeout. 7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 711fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt eloop_cancel_timeout(httpread_timeout_handler, NULL, h); 7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY); 7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* httpread_create -- start a new reading session making use of eloop. 7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The new instance will use the socket descriptor for reading (until 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it gets a file and not after) but will not close the socket, even 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * when the instance is destroyed (the application must do that). 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Return NULL on error. 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Provided that httpread_create successfully returns a handle, 7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the callback fnc is called to handle httpread_event events. 7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The caller should do destroy on any errors or unknown events. 7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Pass max_bytes == 0 to not read body at all (required for e.g. 7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * reply to HEAD request). 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct httpread * httpread_create( 7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sd, /* descriptor of TCP socket to read from */ 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void (*cb)(struct httpread *handle, void *cookie, 7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum httpread_event e), /* call on event */ 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void *cookie, /* pass to callback */ 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int max_bytes, /* maximum body size else abort it */ 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int timeout_seconds /* 0; or total duration timeout period */ 7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ) 7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct httpread *h = NULL; 7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h = os_zalloc(sizeof(*h)); 7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h == NULL) 7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->sd = sd; 7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->cb = cb; 7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->cookie = cookie; 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->max_bytes = max_bytes; 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h->timeout_seconds = timeout_seconds; 7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 749fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (timeout_seconds > 0 && 750fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt eloop_register_timeout(timeout_seconds, 0, 751fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt httpread_timeout_handler, NULL, h)) { 752fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt /* No way to recover (from malloc failure) */ 753fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt goto fail; 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler, 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NULL, h)) { 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* No way to recover (from malloc failure) */ 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return h; 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail: 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Error */ 7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt httpread_destroy(h); 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* httpread_hdr_type_get -- When file is ready, returns header type. */ 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtenum httpread_hdr_type httpread_hdr_type_get(struct httpread *h) 7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return h->hdr_type; 7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI 7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * or possibly NULL (which would be an error). 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar * httpread_uri_get(struct httpread *h) 7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return h->uri; 7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* httpread_reply_code_get -- When reply is ready, returns reply code */ 7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint httpread_reply_code_get(struct httpread *h) 7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return h->reply_code; 7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* httpread_length_get -- When file is ready, returns file length. */ 7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint httpread_length_get(struct httpread *h) 7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return h->body_nbytes; 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* httpread_data_get -- When file is ready, returns file content 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * with null byte appened. 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Might return NULL in some error condition. 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid * httpread_data_get(struct httpread *h) 8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return h->body ? h->body : ""; 8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* httpread_hdr_get -- When file is ready, returns header content 8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * with null byte appended. 8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Might return NULL in some error condition. 8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar * httpread_hdr_get(struct httpread *h) 8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return h->hdr; 8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* httpread_hdr_line_get -- When file is ready, returns pointer 8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * to line within header content matching the given tag 8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * (after the tag itself and any spaces/tabs). 8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The tag should end with a colon for reliable matching. 8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * If not found, returns NULL; 8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar * httpread_hdr_line_get(struct httpread *h, const char *tag) 8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int tag_len = os_strlen(tag); 8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *hdr = h->hdr; 8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr = os_strchr(hdr, '\n'); 8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr == NULL) 8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr++; 8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (;;) { 8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!os_strncasecmp(hdr, tag, tag_len)) { 8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr += tag_len; 8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (*hdr == ' ' || *hdr == '\t') 8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr++; 8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return hdr; 8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr = os_strchr(hdr, '\n'); 8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr == NULL) 8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr++; 8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 849