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