Import moonshot-gss-eap_0.9.5.orig.tar.gz
[mech_eap.git] / libeap / src / wps / httpread.c
diff --git a/libeap/src/wps/httpread.c b/libeap/src/wps/httpread.c
deleted file mode 100644 (file)
index 40422e4..0000000
+++ /dev/null
@@ -1,861 +0,0 @@
-/*
- * httpread - Manage reading file(s) from HTTP/TCP socket
- * Author: Ted Merrill
- * Copyright 2008 Atheros Communications
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * The files are buffered via internal callbacks from eloop, then presented to
- * an application callback routine when completely read into memory. May also
- * be used if no file is expected but just to get the header, including HTTP
- * replies (e.g. HTTP/1.1 200 OK etc.).
- *
- * This does not attempt to be an optimally efficient implementation, but does
- * attempt to be of reasonably small size and memory consumption; assuming that
- * only small files are to be read. A maximum file size is provided by
- * application and enforced.
- *
- * It is assumed that the application does not expect any of the following:
- * -- transfer encoding other than chunked
- * -- trailer fields
- * It is assumed that, even if the other side requested that the connection be
- * kept open, that we will close it (thus HTTP messages sent by application
- * should have the connection closed field); this is allowed by HTTP/1.1 and
- * simplifies things for us.
- *
- * Other limitations:
- * -- HTTP header may not exceed a hard-coded size.
- *
- * Notes:
- * This code would be massively simpler without some of the new features of
- * HTTP/1.1, especially chunked data.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "httpread.h"
-
-
-/* Tunable parameters */
-#define HTTPREAD_READBUF_SIZE 1024      /* read in chunks of this size */
-#define HTTPREAD_HEADER_MAX_SIZE 4096   /* max allowed for headers */
-#define HTTPREAD_BODYBUF_DELTA 4096     /* increase allocation by this */
-
-#if 0
-/* httpread_debug -- set this global variable > 0 e.g. from debugger
- * to enable debugs (larger numbers for more debugs)
- * Make this a #define of 0 to eliminate the debugging code.
- */
-int httpread_debug = 99;
-#else
-#define httpread_debug 0        /* eliminates even the debugging code */
-#endif
-
-
-/* control instance -- actual definition (opaque to application)
- */
-struct httpread {
-       /* information from creation */
-       int sd;         /* descriptor of TCP socket to read from */
-       void (*cb)(struct httpread *handle, void *cookie,
-                   enum httpread_event e);  /* call on event */
-       void *cookie;   /* pass to callback */
-       int max_bytes;          /* maximum file size else abort it */
-       int timeout_seconds;            /* 0 or total duration timeout period */
-
-       /* dynamically used information follows */
-       int sd_registered;      /* nonzero if we need to unregister socket */
-       int to_registered;      /* nonzero if we need to unregister timeout */
-
-       int got_hdr;            /* nonzero when header is finalized */
-       char hdr[HTTPREAD_HEADER_MAX_SIZE+1];   /* headers stored here */
-       int hdr_nbytes;
-
-       enum httpread_hdr_type hdr_type;
-       int version;            /* 1 if we've seen 1.1 */
-       int reply_code;         /* for type REPLY, e.g. 200 for HTTP/1.1 200 OK */
-       int got_content_length; /* true if we know content length for sure */
-       int content_length;     /* body length,  iff got_content_length */
-       int chunked;            /* nonzero for chunked data */
-       char *uri;
-
-       int got_body;           /* nonzero when body is finalized */
-       char *body;
-       int body_nbytes;
-       int body_alloc_nbytes;  /* amount allocated */
-
-       int got_file;           /* here when we are done */
-
-       /* The following apply if data is chunked: */
-       int in_chunk_data;      /* 0=in/at header, 1=in the data or tail*/
-       int chunk_start;        /* offset in body of chunk hdr or data */
-       int chunk_size;         /* data of chunk (not hdr or ending CRLF)*/
-       int in_trailer;         /* in header fields after data (chunked only)*/
-       enum trailer_state {
-               trailer_line_begin = 0,
-               trailer_empty_cr,       /* empty line + CR */
-               trailer_nonempty,
-               trailer_nonempty_cr,
-       } trailer_state;
-};
-
-
-/* Check words for equality, where words consist of graphical characters
- * delimited by whitespace
- * Returns nonzero if "equal" doing case insensitive comparison.
- */
-static int word_eq(char *s1, char *s2)
-{
-       int c1;
-       int c2;
-       int end1 = 0;
-       int end2 = 0;
-       for (;;) {
-               c1 = *s1++;
-               c2 = *s2++;
-               if (isalpha(c1) && isupper(c1))
-                       c1 = tolower(c1);
-               if (isalpha(c2) && isupper(c2))
-                       c2 = tolower(c2);
-               end1 = !isgraph(c1);
-               end2 = !isgraph(c2);
-               if (end1 || end2 || c1 != c2)
-                       break;
-       }
-       return end1 && end2;  /* reached end of both words? */
-}
-
-
-/* convert hex to binary
- * Requires that c have been previously tested true with isxdigit().
- */
-static int hex_value(int c)
-{
-       if (isdigit(c))
-               return c - '0';
-       if (islower(c))
-               return 10 + c - 'a';
-       return 10 + c - 'A';
-}
-
-
-static void httpread_timeout_handler(void *eloop_data, void *user_ctx);
-
-/* httpread_destroy -- if h is non-NULL, clean up
- * This must eventually be called by the application following
- * call of the application's callback and may be called
- * earlier if desired.
- */
-void httpread_destroy(struct httpread *h)
-{
-       if (httpread_debug >= 10)
-               wpa_printf(MSG_DEBUG, "ENTER httpread_destroy(%p)", h);
-       if (!h)
-               return;
-
-       if (h->to_registered)
-               eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
-       h->to_registered = 0;
-       if (h->sd_registered)
-               eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
-       h->sd_registered = 0;
-       os_free(h->body);
-       os_free(h->uri);
-       os_memset(h, 0, sizeof(*h));  /* aid debugging */
-       h->sd = -1;     /* aid debugging */
-       os_free(h);
-}
-
-
-/* httpread_timeout_handler -- called on excessive total duration
- */
-static void httpread_timeout_handler(void *eloop_data, void *user_ctx)
-{
-       struct httpread *h = user_ctx;
-       wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h);
-       h->to_registered = 0;   /* is self-cancelling */
-       (*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT);
-}
-
-
-/* Analyze options only so far as is needed to correctly obtain the file.
- * The application can look at the raw header to find other options.
- */
-static int httpread_hdr_option_analyze(
-       struct httpread *h,
-       char *hbp       /* pointer to current line in header buffer */
-       )
-{
-       if (word_eq(hbp, "CONTENT-LENGTH:")) {
-               while (isgraph(*hbp))
-                       hbp++;
-               while (*hbp == ' ' || *hbp == '\t')
-                       hbp++;
-               if (!isdigit(*hbp))
-                       return -1;
-               h->content_length = atol(hbp);
-               h->got_content_length = 1;
-               return 0;
-       }
-       if (word_eq(hbp, "TRANSFER_ENCODING:") ||
-           word_eq(hbp, "TRANSFER-ENCODING:")) {
-               while (isgraph(*hbp))
-                       hbp++;
-               while (*hbp == ' ' || *hbp == '\t')
-                       hbp++;
-               /* There should (?) be no encodings of interest
-                * other than chunked...
-                */
-               if (word_eq(hbp, "CHUNKED")) {
-                       h->chunked = 1;
-                       h->in_chunk_data = 0;
-                       /* ignore possible ;<parameters> */
-               }
-               return 0;
-       }
-       /* skip anything we don't know, which is a lot */
-       return 0;
-}
-
-
-static int httpread_hdr_analyze(struct httpread *h)
-{
-       char *hbp = h->hdr;      /* pointer into h->hdr */
-       int standard_first_line = 1;
-
-       /* First line is special */
-       h->hdr_type = HTTPREAD_HDR_TYPE_UNKNOWN;
-       if (!isgraph(*hbp))
-               goto bad;
-       if (os_strncmp(hbp, "HTTP/", 5) == 0) {
-               h->hdr_type = HTTPREAD_HDR_TYPE_REPLY;
-               standard_first_line = 0;
-               hbp += 5;
-               if (hbp[0] == '1' && hbp[1] == '.' &&
-                   isdigit(hbp[2]) && hbp[2] != '0')
-                       h->version = 1;
-               while (isgraph(*hbp))
-                       hbp++;
-               while (*hbp == ' ' || *hbp == '\t')
-                       hbp++;
-               if (!isdigit(*hbp))
-                       goto bad;
-               h->reply_code = atol(hbp);
-       } else if (word_eq(hbp, "GET"))
-               h->hdr_type = HTTPREAD_HDR_TYPE_GET;
-       else if (word_eq(hbp, "HEAD"))
-               h->hdr_type = HTTPREAD_HDR_TYPE_HEAD;
-       else if (word_eq(hbp, "POST"))
-               h->hdr_type = HTTPREAD_HDR_TYPE_POST;
-       else if (word_eq(hbp, "PUT"))
-               h->hdr_type = HTTPREAD_HDR_TYPE_PUT;
-       else if (word_eq(hbp, "DELETE"))
-               h->hdr_type = HTTPREAD_HDR_TYPE_DELETE;
-       else if (word_eq(hbp, "TRACE"))
-               h->hdr_type = HTTPREAD_HDR_TYPE_TRACE;
-       else if (word_eq(hbp, "CONNECT"))
-               h->hdr_type = HTTPREAD_HDR_TYPE_CONNECT;
-       else if (word_eq(hbp, "NOTIFY"))
-               h->hdr_type = HTTPREAD_HDR_TYPE_NOTIFY;
-       else if (word_eq(hbp, "M-SEARCH"))
-               h->hdr_type = HTTPREAD_HDR_TYPE_M_SEARCH;
-       else if (word_eq(hbp, "M-POST"))
-               h->hdr_type = HTTPREAD_HDR_TYPE_M_POST;
-       else if (word_eq(hbp, "SUBSCRIBE"))
-               h->hdr_type = HTTPREAD_HDR_TYPE_SUBSCRIBE;
-       else if (word_eq(hbp, "UNSUBSCRIBE"))
-               h->hdr_type = HTTPREAD_HDR_TYPE_UNSUBSCRIBE;
-       else {
-       }
-
-       if (standard_first_line) {
-               char *rawuri;
-               char *uri;
-               /* skip type */
-               while (isgraph(*hbp))
-                       hbp++;
-               while (*hbp == ' ' || *hbp == '\t')
-                       hbp++;
-               /* parse uri.
-                * Find length, allocate memory for translated
-                * copy, then translate by changing %<hex><hex>
-                * into represented value.
-                */
-               rawuri = hbp;
-               while (isgraph(*hbp))
-                       hbp++;
-               h->uri = os_malloc((hbp - rawuri) + 1);
-               if (h->uri == NULL)
-                       goto bad;
-               uri = h->uri;
-               while (rawuri < hbp) {
-                       int c = *rawuri;
-                       if (c == '%' &&
-                           isxdigit(rawuri[1]) && isxdigit(rawuri[2])) {
-                               *uri++ = (hex_value(rawuri[1]) << 4) |
-                                       hex_value(rawuri[2]);
-                               rawuri += 3;
-                       } else {
-                               *uri++ = c;
-                               rawuri++;
-                       }
-               }
-               *uri = 0;       /* null terminate */
-               while (isgraph(*hbp))
-                       hbp++;
-               while (*hbp == ' ' || *hbp == '\t')
-                       hbp++;
-               /* get version */
-               if (0 == strncmp(hbp, "HTTP/", 5)) {
-                       hbp += 5;
-                       if (hbp[0] == '1' && hbp[1] == '.' &&
-                           isdigit(hbp[2]) && hbp[2] != '0')
-                               h->version = 1;
-               }
-       }
-       /* skip rest of line */
-       while (*hbp)
-               if (*hbp++ == '\n')
-                       break;
-
-       /* Remainder of lines are options, in any order;
-        * or empty line to terminate
-        */
-       for (;;) {
-               /* Empty line to terminate */
-               if (hbp[0] == '\n' ||
-                   (hbp[0] == '\r' && hbp[1] == '\n'))
-                       break;
-               if (!isgraph(*hbp))
-                       goto bad;
-               if (httpread_hdr_option_analyze(h, hbp))
-                       goto bad;
-               /* skip line */
-               while (*hbp)
-                       if (*hbp++ == '\n')
-                               break;
-       }
-
-       /* chunked overrides content-length always */
-       if (h->chunked)
-               h->got_content_length = 0;
-
-       /* For some types, we should not try to read a body
-        * This is in addition to the application determining
-        * that we should not read a body.
-        */
-       switch (h->hdr_type) {
-       case HTTPREAD_HDR_TYPE_REPLY:
-               /* Some codes can have a body and some not.
-                * For now, just assume that any other than 200
-                * do not...
-                */
-               if (h->reply_code != 200)
-                       h->max_bytes = 0;
-               break;
-       case HTTPREAD_HDR_TYPE_GET:
-       case HTTPREAD_HDR_TYPE_HEAD:
-               /* in practice it appears that it is assumed
-                * that GETs have a body length of 0... ?
-                */
-               if (h->chunked == 0 && h->got_content_length == 0)
-                       h->max_bytes = 0;
-               break;
-       case HTTPREAD_HDR_TYPE_POST:
-       case HTTPREAD_HDR_TYPE_PUT:
-       case HTTPREAD_HDR_TYPE_DELETE:
-       case HTTPREAD_HDR_TYPE_TRACE:
-       case HTTPREAD_HDR_TYPE_CONNECT:
-       case HTTPREAD_HDR_TYPE_NOTIFY:
-       case HTTPREAD_HDR_TYPE_M_SEARCH:
-       case HTTPREAD_HDR_TYPE_M_POST:
-       case HTTPREAD_HDR_TYPE_SUBSCRIBE:
-       case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
-       default:
-               break;
-       }
-
-       return 0;
-
-bad:
-       /* Error */
-       return -1;
-}
-
-
-/* httpread_read_handler -- called when socket ready to read
- *
- * Note: any extra data we read past end of transmitted file is ignored;
- * if we were to support keeping connections open for multiple files then
- * this would have to be addressed.
- */
-static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx)
-{
-       struct httpread *h = sock_ctx;
-       int nread;
-       char *rbp;      /* pointer into read buffer */
-       char *hbp;      /* pointer into header buffer */
-       char *bbp;      /* pointer into body buffer */
-       char readbuf[HTTPREAD_READBUF_SIZE];  /* temp use to read into */
-
-       if (httpread_debug >= 20)
-               wpa_printf(MSG_DEBUG, "ENTER httpread_read_handler(%p)", h);
-
-       /* read some at a time, then search for the interal
-        * boundaries between header and data and etc.
-        */
-       nread = read(h->sd, readbuf, sizeof(readbuf));
-       if (nread < 0)
-               goto bad;
-       if (nread == 0) {
-               /* end of transmission... this may be normal
-                * or may be an error... in some cases we can't
-                * tell which so we must assume it is normal then.
-                */
-               if (!h->got_hdr) {
-                       /* Must at least have completed header */
-                       wpa_printf(MSG_DEBUG, "httpread premature eof(%p)", h);
-                       goto bad;
-               }
-               if (h->chunked || h->got_content_length) {
-                       /* Premature EOF; e.g. dropped connection */
-                       wpa_printf(MSG_DEBUG,
-                                  "httpread premature eof(%p) %d/%d",
-                                  h, h->body_nbytes,
-                                  h->content_length);
-                       goto bad;
-               }
-               /* No explicit length, hopefully we have all the data
-                * although dropped connections can cause false
-                * end
-                */
-               if (httpread_debug >= 10)
-                       wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h);
-                       h->got_body = 1;
-                       goto got_file;
-       }
-       rbp = readbuf;
-
-       /* Header consists of text lines (terminated by both CR and LF)
-        * and an empty line (CR LF only).
-        */
-       if (!h->got_hdr) {
-               hbp = h->hdr + h->hdr_nbytes;
-               /* add to headers until:
-                *      -- we run out of data in read buffer
-                *      -- or, we run out of header buffer room
-                *      -- or, we get double CRLF in headers
-                */
-               for (;;) {
-                       if (nread == 0)
-                               goto get_more;
-                       if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) {
-                               goto bad;
-                       }
-                       *hbp++ = *rbp++;
-                       nread--;
-                       h->hdr_nbytes++;
-                       if (h->hdr_nbytes >= 4 &&
-                           hbp[-1] == '\n' &&
-                           hbp[-2] == '\r' &&
-                           hbp[-3] == '\n' &&
-                           hbp[-4] == '\r' ) {
-                               h->got_hdr = 1;
-                               *hbp = 0;       /* null terminate */
-                               break;
-                       }
-               }
-               /* here we've just finished reading the header */
-               if (httpread_hdr_analyze(h)) {
-                       wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h);
-                       goto bad;
-               }
-               if (h->max_bytes == 0) {
-                       if (httpread_debug >= 10)
-                               wpa_printf(MSG_DEBUG,
-                                          "httpread no body hdr end(%p)", h);
-                       goto got_file;
-               }
-               if (h->got_content_length && h->content_length == 0) {
-                       if (httpread_debug >= 10)
-                               wpa_printf(MSG_DEBUG,
-                                          "httpread zero content length(%p)",
-                                          h);
-                       goto got_file;
-               }
-       }
-
-       /* Certain types of requests never have data and so
-        * must be specially recognized.
-        */
-       if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) ||
-           !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) ||
-           !os_strncasecmp(h->hdr, "HEAD", 4) ||
-           !os_strncasecmp(h->hdr, "GET", 3)) {
-               if (!h->got_body) {
-                       if (httpread_debug >= 10)
-                               wpa_printf(MSG_DEBUG,
-                                          "httpread NO BODY for sp. type");
-               }
-               h->got_body = 1;
-               goto got_file;
-       }
-
-       /* Data can be just plain binary data, or if "chunked"
-        * consists of chunks each with a header, ending with
-        * an ending header.
-        */
-       if (nread == 0)
-               goto get_more;
-       if (!h->got_body) {
-               /* Here to get (more of) body */
-               /* ensure we have enough room for worst case for body
-                * plus a null termination character
-                */
-               if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) {
-                       char *new_body;
-                       int new_alloc_nbytes;
-
-                       if (h->body_nbytes >= h->max_bytes)
-                               goto bad;
-                       new_alloc_nbytes = h->body_alloc_nbytes +
-                               HTTPREAD_BODYBUF_DELTA;
-                       /* For content-length case, the first time
-                        * through we allocate the whole amount
-                        * we need.
-                        */
-                       if (h->got_content_length &&
-                           new_alloc_nbytes < (h->content_length + 1))
-                               new_alloc_nbytes = h->content_length + 1;
-                       if ((new_body = os_realloc(h->body, new_alloc_nbytes))
-                           == NULL)
-                               goto bad;
-
-                       h->body = new_body;
-                       h->body_alloc_nbytes = new_alloc_nbytes;
-               }
-               /* add bytes */
-               bbp = h->body + h->body_nbytes;
-               for (;;) {
-                       int ncopy;
-                       /* See if we need to stop */
-                       if (h->chunked && h->in_chunk_data == 0) {
-                               /* in chunk header */
-                               char *cbp = h->body + h->chunk_start;
-                               if (bbp-cbp >= 2 && bbp[-2] == '\r' &&
-                                   bbp[-1] == '\n') {
-                                       /* end of chunk hdr line */
-                                       /* hdr line consists solely
-                                        * of a hex numeral and CFLF
-                                        */
-                                       if (!isxdigit(*cbp))
-                                               goto bad;
-                                       h->chunk_size = strtoul(cbp, NULL, 16);
-                                       /* throw away chunk header
-                                        * so we have only real data
-                                        */
-                                       h->body_nbytes = h->chunk_start;
-                                       bbp = cbp;
-                                       if (h->chunk_size == 0) {
-                                               /* end of chunking */
-                                               /* trailer follows */
-                                               h->in_trailer = 1;
-                                               if (httpread_debug >= 20)
-                                                       wpa_printf(
-                                                               MSG_DEBUG,
-                                                               "httpread end chunks(%p)", h);
-                                               break;
-                                       }
-                                       h->in_chunk_data = 1;
-                                       /* leave chunk_start alone */
-                               }
-                       } else if (h->chunked) {
-                               /* in chunk data */
-                               if ((h->body_nbytes - h->chunk_start) ==
-                                   (h->chunk_size + 2)) {
-                                       /* end of chunk reached,
-                                        * new chunk starts
-                                        */
-                                       /* check chunk ended w/ CRLF
-                                        * which we'll throw away
-                                        */
-                                       if (bbp[-1] == '\n' &&
-                                           bbp[-2] == '\r') {
-                                       } else
-                                               goto bad;
-                                       h->body_nbytes -= 2;
-                                       bbp -= 2;
-                                       h->chunk_start = h->body_nbytes;
-                                       h->in_chunk_data = 0;
-                                       h->chunk_size = 0; /* just in case */
-                               }
-                       } else if (h->got_content_length &&
-                                  h->body_nbytes >= h->content_length) {
-                               h->got_body = 1;
-                               if (httpread_debug >= 10)
-                                       wpa_printf(
-                                               MSG_DEBUG,
-                                               "httpread got content(%p)", h);
-                               goto got_file;
-                       }
-                       if (nread <= 0)
-                               break;
-                       /* Now transfer. Optimize using memcpy where we can. */
-                       if (h->chunked && h->in_chunk_data) {
-                               /* copy up to remainder of chunk data
-                                * plus the required CR+LF at end
-                                */
-                               ncopy = (h->chunk_start + h->chunk_size + 2) -
-                                       h->body_nbytes;
-                       } else if (h->chunked) {
-                               /*in chunk header -- don't optimize */
-                               *bbp++ = *rbp++;
-                               nread--;
-                               h->body_nbytes++;
-                               continue;
-                       } else if (h->got_content_length) {
-                               ncopy = h->content_length - h->body_nbytes;
-                       } else {
-                               ncopy = nread;
-                       }
-                       /* Note: should never be 0 */
-                       if (ncopy > nread)
-                               ncopy = nread;
-                       os_memcpy(bbp, rbp, ncopy);
-                       bbp += ncopy;
-                       h->body_nbytes += ncopy;
-                       rbp += ncopy;
-                       nread -= ncopy;
-               }       /* body copy loop */
-       }       /* !got_body */
-       if (h->chunked && h->in_trailer) {
-               /* If "chunked" then there is always a trailer,
-                * consisting of zero or more non-empty lines
-                * ending with CR LF and then an empty line w/ CR LF.
-                * We do NOT support trailers except to skip them --
-                * this is supported (generally) by the http spec.
-                */
-               bbp = h->body + h->body_nbytes;
-               for (;;) {
-                       int c;
-                       if (nread <= 0)
-                               break;
-                       c = *rbp++;
-                       nread--;
-                       switch (h->trailer_state) {
-                       case trailer_line_begin:
-                               if (c == '\r')
-                                       h->trailer_state = trailer_empty_cr;
-                               else
-                                       h->trailer_state = trailer_nonempty;
-                               break;
-                       case trailer_empty_cr:
-                               /* end empty line */
-                               if (c == '\n') {
-                                       h->trailer_state = trailer_line_begin;
-                                       h->in_trailer = 0;
-                                       if (httpread_debug >= 10)
-                                               wpa_printf(
-                                                       MSG_DEBUG,
-                                                       "httpread got content(%p)", h);
-                                       h->got_body = 1;
-                                       goto got_file;
-                               }
-                               h->trailer_state = trailer_nonempty;
-                               break;
-                       case trailer_nonempty:
-                               if (c == '\r')
-                                       h->trailer_state = trailer_nonempty_cr;
-                               break;
-                       case trailer_nonempty_cr:
-                               if (c == '\n')
-                                       h->trailer_state = trailer_line_begin;
-                               else
-                                       h->trailer_state = trailer_nonempty;
-                               break;
-                       }
-               }
-       }
-       goto get_more;
-
-bad:
-       /* Error */
-       wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h);
-       (*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR);
-       return;
-
-get_more:
-       return;
-
-got_file:
-       if (httpread_debug >= 10)
-               wpa_printf(MSG_DEBUG,
-                          "httpread got file %d bytes type %d",
-                          h->body_nbytes, h->hdr_type);
-       /* Null terminate for convenience of some applications */
-       if (h->body)
-               h->body[h->body_nbytes] = 0; /* null terminate */
-       h->got_file = 1;
-       /* Assume that we do NOT support keeping connection alive,
-        * and just in case somehow we don't get destroyed right away,
-        * unregister now.
-        */
-       if (h->sd_registered)
-               eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
-       h->sd_registered = 0;
-       /* The application can destroy us whenever they feel like...
-        * cancel timeout.
-        */
-       if (h->to_registered)
-               eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
-       h->to_registered = 0;
-       (*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY);
-}
-
-
-/* httpread_create -- start a new reading session making use of eloop.
- * The new instance will use the socket descriptor for reading (until
- * it gets a file and not after) but will not close the socket, even
- * when the instance is destroyed (the application must do that).
- * Return NULL on error.
- *
- * Provided that httpread_create successfully returns a handle,
- * the callback fnc is called to handle httpread_event events.
- * The caller should do destroy on any errors or unknown events.
- *
- * Pass max_bytes == 0 to not read body at all (required for e.g.
- * reply to HEAD request).
- */
-struct httpread * httpread_create(
-       int sd,  /* descriptor of TCP socket to read from */
-       void (*cb)(struct httpread *handle, void *cookie,
-                  enum httpread_event e),  /* call on event */
-       void *cookie,    /* pass to callback */
-       int max_bytes,    /* maximum body size else abort it */
-       int timeout_seconds     /* 0; or total duration timeout period */
-       )
-{
-       struct httpread *h = NULL;
-
-       h = os_zalloc(sizeof(*h));
-       if (h == NULL)
-               goto fail;
-       h->sd = sd;
-       h->cb = cb;
-       h->cookie = cookie;
-       h->max_bytes = max_bytes;
-       h->timeout_seconds = timeout_seconds;
-
-       if (timeout_seconds > 0) {
-               if (eloop_register_timeout(timeout_seconds, 0,
-                                          httpread_timeout_handler,
-                                          NULL, h)) {
-                       /* No way to recover (from malloc failure) */
-                       goto fail;
-               }
-               h->to_registered = 1;
-       }
-       if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler,
-                               NULL, h)) {
-               /* No way to recover (from malloc failure) */
-               goto fail;
-       }
-       h->sd_registered = 1;
-       return h;
-
-fail:
-
-       /* Error */
-       httpread_destroy(h);
-       return NULL;
-}
-
-
-/* httpread_hdr_type_get -- When file is ready, returns header type. */
-enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h)
-{
-       return h->hdr_type;
-}
-
-
-/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI
- * or possibly NULL (which would be an error).
- */
-char * httpread_uri_get(struct httpread *h)
-{
-       return h->uri;
-}
-
-
-/* httpread_reply_code_get -- When reply is ready, returns reply code */
-int httpread_reply_code_get(struct httpread *h)
-{
-       return h->reply_code;
-}
-
-
-/* httpread_length_get -- When file is ready, returns file length. */
-int httpread_length_get(struct httpread *h)
-{
-       return h->body_nbytes;
-}
-
-
-/* httpread_data_get -- When file is ready, returns file content
- * with null byte appened.
- * Might return NULL in some error condition.
- */
-void * httpread_data_get(struct httpread *h)
-{
-       return h->body ? h->body : "";
-}
-
-
-/* httpread_hdr_get -- When file is ready, returns header content
- * with null byte appended.
- * Might return NULL in some error condition.
- */
-char * httpread_hdr_get(struct httpread *h)
-{
-       return h->hdr;
-}
-
-
-/* httpread_hdr_line_get -- When file is ready, returns pointer
- * to line within header content matching the given tag
- * (after the tag itself and any spaces/tabs).
- *
- * The tag should end with a colon for reliable matching.
- *
- * If not found, returns NULL;
- */
-char * httpread_hdr_line_get(struct httpread *h, const char *tag)
-{
-       int tag_len = os_strlen(tag);
-       char *hdr = h->hdr;
-       hdr = os_strchr(hdr, '\n');
-       if (hdr == NULL)
-               return NULL;
-       hdr++;
-       for (;;) {
-               if (!os_strncasecmp(hdr, tag, tag_len)) {
-                       hdr += tag_len;
-                       while (*hdr == ' ' || *hdr == '\t')
-                               hdr++;
-                       return hdr;
-               }
-               hdr = os_strchr(hdr, '\n');
-               if (hdr == NULL)
-                       return NULL;
-               hdr++;
-       }
-}