httpread.c revision 623d63a3a443027e50efdaaec027befcc3882527
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * httpread - Manage reading file(s) from HTTP/TCP socket
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Author: Ted Merrill
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright 2008 Atheros Communications
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This software may be distributed under the terms of the BSD license.
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * See README for more details.
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * The files are buffered via internal callbacks from eloop, then presented to
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * an application callback routine when completely read into memory. May also
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * be used if no file is expected but just to get the header, including HTTP
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * replies (e.g. HTTP/1.1 200 OK etc.).
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This does not attempt to be an optimally efficient implementation, but does
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * attempt to be of reasonably small size and memory consumption; assuming that
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * only small files are to be read. A maximum file size is provided by
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * application and enforced.
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * It is assumed that the application does not expect any of the following:
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * -- transfer encoding other than chunked
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * -- trailer fields
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * It is assumed that, even if the other side requested that the connection be
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * kept open, that we will close it (thus HTTP messages sent by application
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * should have the connection closed field); this is allowed by HTTP/1.1 and
25e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) * simplifies things for us.
2653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *
27e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) * Other limitations:
28e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) * -- HTTP header may not exceed a hard-coded size.
29e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) *
30e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) * Notes:
31e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) * This code would be massively simpler without some of the new features of
321e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * HTTP/1.1, especially chunked data.
3353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) */
3493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
357242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "includes.h"
365d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)
371e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "common.h"
385d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "eloop.h"
39a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "httpread.h"
40e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
41e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* Tunable parameters */
43c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)#define HTTPREAD_READBUF_SIZE 1024      /* read in chunks of this size */
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#define HTTPREAD_HEADER_MAX_SIZE 4096   /* max allowed for headers */
453c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch#define HTTPREAD_BODYBUF_DELTA 4096     /* increase allocation by this */
463c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch
47f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)#if 0
48d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)/* httpread_debug -- set this global variable > 0 e.g. from debugger
4953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) * to enable debugs (larger numbers for more debugs)
50f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) * Make this a #define of 0 to eliminate the debugging code.
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
527242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciint httpread_debug = 99;
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#else
5453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#define httpread_debug 0        /* eliminates even the debugging code */
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
57c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)
58e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)/* control instance -- actual definition (opaque to application)
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct httpread {
617242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci	/* information from creation */
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int sd;         /* descriptor of TCP socket to read from */
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	void (*cb)(struct httpread *handle, void *cookie,
6453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)		    enum httpread_event e);  /* call on event */
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	void *cookie;   /* pass to callback */
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int max_bytes;          /* maximum file size else abort it */
67c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)	int timeout_seconds;            /* 0 or total duration timeout period */
6809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
6909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)	/* dynamically used information follows */
7009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
717242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci	int got_hdr;            /* nonzero when header is finalized */
7209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)	char hdr[HTTPREAD_HEADER_MAX_SIZE+1];   /* headers stored here */
7309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)	int hdr_nbytes;
7409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
7509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)	enum httpread_hdr_type hdr_type;
7609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)	int version;            /* 1 if we've seen 1.1 */
773c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	int reply_code;         /* for type REPLY, e.g. 200 for HTTP/1.1 200 OK */
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int got_content_length; /* true if we know content length for sure */
797242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci	int content_length;     /* body length,  iff got_content_length */
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int chunked;            /* nonzero for chunked data */
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char *uri;
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
833c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	int got_body;           /* nonzero when body is finalized */
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char *body;
853464d02a173573db42f8ee6bb07bb74fabf4f5f2Ben Murdoch	int body_nbytes;
86fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch	int body_alloc_nbytes;  /* amount allocated */
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int got_file;           /* here when we are done */
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	/* The following apply if data is chunked: */
913c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	int in_chunk_data;      /* 0=in/at header, 1=in the data or tail*/
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int chunk_start;        /* offset in body of chunk hdr or data */
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int chunk_size;         /* data of chunk (not hdr or ending CRLF)*/
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int in_trailer;         /* in header fields after data (chunked only)*/
9553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)	enum trailer_state {
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		trailer_line_begin = 0,
9753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)		trailer_empty_cr,       /* empty line + CR */
983c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch		trailer_nonempty,
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		trailer_nonempty_cr,
1003c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	} trailer_state;
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
102fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* Check words for equality, where words consist of graphical characters
1053c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch * delimited by whitespace
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Returns nonzero if "equal" doing case insensitive comparison.
107926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) */
1083c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdochstatic int word_eq(char *s1, char *s2)
109926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
1103c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	int c1;
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int c2;
1123c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	int end1 = 0;
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int end2 = 0;
114fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch	for (;;) {
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		c1 = *s1++;
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		c2 = *s2++;
1173c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch		if (isalpha(c1) && isupper(c1))
118926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			c1 = tolower(c1);
119926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		if (isalpha(c2) && isupper(c2))
120926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			c2 = tolower(c2);
121926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		end1 = !isgraph(c1);
122926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		end2 = !isgraph(c2);
123fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch		if (end1 || end2 || c1 != c2)
124926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			break;
125926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	}
126926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	return end1 && end2;  /* reached end of both words? */
127fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch}
12851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
129926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1303c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdochstatic void httpread_timeout_handler(void *eloop_data, void *user_ctx);
131926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
132926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)/* httpread_destroy -- if h is non-NULL, clean up
133926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * This must eventually be called by the application following
134fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch * call of the application's callback and may be called
135926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * earlier if desired.
136926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) */
13709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void httpread_destroy(struct httpread *h)
13809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
139d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)	if (httpread_debug >= 10)
140d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)		wpa_printf(MSG_DEBUG, "ENTER httpread_destroy(%p)", h);
14109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)	if (!h)
14209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)		return;
14309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
14409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)	eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
145d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)	eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
146d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)	os_free(h->body);
14709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)	os_free(h->uri);
14809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)	os_memset(h, 0, sizeof(*h));  /* aid debugging */
14909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)	h->sd = -1;     /* aid debugging */
15009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)	os_free(h);
15109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
15209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
1533c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* httpread_timeout_handler -- called on excessive total duration
155926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) */
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void httpread_timeout_handler(void *eloop_data, void *user_ctx)
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
158fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch	struct httpread *h = user_ctx;
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h);
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT);
161c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)}
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
164c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)/* Analyze options only so far as is needed to correctly obtain the file.
16551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * The application can look at the raw header to find other options.
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static int httpread_hdr_option_analyze(
168c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)	struct httpread *h,
16951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)	char *hbp       /* pointer to current line in header buffer */
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	)
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1723c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	if (word_eq(hbp, "CONTENT-LENGTH:")) {
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (isgraph(*hbp))
17453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)			hbp++;
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (*hbp == ' ' || *hbp == '\t')
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			hbp++;
177c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)		if (!isdigit(*hbp))
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			return -1;
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->content_length = atol(hbp);
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->got_content_length = 1;
18153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)		return 0;
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
1833c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	if (word_eq(hbp, "TRANSFER_ENCODING:") ||
18453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)	    word_eq(hbp, "TRANSFER-ENCODING:")) {
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (isgraph(*hbp))
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			hbp++;
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (*hbp == ' ' || *hbp == '\t')
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			hbp++;
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		/* There should (?) be no encodings of interest
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		 * other than chunked...
191c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)		 */
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (word_eq(hbp, "CHUNKED")) {
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			h->chunked = 1;
194c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)			h->in_chunk_data = 0;
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			/* ignore possible ;<parameters> */
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		}
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		return 0;
19853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)	}
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	/* skip anything we don't know, which is a lot */
2003c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	return 0;
20153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)}
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static int httpread_hdr_analyze(struct httpread *h)
205926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
206c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)	char *hbp = h->hdr;      /* pointer into h->hdr */
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int standard_first_line = 1;
208926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
209c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)	/* First line is special */
210c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)	h->hdr_type = HTTPREAD_HDR_TYPE_UNKNOWN;
211926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	if (!isgraph(*hbp))
212926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		goto bad;
21393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)	if (os_strncmp(hbp, "HTTP/", 5) == 0) {
214926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_REPLY;
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		standard_first_line = 0;
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		hbp += 5;
2173c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch		if (hbp[0] == '1' && hbp[1] == '.' &&
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		    isdigit(hbp[2]) && hbp[2] != '0')
219926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			h->version = 1;
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (isgraph(*hbp))
221926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			hbp++;
222926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		while (*hbp == ' ' || *hbp == '\t')
223926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			hbp++;
224926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		if (!isdigit(*hbp))
225926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			goto bad;
226926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		h->reply_code = atol(hbp);
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	} else if (word_eq(hbp, "GET"))
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_GET;
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	else if (word_eq(hbp, "HEAD"))
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_HEAD;
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	else if (word_eq(hbp, "POST"))
232926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_POST;
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	else if (word_eq(hbp, "PUT"))
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_PUT;
2353c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	else if (word_eq(hbp, "DELETE"))
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_DELETE;
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	else if (word_eq(hbp, "TRACE"))
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_TRACE;
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	else if (word_eq(hbp, "CONNECT"))
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_CONNECT;
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	else if (word_eq(hbp, "NOTIFY"))
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_NOTIFY;
2433c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	else if (word_eq(hbp, "M-SEARCH"))
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_M_SEARCH;
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	else if (word_eq(hbp, "M-POST"))
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_M_POST;
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	else if (word_eq(hbp, "SUBSCRIBE"))
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_SUBSCRIBE;
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	else if (word_eq(hbp, "UNSUBSCRIBE"))
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->hdr_type = HTTPREAD_HDR_TYPE_UNSUBSCRIBE;
2513c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	else {
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (standard_first_line) {
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		char *rawuri;
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		char *uri;
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		/* skip type */
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (isgraph(*hbp))
259e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)			hbp++;
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (*hbp == ' ' || *hbp == '\t')
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			hbp++;
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		/* parse uri.
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		 * Find length, allocate memory for translated
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		 * copy, then translate by changing %<hex><hex>
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		 * into represented value.
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		 */
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		rawuri = hbp;
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (isgraph(*hbp))
269a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)			hbp++;
270e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)		h->uri = os_malloc((hbp - rawuri) + 1);
271926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		if (h->uri == NULL)
272926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			goto bad;
273926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		uri = h->uri;
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (rawuri < hbp) {
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			int c = *rawuri;
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (c == '%' &&
27753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)			    isxdigit(rawuri[1]) && isxdigit(rawuri[2])) {
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				*uri++ = hex2byte(rawuri + 1);
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				rawuri += 3;
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			} else {
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				*uri++ = c;
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				rawuri++;
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			}
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		}
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		*uri = 0;       /* null terminate */
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (isgraph(*hbp))
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			hbp++;
2883c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch		while (*hbp == ' ' || *hbp == '\t')
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			hbp++;
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		/* get version */
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (0 == strncmp(hbp, "HTTP/", 5)) {
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			hbp += 5;
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (hbp[0] == '1' && hbp[1] == '.' &&
2943c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch			    isdigit(hbp[2]) && hbp[2] != '0')
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				h->version = 1;
2963c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch		}
2973c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	}
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	/* skip rest of line */
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	while (*hbp)
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (*hbp++ == '\n')
3013c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch			break;
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
30309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)	/* Remainder of lines are options, in any order;
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 * or empty line to terminate
305926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	 */
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	for (;;) {
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		/* Empty line to terminate */
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (hbp[0] == '\n' ||
3093c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch		    (hbp[0] == '\r' && hbp[1] == '\n'))
31053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)			break;
3115267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)		if (!isgraph(*hbp))
312591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch			goto bad;
31353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)		if (httpread_hdr_option_analyze(h, hbp))
31453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)			goto bad;
3153c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch		/* skip line */
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (*hbp)
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (*hbp++ == '\n')
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				break;
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
32093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
32193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)	/* chunked overrides content-length always */
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (h->chunked)
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->got_content_length = 0;
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3253c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	/* For some types, we should not try to read a body
326926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	 * This is in addition to the application determining
3273c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	 * that we should not read a body.
328926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	 */
329926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	switch (h->hdr_type) {
330926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	case HTTPREAD_HDR_TYPE_REPLY:
331926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		/* Some codes can have a body and some not.
332926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		 * For now, just assume that any other than 200
333926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		 * do not...
334926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		 */
335926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		if (h->reply_code != 200)
336926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			h->max_bytes = 0;
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		break;
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	case HTTPREAD_HDR_TYPE_GET:
3393c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	case HTTPREAD_HDR_TYPE_HEAD:
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		/* in practice it appears that it is assumed
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		 * that GETs have a body length of 0... ?
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		 */
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (h->chunked == 0 && h->got_content_length == 0)
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			h->max_bytes = 0;
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		break;
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	case HTTPREAD_HDR_TYPE_POST:
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	case HTTPREAD_HDR_TYPE_PUT:
3483c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	case HTTPREAD_HDR_TYPE_DELETE:
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	case HTTPREAD_HDR_TYPE_TRACE:
350fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch	case HTTPREAD_HDR_TYPE_CONNECT:
35153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)	case HTTPREAD_HDR_TYPE_NOTIFY:
35253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)	case HTTPREAD_HDR_TYPE_M_SEARCH:
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	case HTTPREAD_HDR_TYPE_M_POST:
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	case HTTPREAD_HDR_TYPE_SUBSCRIBE:
3553c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	default:
357197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch		break;
3581e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)	}
359926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
360926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	return 0;
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bad:
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	/* Error */
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	return -1;
36553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)}
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
367926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
36853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)/* httpread_read_handler -- called when socket ready to read
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Note: any extra data we read past end of transmitted file is ignored;
3713c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch * if we were to support keeping connections open for multiple files then
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * this would have to be addressed.
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx)
37553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles){
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	struct httpread *h = sock_ctx;
37707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch	int nread;
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char *rbp;      /* pointer into read buffer */
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char *hbp;      /* pointer into header buffer */
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char *bbp;      /* pointer into body buffer */
38153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)	char readbuf[HTTPREAD_READBUF_SIZE];  /* temp use to read into */
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (httpread_debug >= 20)
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		wpa_printf(MSG_DEBUG, "ENTER httpread_read_handler(%p)", h);
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	/* read some at a time, then search for the interal
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 * boundaries between header and data and etc.
3887242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci	 */
3897242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci	nread = read(h->sd, readbuf, sizeof(readbuf));
3907242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci	if (nread < 0)
3917242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci		goto bad;
3927242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci	if (nread == 0) {
3937242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci		/* end of transmission... this may be normal
3947242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci		 * or may be an error... in some cases we can't
3957242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci		 * tell which so we must assume it is normal then.
3967242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci		 */
3977242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci		if (!h->got_hdr) {
3987242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci			/* Must at least have completed header */
3997242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci			wpa_printf(MSG_DEBUG, "httpread premature eof(%p)", h);
4007242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci			goto bad;
4013c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch		}
40253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)		if (h->chunked || h->got_content_length) {
40381a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)			/* Premature EOF; e.g. dropped connection */
40481a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)			wpa_printf(MSG_DEBUG,
40553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)				   "httpread premature eof(%p) %d/%d",
40681a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)				   h, h->body_nbytes,
40781a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)				   h->content_length);
408fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch			goto bad;
40953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)		}
41053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)		/* No explicit length, hopefully we have all the data
4113c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch		 * although dropped connections can cause false
4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		 * end
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		 */
414fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch		if (httpread_debug >= 10)
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h);
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		h->got_body = 1;
4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		goto got_file;
4183c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch	}
4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	rbp = readbuf;
42081a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)
42181a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)	/* Header consists of text lines (terminated by both CR and LF)
42281a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)	 * and an empty line (CR LF only).
42353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)	 */
424f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)	if (!h->got_hdr) {
425f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)		hbp = h->hdr + h->hdr_nbytes;
426f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)		/* add to headers until:
427f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)		 *      -- we run out of data in read buffer
428f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)		 *      -- or, we run out of header buffer room
429f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)		 *      -- or, we get double CRLF in headers
430f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)		 */
431fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch		for (;;) {
4325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (nread == 0)
4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				goto get_more;
434c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)			if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) {
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				goto bad;
4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			}
4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			*hbp++ = *rbp++;
43853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)			nread--;
4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			h->hdr_nbytes++;
4405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (h->hdr_nbytes >= 4 &&
4415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			    hbp[-1] == '\n' &&
442c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)			    hbp[-2] == '\r' &&
4435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			    hbp[-3] == '\n' &&
4445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			    hbp[-4] == '\r' ) {
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				h->got_hdr = 1;
4467242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci				*hbp = 0;       /* null terminate */
4477242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci				break;
4487242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci			}
4497242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci		}
4507242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci		/* here we've just finished reading the header */
4515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (httpread_hdr_analyze(h)) {
4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h);
453c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)			goto bad;
4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		}
4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (h->max_bytes == 0) {
4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (httpread_debug >= 10)
45753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)				wpa_printf(MSG_DEBUG,
4583c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch					   "httpread no body hdr end(%p)", h);
4593c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch			goto got_file;
4605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		}
4615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (h->got_content_length && h->content_length == 0) {
4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (httpread_debug >= 10)
4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				wpa_printf(MSG_DEBUG,
4645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					   "httpread zero content length(%p)",
4655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					   h);
4665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			goto got_file;
467c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)		}
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	/* Certain types of requests never have data and so
4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 * must be specially recognized.
4725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 */
4735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) ||
474c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)	    !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) ||
4755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	    !os_strncasecmp(h->hdr, "HEAD", 4) ||
4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	    !os_strncasecmp(h->hdr, "GET", 3)) {
4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (!h->got_body) {
4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (httpread_debug >= 10)
4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				wpa_printf(MSG_DEBUG,
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					   "httpread NO BODY for sp. type");
4813c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch		}
482926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		h->got_body = 1;
483c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)		goto got_file;
484926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	}
485926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
486926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	/* Data can be just plain binary data, or if "chunked"
487926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	 * consists of chunks each with a header, ending with
488926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	 * an ending header.
489f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)	 */
490f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)	if (nread == 0)
491f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)		goto get_more;
492f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)	if (!h->got_body) {
493f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)		/* Here to get (more of) body */
494f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)		/* ensure we have enough room for worst case for body
495f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)		 * plus a null termination character
496f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)		 */
497f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)		if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) {
498c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)			char *new_body;
499			int new_alloc_nbytes;
500
501			if (h->body_nbytes >= h->max_bytes)
502				goto bad;
503			new_alloc_nbytes = h->body_alloc_nbytes +
504				HTTPREAD_BODYBUF_DELTA;
505			/* For content-length case, the first time
506			 * through we allocate the whole amount
507			 * we need.
508			 */
509			if (h->got_content_length &&
510			    new_alloc_nbytes < (h->content_length + 1))
511				new_alloc_nbytes = h->content_length + 1;
512			if ((new_body = os_realloc(h->body, new_alloc_nbytes))
513			    == NULL)
514				goto bad;
515
516			h->body = new_body;
517			h->body_alloc_nbytes = new_alloc_nbytes;
518		}
519		/* add bytes */
520		bbp = h->body + h->body_nbytes;
521		for (;;) {
522			int ncopy;
523			/* See if we need to stop */
524			if (h->chunked && h->in_chunk_data == 0) {
525				/* in chunk header */
526				char *cbp = h->body + h->chunk_start;
527				if (bbp-cbp >= 2 && bbp[-2] == '\r' &&
528				    bbp[-1] == '\n') {
529					/* end of chunk hdr line */
530					/* hdr line consists solely
531					 * of a hex numeral and CFLF
532					 */
533					if (!isxdigit(*cbp))
534						goto bad;
535					h->chunk_size = strtoul(cbp, NULL, 16);
536					/* throw away chunk header
537					 * so we have only real data
538					 */
539					h->body_nbytes = h->chunk_start;
540					bbp = cbp;
541					if (h->chunk_size == 0) {
542						/* end of chunking */
543						/* trailer follows */
544						h->in_trailer = 1;
545						if (httpread_debug >= 20)
546							wpa_printf(
547								MSG_DEBUG,
548								"httpread end chunks(%p)", h);
549						break;
550					}
551					h->in_chunk_data = 1;
552					/* leave chunk_start alone */
553				}
554			} else if (h->chunked) {
555				/* in chunk data */
556				if ((h->body_nbytes - h->chunk_start) ==
557				    (h->chunk_size + 2)) {
558					/* end of chunk reached,
559					 * new chunk starts
560					 */
561					/* check chunk ended w/ CRLF
562					 * which we'll throw away
563					 */
564					if (bbp[-1] == '\n' &&
565					    bbp[-2] == '\r') {
566					} else
567						goto bad;
568					h->body_nbytes -= 2;
569					bbp -= 2;
570					h->chunk_start = h->body_nbytes;
571					h->in_chunk_data = 0;
572					h->chunk_size = 0; /* just in case */
573				}
574			} else if (h->got_content_length &&
575				   h->body_nbytes >= h->content_length) {
576				h->got_body = 1;
577				if (httpread_debug >= 10)
578					wpa_printf(
579						MSG_DEBUG,
580						"httpread got content(%p)", h);
581				goto got_file;
582			}
583			if (nread <= 0)
584				break;
585			/* Now transfer. Optimize using memcpy where we can. */
586			if (h->chunked && h->in_chunk_data) {
587				/* copy up to remainder of chunk data
588				 * plus the required CR+LF at end
589				 */
590				ncopy = (h->chunk_start + h->chunk_size + 2) -
591					h->body_nbytes;
592			} else if (h->chunked) {
593				/*in chunk header -- don't optimize */
594				*bbp++ = *rbp++;
595				nread--;
596				h->body_nbytes++;
597				continue;
598			} else if (h->got_content_length) {
599				ncopy = h->content_length - h->body_nbytes;
600			} else {
601				ncopy = nread;
602			}
603			/* Note: should never be 0 */
604			if (ncopy > nread)
605				ncopy = nread;
606			os_memcpy(bbp, rbp, ncopy);
607			bbp += ncopy;
608			h->body_nbytes += ncopy;
609			rbp += ncopy;
610			nread -= ncopy;
611		}       /* body copy loop */
612	}       /* !got_body */
613	if (h->chunked && h->in_trailer) {
614		/* If "chunked" then there is always a trailer,
615		 * consisting of zero or more non-empty lines
616		 * ending with CR LF and then an empty line w/ CR LF.
617		 * We do NOT support trailers except to skip them --
618		 * this is supported (generally) by the http spec.
619		 */
620		for (;;) {
621			int c;
622			if (nread <= 0)
623				break;
624			c = *rbp++;
625			nread--;
626			switch (h->trailer_state) {
627			case trailer_line_begin:
628				if (c == '\r')
629					h->trailer_state = trailer_empty_cr;
630				else
631					h->trailer_state = trailer_nonempty;
632				break;
633			case trailer_empty_cr:
634				/* end empty line */
635				if (c == '\n') {
636					h->trailer_state = trailer_line_begin;
637					h->in_trailer = 0;
638					if (httpread_debug >= 10)
639						wpa_printf(
640							MSG_DEBUG,
641							"httpread got content(%p)", h);
642					h->got_body = 1;
643					goto got_file;
644				}
645				h->trailer_state = trailer_nonempty;
646				break;
647			case trailer_nonempty:
648				if (c == '\r')
649					h->trailer_state = trailer_nonempty_cr;
650				break;
651			case trailer_nonempty_cr:
652				if (c == '\n')
653					h->trailer_state = trailer_line_begin;
654				else
655					h->trailer_state = trailer_nonempty;
656				break;
657			}
658		}
659	}
660	goto get_more;
661
662bad:
663	/* Error */
664	wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h);
665	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR);
666	return;
667
668get_more:
669	return;
670
671got_file:
672	if (httpread_debug >= 10)
673		wpa_printf(MSG_DEBUG,
674			   "httpread got file %d bytes type %d",
675			   h->body_nbytes, h->hdr_type);
676	/* Null terminate for convenience of some applications */
677	if (h->body)
678		h->body[h->body_nbytes] = 0; /* null terminate */
679	h->got_file = 1;
680	/* Assume that we do NOT support keeping connection alive,
681	 * and just in case somehow we don't get destroyed right away,
682	 * unregister now.
683	 */
684	eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
685	/* The application can destroy us whenever they feel like...
686	 * cancel timeout.
687	 */
688	eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
689	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY);
690}
691
692
693/* httpread_create -- start a new reading session making use of eloop.
694 * The new instance will use the socket descriptor for reading (until
695 * it gets a file and not after) but will not close the socket, even
696 * when the instance is destroyed (the application must do that).
697 * Return NULL on error.
698 *
699 * Provided that httpread_create successfully returns a handle,
700 * the callback fnc is called to handle httpread_event events.
701 * The caller should do destroy on any errors or unknown events.
702 *
703 * Pass max_bytes == 0 to not read body at all (required for e.g.
704 * reply to HEAD request).
705 */
706struct httpread * httpread_create(
707	int sd,	 /* descriptor of TCP socket to read from */
708	void (*cb)(struct httpread *handle, void *cookie,
709		   enum httpread_event e),  /* call on event */
710	void *cookie,    /* pass to callback */
711	int max_bytes,	  /* maximum body size else abort it */
712	int timeout_seconds     /* 0; or total duration timeout period */
713	)
714{
715	struct httpread *h = NULL;
716
717	h = os_zalloc(sizeof(*h));
718	if (h == NULL)
719		goto fail;
720	h->sd = sd;
721	h->cb = cb;
722	h->cookie = cookie;
723	h->max_bytes = max_bytes;
724	h->timeout_seconds = timeout_seconds;
725
726	if (timeout_seconds > 0 &&
727	    eloop_register_timeout(timeout_seconds, 0,
728				   httpread_timeout_handler, NULL, h)) {
729		/* No way to recover (from malloc failure) */
730		goto fail;
731	}
732	if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler,
733				NULL, h)) {
734		/* No way to recover (from malloc failure) */
735		goto fail;
736	}
737	return h;
738
739fail:
740
741	/* Error */
742	httpread_destroy(h);
743	return NULL;
744}
745
746
747/* httpread_hdr_type_get -- When file is ready, returns header type. */
748enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h)
749{
750	return h->hdr_type;
751}
752
753
754/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI
755 * or possibly NULL (which would be an error).
756 */
757char * httpread_uri_get(struct httpread *h)
758{
759	return h->uri;
760}
761
762
763/* httpread_reply_code_get -- When reply is ready, returns reply code */
764int httpread_reply_code_get(struct httpread *h)
765{
766	return h->reply_code;
767}
768
769
770/* httpread_length_get -- When file is ready, returns file length. */
771int httpread_length_get(struct httpread *h)
772{
773	return h->body_nbytes;
774}
775
776
777/* httpread_data_get -- When file is ready, returns file content
778 * with null byte appened.
779 * Might return NULL in some error condition.
780 */
781void * httpread_data_get(struct httpread *h)
782{
783	return h->body ? h->body : "";
784}
785
786
787/* httpread_hdr_get -- When file is ready, returns header content
788 * with null byte appended.
789 * Might return NULL in some error condition.
790 */
791char * httpread_hdr_get(struct httpread *h)
792{
793	return h->hdr;
794}
795
796
797/* httpread_hdr_line_get -- When file is ready, returns pointer
798 * to line within header content matching the given tag
799 * (after the tag itself and any spaces/tabs).
800 *
801 * The tag should end with a colon for reliable matching.
802 *
803 * If not found, returns NULL;
804 */
805char * httpread_hdr_line_get(struct httpread *h, const char *tag)
806{
807	int tag_len = os_strlen(tag);
808	char *hdr = h->hdr;
809	hdr = os_strchr(hdr, '\n');
810	if (hdr == NULL)
811		return NULL;
812	hdr++;
813	for (;;) {
814		if (!os_strncasecmp(hdr, tag, tag_len)) {
815			hdr += tag_len;
816			while (*hdr == ' ' || *hdr == '\t')
817				hdr++;
818			return hdr;
819		}
820		hdr = os_strchr(hdr, '\n');
821		if (hdr == NULL)
822			return NULL;
823		hdr++;
824	}
825}
826