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