Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_httpd.c Source File

lwip_httpd.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * LWIP HTTP server implementation
00004  */
00005 
00006 /*
00007  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without modification,
00011  * are permitted provided that the following conditions are met:
00012  *
00013  * 1. Redistributions of source code must retain the above copyright notice,
00014  *    this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright notice,
00016  *    this list of conditions and the following disclaimer in the documentation
00017  *    and/or other materials provided with the distribution.
00018  * 3. The name of the author may not be used to endorse or promote products
00019  *    derived from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00023  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00024  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00026  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00029  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00030  * OF SUCH DAMAGE.
00031  *
00032  * This file is part of the lwIP TCP/IP stack.
00033  *
00034  * Author: Adam Dunkels <adam@sics.se>
00035  *         Simon Goldschmidt
00036  *
00037  */
00038 
00039 /**
00040  * @defgroup httpd HTTP server
00041  * @ingroup apps
00042  *
00043  * This httpd supports for a
00044  * rudimentary server-side-include facility which will replace tags of the form
00045  * <!--#tag--> in any file whose extension is .shtml, .shtm or .ssi with
00046  * strings provided by an include handler whose pointer is provided to the
00047  * module via function http_set_ssi_handler().
00048  * Additionally, a simple common
00049  * gateway interface (CGI) handling mechanism has been added to allow clients
00050  * to hook functions to particular request URIs.
00051  *
00052  * To enable SSI support, define label LWIP_HTTPD_SSI in lwipopts.h.
00053  * To enable CGI support, define label LWIP_HTTPD_CGI in lwipopts.h.
00054  *
00055  * By default, the server assumes that HTTP headers are already present in
00056  * each file stored in the file system.  By defining LWIP_HTTPD_DYNAMIC_HEADERS in
00057  * lwipopts.h, this behavior can be changed such that the server inserts the
00058  * headers automatically based on the extension of the file being served.  If
00059  * this mode is used, be careful to ensure that the file system image used
00060  * does not already contain the header information.
00061  *
00062  * File system images without headers can be created using the makefsfile
00063  * tool with the -h command line option.
00064  *
00065  *
00066  * Notes about valid SSI tags
00067  * --------------------------
00068  *
00069  * The following assumptions are made about tags used in SSI markers:
00070  *
00071  * 1. No tag may contain '-' or whitespace characters within the tag name.
00072  * 2. Whitespace is allowed between the tag leadin "<!--#" and the start of
00073  *    the tag name and between the tag name and the leadout string "-->".
00074  * 3. The maximum tag name length is LWIP_HTTPD_MAX_TAG_NAME_LEN, currently 8 characters.
00075  *
00076  * Notes on CGI usage
00077  * ------------------
00078  *
00079  * The simple CGI support offered here works with GET method requests only
00080  * and can handle up to 16 parameters encoded into the URI. The handler
00081  * function may not write directly to the HTTP output but must return a
00082  * filename that the HTTP server will send to the browser as a response to
00083  * the incoming CGI request.
00084  *
00085  *
00086  *
00087  * The list of supported file types is quite short, so if makefsdata complains
00088  * about an unknown extension, make sure to add it (and its doctype) to
00089  * the 'g_psHTTPHeaders' list.
00090  */
00091 #include "lwip/init.h"
00092 #include "lwip/apps/httpd.h"
00093 #include "lwip/debug.h"
00094 #include "lwip/stats.h"
00095 #include "lwip/apps/fs.h"
00096 #include "httpd_structs.h"
00097 #include "lwip/def.h"
00098 #include "lwip/ip.h"
00099 #include "lwip/tcp.h"
00100 
00101 #include <string.h> /* memset */
00102 #include <stdlib.h> /* atoi */
00103 #include <stdio.h>
00104 
00105 #if LWIP_TCP && LWIP_CALLBACK_API
00106 
00107 /** Minimum length for a valid HTTP/0.9 request: "GET /\r\n" -> 7 bytes */
00108 #define MIN_REQ_LEN   7
00109 
00110 #define CRLF "\r\n"
00111 #if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
00112 #define HTTP11_CONNECTIONKEEPALIVE  "Connection: keep-alive"
00113 #define HTTP11_CONNECTIONKEEPALIVE2 "Connection: Keep-Alive"
00114 #endif
00115 
00116 /** These defines check whether tcp_write has to copy data or not */
00117 
00118 /** This was TI's check whether to let TCP copy data or not
00119  * \#define HTTP_IS_DATA_VOLATILE(hs) ((hs->file < (char *)0x20000000) ? 0 : TCP_WRITE_FLAG_COPY)
00120  */
00121 #ifndef HTTP_IS_DATA_VOLATILE
00122 #if LWIP_HTTPD_SSI
00123 /* Copy for SSI files, no copy for non-SSI files */
00124 #define HTTP_IS_DATA_VOLATILE(hs)   ((hs)->ssi ? TCP_WRITE_FLAG_COPY : 0)
00125 #else /* LWIP_HTTPD_SSI */
00126 /** Default: don't copy if the data is sent from file-system directly */
00127 #define HTTP_IS_DATA_VOLATILE(hs) (((hs->file != NULL) && (hs->handle != NULL) && (hs->file == \
00128                                    (const char*)hs->handle->data + hs->handle->len - hs->left)) \
00129                                    ? 0 : TCP_WRITE_FLAG_COPY)
00130 #endif /* LWIP_HTTPD_SSI */
00131 #endif
00132 
00133 /** Default: headers are sent from ROM */
00134 #ifndef HTTP_IS_HDR_VOLATILE
00135 #define HTTP_IS_HDR_VOLATILE(hs, ptr) 0
00136 #endif
00137 
00138 /* Return values for http_send_*() */
00139 #define HTTP_DATA_TO_SEND_BREAK    2
00140 #define HTTP_DATA_TO_SEND_CONTINUE 1
00141 #define HTTP_NO_DATA_TO_SEND       0
00142 
00143 typedef struct
00144 {
00145   const char *name;
00146   u8_t shtml;
00147 } default_filename;
00148 
00149 const default_filename g_psDefaultFilenames[] = {
00150   {"/index.shtml", 1 },
00151   {"/index.ssi",   1 },
00152   {"/index.shtm",  1 },
00153   {"/index.html",  0 },
00154   {"/index.htm",   0 }
00155 };
00156 
00157 #define NUM_DEFAULT_FILENAMES (sizeof(g_psDefaultFilenames) /   \
00158                                sizeof(default_filename))
00159 
00160 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
00161 /** HTTP request is copied here from pbufs for simple parsing */
00162 static char httpd_req_buf[LWIP_HTTPD_MAX_REQ_LENGTH+1];
00163 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
00164 
00165 #if LWIP_HTTPD_SUPPORT_POST
00166 #if LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN > LWIP_HTTPD_MAX_REQUEST_URI_LEN
00167 #define LWIP_HTTPD_URI_BUF_LEN LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN
00168 #endif
00169 #endif
00170 #ifndef LWIP_HTTPD_URI_BUF_LEN
00171 #define LWIP_HTTPD_URI_BUF_LEN LWIP_HTTPD_MAX_REQUEST_URI_LEN
00172 #endif
00173 #if LWIP_HTTPD_URI_BUF_LEN
00174 /* Filename for response file to send when POST is finished or
00175  * search for default files when a directory is requested. */
00176 static char http_uri_buf[LWIP_HTTPD_URI_BUF_LEN+1];
00177 #endif
00178 
00179 #if LWIP_HTTPD_DYNAMIC_HEADERS
00180 /* The number of individual strings that comprise the headers sent before each
00181  * requested file.
00182  */
00183 #define NUM_FILE_HDR_STRINGS 5
00184 #define HDR_STRINGS_IDX_HTTP_STATUS          0 /* e.g. "HTTP/1.0 200 OK\r\n" */
00185 #define HDR_STRINGS_IDX_SERVER_NAME          1 /* e.g. "Server: "HTTPD_SERVER_AGENT"\r\n" */
00186 #define HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE 2 /* e.g. "Content-Length: xy\r\n" and/or "Connection: keep-alive\r\n" */
00187 #define HDR_STRINGS_IDX_CONTENT_LEN_NR       3 /* the byte count, when content-length is used */
00188 #define HDR_STRINGS_IDX_CONTENT_TYPE         4 /* the content type (or default answer content type including default document) */
00189 
00190 /* The dynamically generated Content-Length buffer needs space for CRLF + NULL */
00191 #define LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET 3
00192 #ifndef LWIP_HTTPD_MAX_CONTENT_LEN_SIZE
00193 /* The dynamically generated Content-Length buffer shall be able to work with
00194    ~953 MB (9 digits) */
00195 #define LWIP_HTTPD_MAX_CONTENT_LEN_SIZE   (9 + LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET)
00196 #endif
00197 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
00198 
00199 #if LWIP_HTTPD_SSI
00200 
00201 #define HTTPD_LAST_TAG_PART 0xFFFF
00202 
00203 enum tag_check_state {
00204   TAG_NONE,       /* Not processing an SSI tag */
00205   TAG_LEADIN,     /* Tag lead in "<!--#" being processed */
00206   TAG_FOUND,      /* Tag name being read, looking for lead-out start */
00207   TAG_LEADOUT,    /* Tag lead out "-->" being processed */
00208   TAG_SENDING     /* Sending tag replacement string */
00209 };
00210 
00211 struct http_ssi_state {
00212   const char *parsed;     /* Pointer to the first unparsed byte in buf. */
00213 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
00214   const char *tag_started;/* Pointer to the first opening '<' of the tag. */
00215 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */
00216   const char *tag_end;    /* Pointer to char after the closing '>' of the tag. */
00217   u32_t parse_left; /* Number of unparsed bytes in buf. */
00218   u16_t tag_index;   /* Counter used by tag parsing state machine */
00219   u16_t tag_insert_len; /* Length of insert in string tag_insert */
00220 #if LWIP_HTTPD_SSI_MULTIPART
00221   u16_t tag_part; /* Counter passed to and changed by tag insertion function to insert multiple times */
00222 #endif /* LWIP_HTTPD_SSI_MULTIPART */
00223   u8_t tag_name_len; /* Length of the tag name in string tag_name */
00224   char tag_name[LWIP_HTTPD_MAX_TAG_NAME_LEN + 1]; /* Last tag name extracted */
00225   char tag_insert[LWIP_HTTPD_MAX_TAG_INSERT_LEN + 1]; /* Insert string for tag_name */
00226   enum tag_check_state tag_state; /* State of the tag processor */
00227 };
00228 #endif /* LWIP_HTTPD_SSI */
00229 
00230 struct http_state {
00231 #if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
00232   struct http_state *next;
00233 #endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
00234   struct fs_file file_handle;
00235   struct fs_file *handle;
00236   const char *file;       /* Pointer to first unsent byte in buf. */
00237 
00238   struct tcp_pcb *pcb;
00239 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
00240   struct pbuf *req;
00241 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
00242 
00243 #if LWIP_HTTPD_DYNAMIC_FILE_READ
00244   char *buf;        /* File read buffer. */
00245   int buf_len;      /* Size of file read buffer, buf. */
00246 #endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
00247   u32_t left;       /* Number of unsent bytes in buf. */
00248   u8_t retries;
00249 #if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
00250   u8_t keepalive;
00251 #endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
00252 #if LWIP_HTTPD_SSI
00253   struct http_ssi_state *ssi;
00254 #endif /* LWIP_HTTPD_SSI */
00255 #if LWIP_HTTPD_CGI
00256   char *params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */
00257   char *param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */
00258 #endif /* LWIP_HTTPD_CGI */
00259 #if LWIP_HTTPD_DYNAMIC_HEADERS
00260   const char *hdrs[NUM_FILE_HDR_STRINGS]; /* HTTP headers to be sent. */
00261   char hdr_content_len[LWIP_HTTPD_MAX_CONTENT_LEN_SIZE];
00262   u16_t hdr_pos;     /* The position of the first unsent header byte in the
00263                         current string */
00264   u16_t hdr_index;   /* The index of the hdr string currently being sent. */
00265 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
00266 #if LWIP_HTTPD_TIMING
00267   u32_t time_started;
00268 #endif /* LWIP_HTTPD_TIMING */
00269 #if LWIP_HTTPD_SUPPORT_POST
00270   u32_t post_content_len_left;
00271 #if LWIP_HTTPD_POST_MANUAL_WND
00272   u32_t unrecved_bytes;
00273   u8_t no_auto_wnd;
00274   u8_t post_finished;
00275 #endif /* LWIP_HTTPD_POST_MANUAL_WND */
00276 #endif /* LWIP_HTTPD_SUPPORT_POST*/
00277 };
00278 
00279 #if HTTPD_USE_MEM_POOL
00280 LWIP_MEMPOOL_DECLARE(HTTPD_STATE,     MEMP_NUM_PARALLEL_HTTPD_CONNS,     sizeof(struct http_state),     "HTTPD_STATE")
00281 #if LWIP_HTTPD_SSI
00282 LWIP_MEMPOOL_DECLARE(HTTPD_SSI_STATE, MEMP_NUM_PARALLEL_HTTPD_SSI_CONNS, sizeof(struct http_ssi_state), "HTTPD_SSI_STATE")
00283 #define HTTP_FREE_SSI_STATE(x)  LWIP_MEMPOOL_FREE(HTTPD_SSI_STATE, (x))
00284 #define HTTP_ALLOC_SSI_STATE()  (struct http_ssi_state *)LWIP_MEMPOOL_ALLOC(HTTPD_SSI_STATE)
00285 #endif /* LWIP_HTTPD_SSI */
00286 #define HTTP_ALLOC_HTTP_STATE() (struct http_state *)LWIP_MEMPOOL_ALLOC(HTTPD_STATE)
00287 #define HTTP_FREE_HTTP_STATE(x) LWIP_MEMPOOL_FREE(HTTPD_STATE, (x))
00288 #else /* HTTPD_USE_MEM_POOL */
00289 #define HTTP_ALLOC_HTTP_STATE() (struct http_state *)mem_malloc(sizeof(struct http_state))
00290 #define HTTP_FREE_HTTP_STATE(x) mem_free(x)
00291 #if LWIP_HTTPD_SSI
00292 #define HTTP_ALLOC_SSI_STATE()  (struct http_ssi_state *)mem_malloc(sizeof(struct http_ssi_state))
00293 #define HTTP_FREE_SSI_STATE(x)  mem_free(x)
00294 #endif /* LWIP_HTTPD_SSI */
00295 #endif /* HTTPD_USE_MEM_POOL */
00296 
00297 static err_t http_close_conn(struct tcp_pcb *pcb, struct http_state *hs);
00298 static err_t http_close_or_abort_conn(struct tcp_pcb *pcb, struct http_state *hs, u8_t abort_conn);
00299 static err_t http_find_file(struct http_state *hs, const char *uri, int is_09);
00300 static err_t http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri, u8_t tag_check, char* params);
00301 static err_t http_poll(void *arg, struct tcp_pcb *pcb);
00302 static u8_t http_check_eof(struct tcp_pcb *pcb, struct http_state *hs);
00303 #if LWIP_HTTPD_FS_ASYNC_READ
00304 static void http_continue(void *connection);
00305 #endif /* LWIP_HTTPD_FS_ASYNC_READ */
00306 
00307 #if LWIP_HTTPD_SSI
00308 /* SSI insert handler function pointer. */
00309 tSSIHandler g_pfnSSIHandler;
00310 #if !LWIP_HTTPD_SSI_RAW
00311 int g_iNumTags;
00312 const char **g_ppcTags;
00313 #endif /* !LWIP_HTTPD_SSI_RAW */
00314 
00315 #define LEN_TAG_LEAD_IN 5
00316 const char * const g_pcTagLeadIn = "<!--#";
00317 
00318 #define LEN_TAG_LEAD_OUT 3
00319 const char * const g_pcTagLeadOut = "-->";
00320 #endif /* LWIP_HTTPD_SSI */
00321 
00322 #if LWIP_HTTPD_CGI
00323 /* CGI handler information */
00324 const tCGI *g_pCGIs;
00325 int g_iNumCGIs;
00326 int http_cgi_paramcount;
00327 #define http_cgi_params     hs->params
00328 #define http_cgi_param_vals hs->param_vals
00329 #elif LWIP_HTTPD_CGI_SSI
00330 char *http_cgi_params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */
00331 char *http_cgi_param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */
00332 #endif /* LWIP_HTTPD_CGI */
00333 
00334 #if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
00335 /** global list of active HTTP connections, use to kill the oldest when
00336     running out of memory */
00337 static struct http_state *http_connections;
00338 
00339 static void
00340 http_add_connection(struct http_state *hs)
00341 {
00342   /* add the connection to the list */
00343   hs->next = http_connections;
00344   http_connections = hs;
00345 }
00346 
00347 static void
00348 http_remove_connection(struct http_state *hs)
00349 {
00350   /* take the connection off the list */
00351   if (http_connections) {
00352     if (http_connections == hs) {
00353       http_connections = hs->next;
00354     } else {
00355       struct http_state *last;
00356       for(last = http_connections; last->next != NULL; last = last->next) {
00357         if (last->next == hs) {
00358           last->next = hs->next;
00359           break;
00360         }
00361       }
00362     }
00363   }
00364 }
00365 
00366 static void
00367 http_kill_oldest_connection(u8_t ssi_required)
00368 {
00369   struct http_state *hs = http_connections;
00370   struct http_state *hs_free_next = NULL;
00371   while(hs && hs->next) {
00372 #if LWIP_HTTPD_SSI
00373     if (ssi_required) {
00374       if (hs->next->ssi != NULL) {
00375         hs_free_next = hs;
00376       }
00377     } else
00378 #else /* LWIP_HTTPD_SSI */
00379     LWIP_UNUSED_ARG(ssi_required);
00380 #endif /* LWIP_HTTPD_SSI */
00381     {
00382       hs_free_next = hs;
00383     }
00384     LWIP_ASSERT("broken list", hs != hs->next);
00385     hs = hs->next;
00386   }
00387   if (hs_free_next != NULL) {
00388     LWIP_ASSERT("hs_free_next->next != NULL", hs_free_next->next != NULL);
00389     LWIP_ASSERT("hs_free_next->next->pcb != NULL", hs_free_next->next->pcb != NULL);
00390     /* send RST when killing a connection because of memory shortage */
00391     http_close_or_abort_conn(hs_free_next->next->pcb, hs_free_next->next, 1); /* this also unlinks the http_state from the list */
00392   }
00393 }
00394 #else /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
00395 
00396 #define http_add_connection(hs)
00397 #define http_remove_connection(hs)
00398 
00399 #endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
00400 
00401 #if LWIP_HTTPD_SSI
00402 /** Allocate as struct http_ssi_state. */
00403 static struct http_ssi_state*
00404 http_ssi_state_alloc(void)
00405 {
00406   struct http_ssi_state *ret = HTTP_ALLOC_SSI_STATE();
00407 #if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
00408   if (ret == NULL) {
00409     http_kill_oldest_connection(1);
00410     ret = HTTP_ALLOC_SSI_STATE();
00411   }
00412 #endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
00413   if (ret != NULL) {
00414     memset(ret, 0, sizeof(struct http_ssi_state));
00415   }
00416   return ret;
00417 }
00418 
00419 /** Free a struct http_ssi_state. */
00420 static void
00421 http_ssi_state_free(struct http_ssi_state *ssi)
00422 {
00423   if (ssi != NULL) {
00424     HTTP_FREE_SSI_STATE(ssi);
00425   }
00426 }
00427 #endif /* LWIP_HTTPD_SSI */
00428 
00429 /** Initialize a struct http_state.
00430  */
00431 static void
00432 http_state_init(struct http_state* hs)
00433 {
00434   /* Initialize the structure. */
00435   memset(hs, 0, sizeof(struct http_state));
00436 #if LWIP_HTTPD_DYNAMIC_HEADERS
00437   /* Indicate that the headers are not yet valid */
00438   hs->hdr_index = NUM_FILE_HDR_STRINGS;
00439 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
00440 }
00441 
00442 /** Allocate a struct http_state. */
00443 static struct http_state*
00444 http_state_alloc(void)
00445 {
00446   struct http_state *ret = HTTP_ALLOC_HTTP_STATE();
00447 #if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
00448   if (ret == NULL) {
00449     http_kill_oldest_connection(0);
00450     ret = HTTP_ALLOC_HTTP_STATE();
00451   }
00452 #endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
00453   if (ret != NULL) {
00454     http_state_init(ret);
00455     http_add_connection(ret);
00456   }
00457   return ret;
00458 }
00459 
00460 /** Free a struct http_state.
00461  * Also frees the file data if dynamic.
00462  */
00463 static void
00464 http_state_eof(struct http_state *hs)
00465 {
00466   if(hs->handle) {
00467 #if LWIP_HTTPD_TIMING
00468     u32_t ms_needed = sys_now() - hs->time_started;
00469     u32_t needed = LWIP_MAX(1, (ms_needed/100));
00470     LWIP_DEBUGF(HTTPD_DEBUG_TIMING, ("httpd: needed %"U32_F" ms to send file of %d bytes -> %"U32_F" bytes/sec\n",
00471       ms_needed, hs->handle->len, ((((u32_t)hs->handle->len) * 10) / needed)));
00472 #endif /* LWIP_HTTPD_TIMING */
00473     fs_close(hs->handle);
00474     hs->handle = NULL;
00475   }
00476 #if LWIP_HTTPD_DYNAMIC_FILE_READ
00477   if (hs->buf != NULL) {
00478     mem_free(hs->buf);
00479     hs->buf = NULL;
00480   }
00481 #endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
00482 #if LWIP_HTTPD_SSI
00483   if (hs->ssi) {
00484     http_ssi_state_free(hs->ssi);
00485     hs->ssi = NULL;
00486   }
00487 #endif /* LWIP_HTTPD_SSI */
00488 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
00489   if (hs->req) {
00490     pbuf_free(hs->req);
00491     hs->req = NULL;
00492   }
00493 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
00494 }
00495 
00496 /** Free a struct http_state.
00497  * Also frees the file data if dynamic.
00498  */
00499 static void
00500 http_state_free(struct http_state *hs)
00501 {
00502   if (hs != NULL) {
00503     http_state_eof(hs);
00504     http_remove_connection(hs);
00505     HTTP_FREE_HTTP_STATE(hs);
00506   }
00507 }
00508 
00509 /** Call tcp_write() in a loop trying smaller and smaller length
00510  *
00511  * @param pcb tcp_pcb to send
00512  * @param ptr Data to send
00513  * @param length Length of data to send (in/out: on return, contains the
00514  *        amount of data sent)
00515  * @param apiflags directly passed to tcp_write
00516  * @return the return value of tcp_write
00517  */
00518 static err_t
00519 http_write(struct tcp_pcb *pcb, const void* ptr, u16_t *length, u8_t apiflags)
00520 {
00521   u16_t len, max_len;
00522   err_t err;
00523   LWIP_ASSERT("length != NULL", length != NULL);
00524   len = *length;
00525   if (len == 0) {
00526     return ERR_OK;
00527   }
00528   /* We cannot send more data than space available in the send buffer. */
00529   max_len = tcp_sndbuf(pcb);
00530   if (max_len < len) {
00531     len = max_len;
00532   }
00533 #ifdef HTTPD_MAX_WRITE_LEN
00534   /* Additional limitation: e.g. don't enqueue more than 2*mss at once */
00535   max_len = HTTPD_MAX_WRITE_LEN(pcb);
00536   if(len > max_len) {
00537     len = max_len;
00538   }
00539 #endif /* HTTPD_MAX_WRITE_LEN */
00540   do {
00541     LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Trying go send %d bytes\n", len));
00542     err = tcp_write(pcb, ptr, len, apiflags);
00543     if (err == ERR_MEM) {
00544       if ((tcp_sndbuf(pcb) == 0) ||
00545         (tcp_sndqueuelen(pcb) >= TCP_SND_QUEUELEN)) {
00546           /* no need to try smaller sizes */
00547           len = 1;
00548       } else {
00549         len /= 2;
00550       }
00551       LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, 
00552         ("Send failed, trying less (%d bytes)\n", len));
00553     }
00554   } while ((err == ERR_MEM) && (len > 1));
00555 
00556   if (err == ERR_OK) {
00557     LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Sent %d bytes\n", len));
00558     *length = len;
00559   } else {
00560     LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Send failed with err %d (\"%s\")\n", err, lwip_strerr(err)));
00561     *length = 0;
00562   }
00563 
00564 #if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
00565    /* ensure nagle is normally enabled (only disabled for persistent connections
00566       when all data has been enqueued but the connection stays open for the next
00567       request */
00568    tcp_nagle_enable(pcb);
00569 #endif
00570 
00571   return err;
00572 }
00573 
00574 /**
00575  * The connection shall be actively closed (using RST to close from fault states).
00576  * Reset the sent- and recv-callbacks.
00577  *
00578  * @param pcb the tcp pcb to reset callbacks
00579  * @param hs connection state to free
00580  */
00581 static err_t
00582 http_close_or_abort_conn(struct tcp_pcb *pcb, struct http_state *hs, u8_t abort_conn)
00583 {
00584   err_t err;
00585   LWIP_DEBUGF(HTTPD_DEBUG, ("Closing connection %p\n", (void*)pcb));
00586 
00587 #if LWIP_HTTPD_SUPPORT_POST
00588   if (hs != NULL) {
00589     if ((hs->post_content_len_left != 0)
00590 #if LWIP_HTTPD_POST_MANUAL_WND
00591        || ((hs->no_auto_wnd != 0) && (hs->unrecved_bytes != 0))
00592 #endif /* LWIP_HTTPD_POST_MANUAL_WND */
00593        ) {
00594       /* make sure the post code knows that the connection is closed */
00595       http_uri_buf[0] = 0;
00596       httpd_post_finished(hs, http_uri_buf, LWIP_HTTPD_URI_BUF_LEN);
00597     }
00598   }
00599 #endif /* LWIP_HTTPD_SUPPORT_POST*/
00600 
00601 
00602   tcp_arg(pcb, NULL);
00603   tcp_recv(pcb, NULL);
00604   tcp_err(pcb, NULL);
00605   tcp_poll(pcb, NULL, 0);
00606   tcp_sent(pcb, NULL);
00607   if (hs != NULL) {
00608     http_state_free(hs);
00609   }
00610 
00611   if (abort_conn) {
00612     tcp_abort(pcb);
00613     return ERR_OK;
00614   }
00615   err = tcp_close(pcb);
00616   if (err != ERR_OK) {
00617     LWIP_DEBUGF(HTTPD_DEBUG, ("Error %d closing %p\n", err, (void*)pcb));
00618     /* error closing, try again later in poll */
00619     tcp_poll(pcb, http_poll, HTTPD_POLL_INTERVAL);
00620   }
00621   return err;
00622 }
00623 
00624 /**
00625  * The connection shall be actively closed.
00626  * Reset the sent- and recv-callbacks.
00627  *
00628  * @param pcb the tcp pcb to reset callbacks
00629  * @param hs connection state to free
00630  */
00631 static err_t
00632 http_close_conn(struct tcp_pcb *pcb, struct http_state *hs)
00633 {
00634    return http_close_or_abort_conn(pcb, hs, 0);
00635 }
00636 
00637 /** End of file: either close the connection (Connection: close) or
00638  * close the file (Connection: keep-alive)
00639  */
00640 static void
00641 http_eof(struct tcp_pcb *pcb, struct http_state *hs)
00642 {
00643   /* HTTP/1.1 persistent connection? (Not supported for SSI) */
00644 #if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
00645   if (hs->keepalive) {
00646     http_remove_connection(hs);
00647 
00648     http_state_eof(hs);
00649     http_state_init(hs);
00650     /* restore state: */
00651     hs->pcb = pcb;
00652     hs->keepalive = 1;
00653     http_add_connection(hs);
00654     /* ensure nagle doesn't interfere with sending all data as fast as possible: */
00655     tcp_nagle_disable(pcb);
00656   } else
00657 #endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
00658   {
00659     http_close_conn(pcb, hs);
00660   }
00661 }
00662 
00663 #if LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI
00664 /**
00665  * Extract URI parameters from the parameter-part of an URI in the form
00666  * "test.cgi?x=y" @todo: better explanation!
00667  * Pointers to the parameters are stored in hs->param_vals.
00668  *
00669  * @param hs http connection state
00670  * @param params pointer to the NULL-terminated parameter string from the URI
00671  * @return number of parameters extracted
00672  */
00673 static int
00674 extract_uri_parameters(struct http_state *hs, char *params)
00675 {
00676   char *pair;
00677   char *equals;
00678   int loop;
00679 
00680   LWIP_UNUSED_ARG(hs);
00681 
00682   /* If we have no parameters at all, return immediately. */
00683   if(!params || (params[0] == '\0')) {
00684       return(0);
00685   }
00686 
00687   /* Get a pointer to our first parameter */
00688   pair = params;
00689 
00690   /* Parse up to LWIP_HTTPD_MAX_CGI_PARAMETERS from the passed string and ignore the
00691    * remainder (if any) */
00692   for(loop = 0; (loop < LWIP_HTTPD_MAX_CGI_PARAMETERS) && pair; loop++) {
00693 
00694     /* Save the name of the parameter */
00695     http_cgi_params[loop] = pair;
00696 
00697     /* Remember the start of this name=value pair */
00698     equals = pair;
00699 
00700     /* Find the start of the next name=value pair and replace the delimiter
00701      * with a 0 to terminate the previous pair string. */
00702     pair = strchr(pair, '&');
00703     if(pair) {
00704       *pair = '\0';
00705       pair++;
00706     } else {
00707        /* We didn't find a new parameter so find the end of the URI and
00708         * replace the space with a '\0' */
00709         pair = strchr(equals, ' ');
00710         if(pair) {
00711             *pair = '\0';
00712         }
00713 
00714         /* Revert to NULL so that we exit the loop as expected. */
00715         pair = NULL;
00716     }
00717 
00718     /* Now find the '=' in the previous pair, replace it with '\0' and save
00719      * the parameter value string. */
00720     equals = strchr(equals, '=');
00721     if(equals) {
00722       *equals = '\0';
00723       http_cgi_param_vals[loop] = equals + 1;
00724     } else {
00725       http_cgi_param_vals[loop] = NULL;
00726     }
00727   }
00728 
00729   return loop;
00730 }
00731 #endif /* LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI */
00732 
00733 #if LWIP_HTTPD_SSI
00734 /**
00735  * Insert a tag (found in an shtml in the form of "<!--#tagname-->" into the file.
00736  * The tag's name is stored in ssi->tag_name (NULL-terminated), the replacement
00737  * should be written to hs->tag_insert (up to a length of LWIP_HTTPD_MAX_TAG_INSERT_LEN).
00738  * The amount of data written is stored to ssi->tag_insert_len.
00739  *
00740  * @todo: return tag_insert_len - maybe it can be removed from struct http_state?
00741  *
00742  * @param hs http connection state
00743  */
00744 static void
00745 get_tag_insert(struct http_state *hs)
00746 {
00747 #if LWIP_HTTPD_SSI_RAW
00748   const char* tag;
00749 #else /* LWIP_HTTPD_SSI_RAW */
00750   int tag;
00751 #endif /* LWIP_HTTPD_SSI_RAW */
00752   size_t len;
00753   struct http_ssi_state *ssi;
00754 #if LWIP_HTTPD_SSI_MULTIPART
00755   u16_t current_tag_part;
00756 #endif /* LWIP_HTTPD_SSI_MULTIPART */
00757 
00758   LWIP_ASSERT("hs != NULL", hs != NULL);
00759   ssi = hs->ssi;
00760   LWIP_ASSERT("ssi != NULL", ssi != NULL);
00761 #if LWIP_HTTPD_SSI_MULTIPART
00762   current_tag_part = ssi->tag_part;
00763   ssi->tag_part = HTTPD_LAST_TAG_PART;
00764 #endif /* LWIP_HTTPD_SSI_MULTIPART */
00765 #if LWIP_HTTPD_SSI_RAW
00766   tag = ssi->tag_name;
00767 #endif
00768 
00769   if(g_pfnSSIHandler
00770 #if !LWIP_HTTPD_SSI_RAW
00771      && g_ppcTags && g_iNumTags
00772 #endif /* !LWIP_HTTPD_SSI_RAW */
00773      ) {
00774 
00775     /* Find this tag in the list we have been provided. */
00776 #if LWIP_HTTPD_SSI_RAW
00777     {
00778 #else /* LWIP_HTTPD_SSI_RAW */
00779     for(tag = 0; tag < g_iNumTags; tag++) {
00780       if(strcmp(ssi->tag_name, g_ppcTags[tag]) == 0)
00781 #endif /* LWIP_HTTPD_SSI_RAW */
00782       {
00783         ssi->tag_insert_len = g_pfnSSIHandler(tag, ssi->tag_insert,
00784            LWIP_HTTPD_MAX_TAG_INSERT_LEN
00785 #if LWIP_HTTPD_SSI_MULTIPART
00786            , current_tag_part, &ssi->tag_part
00787 #endif /* LWIP_HTTPD_SSI_MULTIPART */
00788 #if LWIP_HTTPD_FILE_STATE
00789            , (hs->handle ? hs->handle->state : NULL)
00790 #endif /* LWIP_HTTPD_FILE_STATE */
00791            );
00792 #if LWIP_HTTPD_SSI_RAW
00793         if (ssi->tag_insert_len != HTTPD_SSI_TAG_UNKNOWN)
00794 #endif /* LWIP_HTTPD_SSI_RAW */
00795         {
00796           return;
00797         }
00798       }
00799     }
00800   }
00801 
00802   /* If we drop out, we were asked to serve a page which contains tags that
00803    * we don't have a handler for. Merely echo back the tags with an error
00804    * marker. */
00805 #define UNKNOWN_TAG1_TEXT "<b>***UNKNOWN TAG "
00806 #define UNKNOWN_TAG1_LEN  18
00807 #define UNKNOWN_TAG2_TEXT "***</b>"
00808 #define UNKNOWN_TAG2_LEN  7
00809   len = LWIP_MIN(sizeof(ssi->tag_name), LWIP_MIN(strlen(ssi->tag_name),
00810     LWIP_HTTPD_MAX_TAG_INSERT_LEN - (UNKNOWN_TAG1_LEN + UNKNOWN_TAG2_LEN)));
00811   MEMCPY(ssi->tag_insert, UNKNOWN_TAG1_TEXT, UNKNOWN_TAG1_LEN);
00812   MEMCPY(&ssi->tag_insert[UNKNOWN_TAG1_LEN], ssi->tag_name, len);
00813   MEMCPY(&ssi->tag_insert[UNKNOWN_TAG1_LEN + len], UNKNOWN_TAG2_TEXT, UNKNOWN_TAG2_LEN);
00814   ssi->tag_insert[UNKNOWN_TAG1_LEN + len + UNKNOWN_TAG2_LEN] = 0;
00815 
00816   len = strlen(ssi->tag_insert);
00817   LWIP_ASSERT("len <= 0xffff", len <= 0xffff);
00818   ssi->tag_insert_len = (u16_t)len;
00819 }
00820 #endif /* LWIP_HTTPD_SSI */
00821 
00822 #if LWIP_HTTPD_DYNAMIC_HEADERS
00823 /**
00824  * Generate the relevant HTTP headers for the given filename and write
00825  * them into the supplied buffer.
00826  */
00827 static void
00828 get_http_headers(struct http_state *hs, const char *uri)
00829 {
00830   size_t content_type;
00831   char *tmp;
00832   char *ext;
00833   char *vars;
00834   u8_t add_content_len;
00835 
00836   /* In all cases, the second header we send is the server identification
00837      so set it here. */
00838   hs->hdrs[HDR_STRINGS_IDX_SERVER_NAME] = g_psHTTPHeaderStrings[HTTP_HDR_SERVER];
00839   hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE] = NULL;
00840   hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_NR] = NULL;
00841 
00842   /* Is this a normal file or the special case we use to send back the
00843      default "404: Page not found" response? */
00844   if (uri == NULL) {
00845     hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND];
00846 #if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
00847     if (hs->keepalive) {
00848       hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = g_psHTTPHeaderStrings[DEFAULT_404_HTML_PERSISTENT];
00849     } else
00850 #endif
00851     {
00852       hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = g_psHTTPHeaderStrings[DEFAULT_404_HTML];
00853     }
00854 
00855     /* Set up to send the first header string. */
00856     hs->hdr_index = 0;
00857     hs->hdr_pos = 0;
00858     return;
00859   }
00860   /* We are dealing with a particular filename. Look for one other
00861       special case.  We assume that any filename with "404" in it must be
00862       indicative of a 404 server error whereas all other files require
00863       the 200 OK header. */
00864   if (strstr(uri, "404")) {
00865     hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND];
00866   } else if (strstr(uri, "400")) {
00867     hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_BAD_REQUEST];
00868   } else if (strstr(uri, "501")) {
00869     hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_IMPL];
00870   } else {
00871     hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_OK];
00872   }
00873 
00874   /* Determine if the URI has any variables and, if so, temporarily remove 
00875       them. */
00876   vars = strchr(uri, '?');
00877   if(vars) {
00878     *vars = '\0';
00879   }
00880 
00881   /* Get a pointer to the file extension.  We find this by looking for the
00882       last occurrence of "." in the filename passed. */
00883   ext = NULL;
00884   tmp = strchr(uri, '.');
00885   while (tmp) {
00886     ext = tmp + 1;
00887     tmp = strchr(ext, '.');
00888   }
00889   if (ext != NULL) {
00890     /* Now determine the content type and add the relevant header for that. */
00891     for (content_type = 0; content_type < NUM_HTTP_HEADERS; content_type++) {
00892       /* Have we found a matching extension? */
00893       if(!lwip_stricmp(g_psHTTPHeaders[content_type].extension, ext)) {
00894         break;
00895       }
00896     }
00897   } else {
00898     content_type = NUM_HTTP_HEADERS;
00899   }
00900 
00901   /* Reinstate the parameter marker if there was one in the original URI. */
00902   if (vars) {
00903     *vars = '?';
00904   }
00905 
00906 #if LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI
00907   /* Does the URL passed have any file extension?  If not, we assume it
00908      is a special-case URL used for control state notification and we do
00909      not send any HTTP headers with the response. */
00910   if (!ext) {
00911     /* Force the header index to a value indicating that all headers
00912        have already been sent. */
00913     hs->hdr_index = NUM_FILE_HDR_STRINGS;
00914     return;
00915   }
00916 #endif /* LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI */
00917   add_content_len = 1;
00918   /* Did we find a matching extension? */
00919   if(content_type < NUM_HTTP_HEADERS) {
00920     /* yes, store it */
00921     hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = g_psHTTPHeaders[content_type].content_type;
00922   } else if (!ext) {
00923     /* no, no extension found -> use binary transfer to prevent the browser adding '.txt' on save */
00924     hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = HTTP_HDR_APP;
00925   } else {
00926     /* No - use the default, plain text file type. */
00927     hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = HTTP_HDR_DEFAULT_TYPE;
00928   }
00929   /* Add content-length header? */
00930 #if LWIP_HTTPD_SSI
00931   if (hs->ssi != NULL) {
00932     add_content_len = 0; /* @todo: get maximum file length from SSI */
00933   } else
00934 #endif /* LWIP_HTTPD_SSI */
00935   if ((hs->handle == NULL) ||
00936       ((hs->handle->flags & (FS_FILE_FLAGS_HEADER_INCLUDED|FS_FILE_FLAGS_HEADER_PERSISTENT)) == FS_FILE_FLAGS_HEADER_INCLUDED)) {
00937     add_content_len = 0;
00938   }
00939   if (add_content_len) {
00940     size_t len;
00941     lwip_itoa(hs->hdr_content_len, (size_t)LWIP_HTTPD_MAX_CONTENT_LEN_SIZE,
00942       hs->handle->len);
00943     len = strlen(hs->hdr_content_len);
00944     if (len <= LWIP_HTTPD_MAX_CONTENT_LEN_SIZE - LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET) {
00945       SMEMCPY(&hs->hdr_content_len[len], CRLF "\0", 3);
00946       hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_NR] = hs->hdr_content_len;
00947     } else {
00948       add_content_len = 0;
00949     }
00950   }
00951 #if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
00952   if (add_content_len) {
00953     hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE] = g_psHTTPHeaderStrings[HTTP_HDR_KEEPALIVE_LEN];
00954   } else {
00955     hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE] = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE];
00956   }
00957 #else /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
00958   if (add_content_len) {
00959     hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE] = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH];
00960   }
00961 #endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
00962 
00963   /* Set up to send the first header string. */
00964   hs->hdr_index = 0;
00965   hs->hdr_pos = 0;
00966 }
00967 
00968 /** Sub-function of http_send(): send dynamic headers
00969  *
00970  * @returns: - HTTP_NO_DATA_TO_SEND: no new data has been enqueued
00971  *           - HTTP_DATA_TO_SEND_CONTINUE: continue with sending HTTP body
00972  *           - HTTP_DATA_TO_SEND_BREAK: data has been enqueued, headers pending,
00973  *                                      so don't send HTTP body yet
00974  */
00975 static u8_t
00976 http_send_headers(struct tcp_pcb *pcb, struct http_state *hs)
00977 {
00978   err_t err;
00979   u16_t len;
00980   u8_t data_to_send = HTTP_NO_DATA_TO_SEND;
00981   u16_t hdrlen, sendlen;
00982 
00983   /* How much data can we send? */
00984   len = tcp_sndbuf(pcb);
00985   sendlen = len;
00986 
00987   while(len && (hs->hdr_index < NUM_FILE_HDR_STRINGS) && sendlen) {
00988     const void *ptr;
00989     u16_t old_sendlen;
00990     u8_t apiflags;
00991     /* How much do we have to send from the current header? */
00992     hdrlen = (u16_t)strlen(hs->hdrs[hs->hdr_index]);
00993 
00994     /* How much of this can we send? */
00995     sendlen = (len < (hdrlen - hs->hdr_pos)) ? len : (hdrlen - hs->hdr_pos);
00996 
00997     /* Send this amount of data or as much as we can given memory
00998      * constraints. */
00999     ptr = (const void *)(hs->hdrs[hs->hdr_index] + hs->hdr_pos);
01000     old_sendlen = sendlen;
01001     apiflags = HTTP_IS_HDR_VOLATILE(hs, ptr);
01002     if (hs->hdr_index == HDR_STRINGS_IDX_CONTENT_LEN_NR) {
01003       /* content-length is always volatile */
01004       apiflags |= TCP_WRITE_FLAG_COPY;
01005     }
01006     if (hs->hdr_index < NUM_FILE_HDR_STRINGS - 1) {
01007       apiflags |= TCP_WRITE_FLAG_MORE;
01008     }
01009     err = http_write(pcb, ptr, &sendlen, apiflags);
01010     if ((err == ERR_OK) && (old_sendlen != sendlen)) {
01011       /* Remember that we added some more data to be transmitted. */
01012       data_to_send = HTTP_DATA_TO_SEND_CONTINUE;
01013     } else if (err != ERR_OK) {
01014        /* special case: http_write does not try to send 1 byte */
01015       sendlen = 0;
01016     }
01017 
01018     /* Fix up the header position for the next time round. */
01019     hs->hdr_pos += sendlen;
01020     len -= sendlen;
01021 
01022     /* Have we finished sending this string? */
01023     if(hs->hdr_pos == hdrlen) {
01024       /* Yes - move on to the next one */
01025       hs->hdr_index++;
01026       /* skip headers that are NULL (not all headers are required) */
01027       while ((hs->hdr_index < NUM_FILE_HDR_STRINGS) &&
01028          (hs->hdrs[hs->hdr_index] == NULL)) {
01029         hs->hdr_index++;
01030       }
01031       hs->hdr_pos = 0;
01032     }
01033   }
01034 
01035   if ((hs->hdr_index >= NUM_FILE_HDR_STRINGS) && (hs->file == NULL)) {
01036     /* When we are at the end of the headers, check for data to send
01037      * instead of waiting for ACK from remote side to continue
01038      * (which would happen when sending files from async read). */
01039     if(http_check_eof(pcb, hs)) {
01040       data_to_send = HTTP_DATA_TO_SEND_CONTINUE;
01041     }
01042   }
01043   /* If we get here and there are still header bytes to send, we send
01044    * the header information we just wrote immediately. If there are no
01045    * more headers to send, but we do have file data to send, drop through
01046    * to try to send some file data too. */
01047   if((hs->hdr_index < NUM_FILE_HDR_STRINGS) || !hs->file) {
01048     LWIP_DEBUGF(HTTPD_DEBUG, ("tcp_output\n"));
01049     return HTTP_DATA_TO_SEND_BREAK;
01050   }
01051   return data_to_send;
01052 }
01053 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
01054 
01055 /** Sub-function of http_send(): end-of-file (or block) is reached,
01056  * either close the file or read the next block (if supported).
01057  *
01058  * @returns: 0 if the file is finished or no data has been read
01059  *           1 if the file is not finished and data has been read
01060  */
01061 static u8_t
01062 http_check_eof(struct tcp_pcb *pcb, struct http_state *hs)
01063 {
01064   int bytes_left;
01065 #if LWIP_HTTPD_DYNAMIC_FILE_READ
01066   int count;
01067 #ifdef HTTPD_MAX_WRITE_LEN
01068   int max_write_len;
01069 #endif /* HTTPD_MAX_WRITE_LEN */
01070 #endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
01071 
01072   /* Do we have a valid file handle? */
01073   if (hs->handle == NULL) {
01074     /* No - close the connection. */
01075     http_eof(pcb, hs);
01076     return 0;
01077   }
01078   bytes_left = fs_bytes_left(hs->handle);
01079   if (bytes_left <= 0) {
01080     /* We reached the end of the file so this request is done. */
01081     LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
01082     http_eof(pcb, hs);
01083     return 0;
01084   }
01085 #if LWIP_HTTPD_DYNAMIC_FILE_READ
01086   /* Do we already have a send buffer allocated? */
01087   if(hs->buf) {
01088     /* Yes - get the length of the buffer */
01089     count = LWIP_MIN(hs->buf_len, bytes_left);
01090   } else {
01091     /* We don't have a send buffer so allocate one now */
01092     count = tcp_sndbuf(pcb);
01093     if(bytes_left < count) {
01094       count = bytes_left;
01095     }
01096 #ifdef HTTPD_MAX_WRITE_LEN
01097     /* Additional limitation: e.g. don't enqueue more than 2*mss at once */
01098     max_write_len = HTTPD_MAX_WRITE_LEN(pcb);
01099     if (count > max_write_len) {
01100       count = max_write_len;
01101     }
01102 #endif /* HTTPD_MAX_WRITE_LEN */
01103     do {
01104       hs->buf = (char*)mem_malloc((mem_size_t)count);
01105       if (hs->buf != NULL) {
01106         hs->buf_len = count;
01107         break;
01108       }
01109       count = count / 2;
01110     } while (count > 100);
01111 
01112     /* Did we get a send buffer? If not, return immediately. */
01113     if (hs->buf == NULL) {
01114       LWIP_DEBUGF(HTTPD_DEBUG, ("No buff\n"));
01115       return 0;
01116     }
01117   }
01118 
01119   /* Read a block of data from the file. */
01120   LWIP_DEBUGF(HTTPD_DEBUG, ("Trying to read %d bytes.\n", count));
01121 
01122 #if LWIP_HTTPD_FS_ASYNC_READ
01123   count = fs_read_async(hs->handle, hs->buf, count, http_continue, hs);
01124 #else /* LWIP_HTTPD_FS_ASYNC_READ */
01125   count = fs_read(hs->handle, hs->buf, count);
01126 #endif /* LWIP_HTTPD_FS_ASYNC_READ */
01127   if (count < 0) {
01128     if (count == FS_READ_DELAYED) {
01129       /* Delayed read, wait for FS to unblock us */
01130       return 0;
01131     }
01132     /* We reached the end of the file so this request is done.
01133      * @todo: close here for HTTP/1.1 when reading file fails */
01134     LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
01135     http_eof(pcb, hs);
01136     return 0;
01137   }
01138 
01139   /* Set up to send the block of data we just read */
01140   LWIP_DEBUGF(HTTPD_DEBUG, ("Read %d bytes.\n", count));
01141   hs->left = count;
01142   hs->file = hs->buf;
01143 #if LWIP_HTTPD_SSI
01144   if (hs->ssi) {
01145     hs->ssi->parse_left = count;
01146     hs->ssi->parsed = hs->buf;
01147   }
01148 #endif /* LWIP_HTTPD_SSI */
01149 #else /* LWIP_HTTPD_DYNAMIC_FILE_READ */
01150   LWIP_ASSERT("SSI and DYNAMIC_HEADERS turned off but eof not reached", 0);
01151 #endif /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */
01152   return 1;
01153 }
01154 
01155 /** Sub-function of http_send(): This is the normal send-routine for non-ssi files
01156  *
01157  * @returns: - 1: data has been written (so call tcp_ouput)
01158  *           - 0: no data has been written (no need to call tcp_output)
01159  */
01160 static u8_t
01161 http_send_data_nonssi(struct tcp_pcb *pcb, struct http_state *hs)
01162 {
01163   err_t err;
01164   u16_t len;
01165   u8_t data_to_send = 0;
01166 
01167   /* We are not processing an SHTML file so no tag checking is necessary.
01168    * Just send the data as we received it from the file. */
01169   len = (u16_t)LWIP_MIN(hs->left, 0xffff);
01170 
01171   err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
01172   if (err == ERR_OK) {
01173     data_to_send = 1;
01174     hs->file += len;
01175     hs->left -= len;
01176   }
01177 
01178   return data_to_send;
01179 }
01180 
01181 #if LWIP_HTTPD_SSI
01182 /** Sub-function of http_send(): This is the send-routine for ssi files
01183  *
01184  * @returns: - 1: data has been written (so call tcp_ouput)
01185  *           - 0: no data has been written (no need to call tcp_output)
01186  */
01187 static u8_t
01188 http_send_data_ssi(struct tcp_pcb *pcb, struct http_state *hs)
01189 {
01190   err_t err = ERR_OK;
01191   u16_t len;
01192   u8_t data_to_send = 0;
01193 
01194   struct http_ssi_state *ssi = hs->ssi;
01195   LWIP_ASSERT("ssi != NULL", ssi != NULL);
01196   /* We are processing an SHTML file so need to scan for tags and replace
01197    * them with insert strings. We need to be careful here since a tag may
01198    * straddle the boundary of two blocks read from the file and we may also
01199    * have to split the insert string between two tcp_write operations. */
01200 
01201   /* How much data could we send? */
01202   len = tcp_sndbuf(pcb);
01203 
01204   /* Do we have remaining data to send before parsing more? */
01205   if(ssi->parsed > hs->file) {
01206     len = (u16_t)LWIP_MIN(ssi->parsed - hs->file, 0xffff);
01207 
01208     err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
01209     if (err == ERR_OK) {
01210       data_to_send = 1;
01211       hs->file += len;
01212       hs->left -= len;
01213     }
01214 
01215     /* If the send buffer is full, return now. */
01216     if(tcp_sndbuf(pcb) == 0) {
01217       return data_to_send;
01218     }
01219   }
01220 
01221   LWIP_DEBUGF(HTTPD_DEBUG, ("State %d, %d left\n", ssi->tag_state, (int)ssi->parse_left));
01222 
01223   /* We have sent all the data that was already parsed so continue parsing
01224    * the buffer contents looking for SSI tags. */
01225   while((ssi->parse_left) && (err == ERR_OK)) {
01226     if (len == 0) {
01227       return data_to_send;
01228     }
01229     switch(ssi->tag_state) {
01230       case TAG_NONE:
01231         /* We are not currently processing an SSI tag so scan for the
01232          * start of the lead-in marker. */
01233         if(*ssi->parsed == g_pcTagLeadIn[0]) {
01234           /* We found what could be the lead-in for a new tag so change
01235            * state appropriately. */
01236           ssi->tag_state = TAG_LEADIN;
01237           ssi->tag_index = 1;
01238 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
01239           ssi->tag_started = ssi->parsed;
01240 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */
01241         }
01242 
01243         /* Move on to the next character in the buffer */
01244         ssi->parse_left--;
01245         ssi->parsed++;
01246         break;
01247 
01248       case TAG_LEADIN:
01249         /* We are processing the lead-in marker, looking for the start of
01250          * the tag name. */
01251 
01252         /* Have we reached the end of the leadin? */
01253         if(ssi->tag_index == LEN_TAG_LEAD_IN) {
01254           ssi->tag_index = 0;
01255           ssi->tag_state = TAG_FOUND;
01256         } else {
01257           /* Have we found the next character we expect for the tag leadin? */
01258           if(*ssi->parsed == g_pcTagLeadIn[ssi->tag_index]) {
01259             /* Yes - move to the next one unless we have found the complete
01260              * leadin, in which case we start looking for the tag itself */
01261             ssi->tag_index++;
01262           } else {
01263             /* We found an unexpected character so this is not a tag. Move
01264              * back to idle state. */
01265             ssi->tag_state = TAG_NONE;
01266           }
01267 
01268           /* Move on to the next character in the buffer */
01269           ssi->parse_left--;
01270           ssi->parsed++;
01271         }
01272         break;
01273 
01274       case TAG_FOUND:
01275         /* We are reading the tag name, looking for the start of the
01276          * lead-out marker and removing any whitespace found. */
01277 
01278         /* Remove leading whitespace between the tag leading and the first
01279          * tag name character. */
01280         if((ssi->tag_index == 0) && ((*ssi->parsed == ' ') ||
01281            (*ssi->parsed == '\t') || (*ssi->parsed == '\n') ||
01282            (*ssi->parsed == '\r'))) {
01283           /* Move on to the next character in the buffer */
01284           ssi->parse_left--;
01285           ssi->parsed++;
01286           break;
01287         }
01288 
01289         /* Have we found the end of the tag name? This is signalled by
01290          * us finding the first leadout character or whitespace */
01291         if((*ssi->parsed == g_pcTagLeadOut[0]) ||
01292            (*ssi->parsed == ' ')  || (*ssi->parsed == '\t') ||
01293            (*ssi->parsed == '\n') || (*ssi->parsed == '\r')) {
01294 
01295           if(ssi->tag_index == 0) {
01296             /* We read a zero length tag so ignore it. */
01297             ssi->tag_state = TAG_NONE;
01298           } else {
01299             /* We read a non-empty tag so go ahead and look for the
01300              * leadout string. */
01301             ssi->tag_state = TAG_LEADOUT;
01302             LWIP_ASSERT("ssi->tag_index <= 0xff", ssi->tag_index <= 0xff);
01303             ssi->tag_name_len = (u8_t)ssi->tag_index;
01304             ssi->tag_name[ssi->tag_index] = '\0';
01305             if(*ssi->parsed == g_pcTagLeadOut[0]) {
01306               ssi->tag_index = 1;
01307             } else {
01308               ssi->tag_index = 0;
01309             }
01310           }
01311         } else {
01312           /* This character is part of the tag name so save it */
01313           if(ssi->tag_index < LWIP_HTTPD_MAX_TAG_NAME_LEN) {
01314             ssi->tag_name[ssi->tag_index++] = *ssi->parsed;
01315           } else {
01316             /* The tag was too long so ignore it. */
01317             ssi->tag_state = TAG_NONE;
01318           }
01319         }
01320 
01321         /* Move on to the next character in the buffer */
01322         ssi->parse_left--;
01323         ssi->parsed++;
01324 
01325         break;
01326 
01327       /* We are looking for the end of the lead-out marker. */
01328       case TAG_LEADOUT:
01329         /* Remove leading whitespace between the tag leading and the first
01330          * tag leadout character. */
01331         if((ssi->tag_index == 0) && ((*ssi->parsed == ' ') ||
01332            (*ssi->parsed == '\t') || (*ssi->parsed == '\n') ||
01333            (*ssi->parsed == '\r'))) {
01334           /* Move on to the next character in the buffer */
01335           ssi->parse_left--;
01336           ssi->parsed++;
01337           break;
01338         }
01339 
01340         /* Have we found the next character we expect for the tag leadout? */
01341         if(*ssi->parsed == g_pcTagLeadOut[ssi->tag_index]) {
01342           /* Yes - move to the next one unless we have found the complete
01343            * leadout, in which case we need to call the client to process
01344            * the tag. */
01345 
01346           /* Move on to the next character in the buffer */
01347           ssi->parse_left--;
01348           ssi->parsed++;
01349 
01350           if(ssi->tag_index == (LEN_TAG_LEAD_OUT - 1)) {
01351             /* Call the client to ask for the insert string for the
01352              * tag we just found. */
01353 #if LWIP_HTTPD_SSI_MULTIPART
01354             ssi->tag_part = 0; /* start with tag part 0 */
01355 #endif /* LWIP_HTTPD_SSI_MULTIPART */
01356             get_tag_insert(hs);
01357 
01358             /* Next time through, we are going to be sending data
01359              * immediately, either the end of the block we start
01360              * sending here or the insert string. */
01361             ssi->tag_index = 0;
01362             ssi->tag_state = TAG_SENDING;
01363             ssi->tag_end = ssi->parsed;
01364 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
01365             ssi->parsed = ssi->tag_started;
01366 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
01367 
01368             /* If there is any unsent data in the buffer prior to the
01369              * tag, we need to send it now. */
01370             if (ssi->tag_end > hs->file) {
01371               /* How much of the data can we send? */
01372 #if LWIP_HTTPD_SSI_INCLUDE_TAG
01373               len = (u16_t)LWIP_MIN(ssi->tag_end - hs->file, 0xffff);
01374 #else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
01375               /* we would include the tag in sending */
01376               len = (u16_t)LWIP_MIN(ssi->tag_started - hs->file, 0xffff);
01377 #endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
01378 
01379               err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
01380               if (err == ERR_OK) {
01381                 data_to_send = 1;
01382 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
01383                 if(ssi->tag_started <= hs->file) {
01384                   /* pretend to have sent the tag, too */
01385                   len += ssi->tag_end - ssi->tag_started;
01386                 }
01387 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
01388                 hs->file += len;
01389                 hs->left -= len;
01390               }
01391             }
01392           } else {
01393             ssi->tag_index++;
01394           }
01395         } else {
01396           /* We found an unexpected character so this is not a tag. Move
01397            * back to idle state. */
01398           ssi->parse_left--;
01399           ssi->parsed++;
01400           ssi->tag_state = TAG_NONE;
01401         }
01402         break;
01403 
01404       /*
01405        * We have found a valid tag and are in the process of sending
01406        * data as a result of that discovery. We send either remaining data
01407        * from the file prior to the insert point or the insert string itself.
01408        */
01409       case TAG_SENDING:
01410         /* Do we have any remaining file data to send from the buffer prior
01411          * to the tag? */
01412         if(ssi->tag_end > hs->file) {
01413           /* How much of the data can we send? */
01414 #if LWIP_HTTPD_SSI_INCLUDE_TAG
01415           len = (u16_t)LWIP_MIN(ssi->tag_end - hs->file, 0xffff);
01416 #else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
01417           LWIP_ASSERT("hs->started >= hs->file", ssi->tag_started >= hs->file);
01418           /* we would include the tag in sending */
01419           len = (u16_t)LWIP_MIN(ssi->tag_started - hs->file, 0xffff);
01420 #endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
01421           if (len != 0) {
01422             err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
01423           } else {
01424             err = ERR_OK;
01425           }
01426           if (err == ERR_OK) {
01427             data_to_send = 1;
01428 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
01429             if(ssi->tag_started <= hs->file) {
01430               /* pretend to have sent the tag, too */
01431               len += ssi->tag_end - ssi->tag_started;
01432             }
01433 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
01434             hs->file += len;
01435             hs->left -= len;
01436           }
01437         } else {
01438 #if LWIP_HTTPD_SSI_MULTIPART
01439           if(ssi->tag_index >= ssi->tag_insert_len) {
01440             /* Did the last SSIHandler have more to send? */
01441             if (ssi->tag_part != HTTPD_LAST_TAG_PART) {
01442               /* If so, call it again */
01443               ssi->tag_index = 0;
01444               get_tag_insert(hs);
01445             }
01446           }
01447 #endif /* LWIP_HTTPD_SSI_MULTIPART */
01448 
01449           /* Do we still have insert data left to send? */
01450           if(ssi->tag_index < ssi->tag_insert_len) {
01451             /* We are sending the insert string itself. How much of the
01452              * insert can we send? */
01453             len = (ssi->tag_insert_len - ssi->tag_index);
01454 
01455             /* Note that we set the copy flag here since we only have a
01456              * single tag insert buffer per connection. If we don't do
01457              * this, insert corruption can occur if more than one insert
01458              * is processed before we call tcp_output. */
01459             err = http_write(pcb, &(ssi->tag_insert[ssi->tag_index]), &len,
01460                              HTTP_IS_TAG_VOLATILE(hs));
01461             if (err == ERR_OK) {
01462               data_to_send = 1;
01463               ssi->tag_index += len;
01464               /* Don't return here: keep on sending data */
01465             }
01466           } else {
01467 #if LWIP_HTTPD_SSI_MULTIPART
01468             if (ssi->tag_part == HTTPD_LAST_TAG_PART)
01469 #endif /* LWIP_HTTPD_SSI_MULTIPART */
01470             {
01471               /* We have sent all the insert data so go back to looking for
01472                * a new tag. */
01473               LWIP_DEBUGF(HTTPD_DEBUG, ("Everything sent.\n"));
01474               ssi->tag_index = 0;
01475               ssi->tag_state = TAG_NONE;
01476 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
01477               ssi->parsed = ssi->tag_end;
01478 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
01479             }
01480           }
01481           break;
01482         default:
01483           break;
01484       }
01485     }
01486   }
01487 
01488   /* If we drop out of the end of the for loop, this implies we must have
01489    * file data to send so send it now. In TAG_SENDING state, we've already
01490    * handled this so skip the send if that's the case. */
01491   if((ssi->tag_state != TAG_SENDING) && (ssi->parsed > hs->file)) {
01492     len = (u16_t)LWIP_MIN(ssi->parsed - hs->file, 0xffff);
01493 
01494     err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
01495     if (err == ERR_OK) {
01496       data_to_send = 1;
01497       hs->file += len;
01498       hs->left -= len;
01499     }
01500   }
01501   return data_to_send;
01502 }
01503 #endif /* LWIP_HTTPD_SSI */
01504 
01505 /**
01506  * Try to send more data on this pcb.
01507  *
01508  * @param pcb the pcb to send data
01509  * @param hs connection state
01510  */
01511 static u8_t
01512 http_send(struct tcp_pcb *pcb, struct http_state *hs)
01513 {
01514   u8_t data_to_send = HTTP_NO_DATA_TO_SEND;
01515 
01516   LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_send: pcb=%p hs=%p left=%d\n", (void*)pcb,
01517     (void*)hs, hs != NULL ? (int)hs->left : 0));
01518 
01519 #if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
01520   if (hs->unrecved_bytes != 0) {
01521     return 0;
01522   }
01523 #endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
01524 
01525   /* If we were passed a NULL state structure pointer, ignore the call. */
01526   if (hs == NULL) {
01527     return 0;
01528   }
01529 
01530 #if LWIP_HTTPD_FS_ASYNC_READ
01531   /* Check if we are allowed to read from this file.
01532      (e.g. SSI might want to delay sending until data is available) */
01533   if (!fs_is_file_ready(hs->handle, http_continue, hs)) {
01534     return 0;
01535   }
01536 #endif /* LWIP_HTTPD_FS_ASYNC_READ */
01537 
01538 #if LWIP_HTTPD_DYNAMIC_HEADERS
01539   /* Do we have any more header data to send for this file? */
01540   if (hs->hdr_index < NUM_FILE_HDR_STRINGS) {
01541     data_to_send = http_send_headers(pcb, hs);
01542     if ((data_to_send != HTTP_DATA_TO_SEND_CONTINUE) &&
01543         (hs->hdr_index < NUM_FILE_HDR_STRINGS)) {
01544       return data_to_send;
01545     }
01546   }
01547 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
01548 
01549   /* Have we run out of file data to send? If so, we need to read the next
01550    * block from the file. */
01551   if (hs->left == 0) {
01552     if (!http_check_eof(pcb, hs)) {
01553       return 0;
01554     }
01555   }
01556 
01557 #if LWIP_HTTPD_SSI
01558   if(hs->ssi) {
01559     data_to_send = http_send_data_ssi(pcb, hs);
01560   } else
01561 #endif /* LWIP_HTTPD_SSI */
01562   {
01563     data_to_send = http_send_data_nonssi(pcb, hs);
01564   }
01565 
01566   if((hs->left == 0) && (fs_bytes_left(hs->handle) <= 0)) {
01567     /* We reached the end of the file so this request is done.
01568      * This adds the FIN flag right into the last data segment. */
01569     LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
01570     http_eof(pcb, hs);
01571     return 0;
01572   }
01573   LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("send_data end.\n"));
01574   return data_to_send;
01575 }
01576 
01577 #if LWIP_HTTPD_SUPPORT_EXTSTATUS
01578 /** Initialize a http connection with a file to send for an error message
01579  *
01580  * @param hs http connection state
01581  * @param error_nr HTTP error number
01582  * @return ERR_OK if file was found and hs has been initialized correctly
01583  *         another err_t otherwise
01584  */
01585 static err_t
01586 http_find_error_file(struct http_state *hs, u16_t error_nr)
01587 {
01588   const char *uri1, *uri2, *uri3;
01589   err_t err;
01590 
01591   if (error_nr == 501) {
01592     uri1 = "/501.html";
01593     uri2 = "/501.htm";
01594     uri3 = "/501.shtml";
01595   } else {
01596     /* 400 (bad request is the default) */
01597     uri1 = "/400.html";
01598     uri2 = "/400.htm";
01599     uri3 = "/400.shtml";
01600   }
01601   err = fs_open(&hs->file_handle, uri1);
01602   if (err != ERR_OK) {
01603     err = fs_open(&hs->file_handle, uri2);
01604     if (err != ERR_OK) {
01605       err = fs_open(&hs->file_handle, uri3);
01606       if (err != ERR_OK) {
01607         LWIP_DEBUGF(HTTPD_DEBUG, ("Error page for error %"U16_F" not found\n",
01608           error_nr));
01609         return ERR_ARG;
01610       }
01611     }
01612   }
01613   return http_init_file(hs, &hs->file_handle, 0, NULL, 0, NULL);
01614 }
01615 #else /* LWIP_HTTPD_SUPPORT_EXTSTATUS */
01616 #define http_find_error_file(hs, error_nr) ERR_ARG
01617 #endif /* LWIP_HTTPD_SUPPORT_EXTSTATUS */
01618 
01619 /**
01620  * Get the file struct for a 404 error page.
01621  * Tries some file names and returns NULL if none found.
01622  *
01623  * @param uri pointer that receives the actual file name URI
01624  * @return file struct for the error page or NULL no matching file was found
01625  */
01626 static struct fs_file *
01627 http_get_404_file(struct http_state *hs, const char **uri)
01628 {
01629   err_t err;
01630 
01631   *uri = "/404.html";
01632   err = fs_open(&hs->file_handle, *uri);
01633   if (err != ERR_OK) {
01634     /* 404.html doesn't exist. Try 404.htm instead. */
01635     *uri = "/404.htm";
01636     err = fs_open(&hs->file_handle, *uri);
01637     if (err != ERR_OK) {
01638       /* 404.htm doesn't exist either. Try 404.shtml instead. */
01639       *uri = "/404.shtml";
01640       err = fs_open(&hs->file_handle, *uri);
01641       if (err != ERR_OK) {
01642         /* 404.htm doesn't exist either. Indicate to the caller that it should
01643          * send back a default 404 page.
01644          */
01645         *uri = NULL;
01646         return NULL;
01647       }
01648     }
01649   }
01650 
01651   return &hs->file_handle;
01652 }
01653 
01654 #if LWIP_HTTPD_SUPPORT_POST
01655 static err_t
01656 http_handle_post_finished(struct http_state *hs)
01657 {
01658 #if LWIP_HTTPD_POST_MANUAL_WND
01659   /* Prevent multiple calls to httpd_post_finished, since it might have already
01660      been called before from httpd_post_data_recved(). */
01661   if (hs->post_finished) {
01662     return ERR_OK;
01663   }
01664   hs->post_finished = 1;
01665 #endif /* LWIP_HTTPD_POST_MANUAL_WND */
01666   /* application error or POST finished */
01667   /* NULL-terminate the buffer */
01668   http_uri_buf[0] = 0;
01669   httpd_post_finished(hs, http_uri_buf, LWIP_HTTPD_URI_BUF_LEN);
01670   return http_find_file(hs, http_uri_buf, 0);
01671 }
01672 
01673 /** Pass received POST body data to the application and correctly handle
01674  * returning a response document or closing the connection.
01675  * ATTENTION: The application is responsible for the pbuf now, so don't free it!
01676  *
01677  * @param hs http connection state
01678  * @param p pbuf to pass to the application
01679  * @return ERR_OK if passed successfully, another err_t if the response file
01680  *         hasn't been found (after POST finished)
01681  */
01682 static err_t
01683 http_post_rxpbuf(struct http_state *hs, struct pbuf *p)
01684 {
01685   err_t err;
01686 
01687   if (p != NULL) {
01688     /* adjust remaining Content-Length */
01689     if (hs->post_content_len_left < p->tot_len) {
01690       hs->post_content_len_left = 0;
01691     } else {
01692       hs->post_content_len_left -= p->tot_len;
01693     }
01694   }
01695 #if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
01696   /* prevent connection being closed if httpd_post_data_recved() is called nested */
01697   hs->unrecved_bytes++;
01698 #endif
01699   err = httpd_post_receive_data(hs, p);
01700 #if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
01701   hs->unrecved_bytes--;
01702 #endif
01703   if (err != ERR_OK) {
01704     /* Ignore remaining content in case of application error */
01705     hs->post_content_len_left = 0;
01706   }
01707   if (hs->post_content_len_left == 0) {
01708 #if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
01709     if (hs->unrecved_bytes != 0) {
01710        return ERR_OK;
01711     }
01712 #endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
01713     /* application error or POST finished */
01714     return http_handle_post_finished(hs);
01715   }
01716 
01717   return ERR_OK;
01718 }
01719 
01720 /** Handle a post request. Called from http_parse_request when method 'POST'
01721  * is found.
01722  *
01723  * @param p The input pbuf (containing the POST header and body).
01724  * @param hs The http connection state.
01725  * @param data HTTP request (header and part of body) from input pbuf(s).
01726  * @param data_len Size of 'data'.
01727  * @param uri The HTTP URI parsed from input pbuf(s).
01728  * @param uri_end Pointer to the end of 'uri' (here, the rest of the HTTP
01729  *                header starts).
01730  * @return ERR_OK: POST correctly parsed and accepted by the application.
01731  *         ERR_INPROGRESS: POST not completely parsed (no error yet)
01732  *         another err_t: Error parsing POST or denied by the application
01733  */
01734 static err_t
01735 http_post_request(struct pbuf *inp, struct http_state *hs,
01736                   char *data, u16_t data_len, char *uri, char *uri_end)
01737 {
01738   err_t err;
01739   /* search for end-of-header (first double-CRLF) */
01740   char* crlfcrlf = lwip_strnstr(uri_end + 1, CRLF CRLF, data_len - (uri_end + 1 - data));
01741 
01742   if (crlfcrlf != NULL) {
01743     /* search for "Content-Length: " */
01744 #define HTTP_HDR_CONTENT_LEN                "Content-Length: "
01745 #define HTTP_HDR_CONTENT_LEN_LEN            16
01746 #define HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN  10
01747     char *scontent_len = lwip_strnstr(uri_end + 1, HTTP_HDR_CONTENT_LEN, crlfcrlf - (uri_end + 1));
01748     if (scontent_len != NULL) {
01749       char *scontent_len_end = lwip_strnstr(scontent_len + HTTP_HDR_CONTENT_LEN_LEN, CRLF, HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN);
01750       if (scontent_len_end != NULL) {
01751         int content_len;
01752         char *content_len_num = scontent_len + HTTP_HDR_CONTENT_LEN_LEN;
01753         content_len = atoi(content_len_num);
01754         if (content_len == 0) {
01755           /* if atoi returns 0 on error, fix this */
01756           if ((content_len_num[0] != '0') || (content_len_num[1] != '\r')) {
01757             content_len = -1;
01758           }
01759         }
01760         if (content_len >= 0) {
01761           /* adjust length of HTTP header passed to application */
01762           const char *hdr_start_after_uri = uri_end + 1;
01763           u16_t hdr_len = (u16_t)LWIP_MIN(data_len, crlfcrlf + 4 - data);
01764           u16_t hdr_data_len = (u16_t)LWIP_MIN(data_len, crlfcrlf + 4 - hdr_start_after_uri);
01765           u8_t post_auto_wnd = 1;
01766           http_uri_buf[0] = 0;
01767           /* trim http header */
01768           *crlfcrlf = 0;
01769           err = httpd_post_begin(hs, uri, hdr_start_after_uri, hdr_data_len, content_len,
01770             http_uri_buf, LWIP_HTTPD_URI_BUF_LEN, &post_auto_wnd);
01771           if (err == ERR_OK) {
01772             /* try to pass in data of the first pbuf(s) */
01773             struct pbuf *q = inp;
01774             u16_t start_offset = hdr_len;
01775 #if LWIP_HTTPD_POST_MANUAL_WND
01776             hs->no_auto_wnd = !post_auto_wnd;
01777 #endif /* LWIP_HTTPD_POST_MANUAL_WND */
01778             /* set the Content-Length to be received for this POST */
01779             hs->post_content_len_left = (u32_t)content_len;
01780 
01781             /* get to the pbuf where the body starts */
01782             while((q != NULL) && (q->len <= start_offset)) {
01783               start_offset -= q->len;
01784               q = q->next;
01785             }
01786             if (q != NULL) {
01787               /* hide the remaining HTTP header */
01788               pbuf_header(q, -(s16_t)start_offset);
01789 #if LWIP_HTTPD_POST_MANUAL_WND
01790               if (!post_auto_wnd) {
01791                 /* already tcp_recved() this data... */
01792                 hs->unrecved_bytes = q->tot_len;
01793               }
01794 #endif /* LWIP_HTTPD_POST_MANUAL_WND */
01795               pbuf_ref(q);
01796               return http_post_rxpbuf(hs, q);
01797             } else if (hs->post_content_len_left == 0) {
01798               q = pbuf_alloc(PBUF_RAW, 0, PBUF_REF);
01799               return http_post_rxpbuf(hs, q);
01800             } else {
01801               return ERR_OK;
01802             }
01803           } else {
01804             /* return file passed from application */
01805             return http_find_file(hs, http_uri_buf, 0);
01806           }
01807         } else {
01808           LWIP_DEBUGF(HTTPD_DEBUG, ("POST received invalid Content-Length: %s\n",
01809             content_len_num));
01810           return ERR_ARG;
01811         }
01812       }
01813     }
01814     /* If we come here, headers are fully received (double-crlf), but Content-Length
01815        was not included. Since this is currently the only supported method, we have
01816        to fail in this case! */
01817     LWIP_DEBUGF(HTTPD_DEBUG, ("Error when parsing Content-Length\n"));
01818     return ERR_ARG;
01819   }
01820   /* if we come here, the POST is incomplete */
01821 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
01822   return ERR_INPROGRESS;
01823 #else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
01824   return ERR_ARG;
01825 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
01826 }
01827 
01828 #if LWIP_HTTPD_POST_MANUAL_WND
01829 /** A POST implementation can call this function to update the TCP window.
01830  * This can be used to throttle data reception (e.g. when received data is
01831  * programmed to flash and data is received faster than programmed).
01832  *
01833  * @param connection A connection handle passed to httpd_post_begin for which
01834  *        httpd_post_finished has *NOT* been called yet!
01835  * @param recved_len Length of data received (for window update)
01836  */
01837 void httpd_post_data_recved(void *connection, u16_t recved_len)
01838 {
01839   struct http_state *hs = (struct http_state*)connection;
01840   if (hs != NULL) {
01841     if (hs->no_auto_wnd) {
01842       u16_t len = recved_len;
01843       if (hs->unrecved_bytes >= recved_len) {
01844         hs->unrecved_bytes -= recved_len;
01845       } else {
01846         LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_LEVEL_WARNING, ("httpd_post_data_recved: recved_len too big\n"));
01847         len = (u16_t)hs->unrecved_bytes;
01848         hs->unrecved_bytes = 0;
01849       }
01850       if (hs->pcb != NULL) {
01851         if (len != 0) {
01852           tcp_recved(hs->pcb, len);
01853         }
01854         if ((hs->post_content_len_left == 0) && (hs->unrecved_bytes == 0)) {
01855           /* finished handling POST */
01856           http_handle_post_finished(hs);
01857           http_send(hs->pcb, hs);
01858         }
01859       }
01860     }
01861   }
01862 }
01863 #endif /* LWIP_HTTPD_POST_MANUAL_WND */
01864 
01865 #endif /* LWIP_HTTPD_SUPPORT_POST */
01866 
01867 #if LWIP_HTTPD_FS_ASYNC_READ
01868 /** Try to send more data if file has been blocked before
01869  * This is a callback function passed to fs_read_async().
01870  */
01871 static void
01872 http_continue(void *connection)
01873 {
01874   struct http_state *hs = (struct http_state*)connection;
01875   if (hs && (hs->pcb) && (hs->handle)) {
01876     LWIP_ASSERT("hs->pcb != NULL", hs->pcb != NULL);
01877     LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("httpd_continue: try to send more data\n"));
01878     if (http_send(hs->pcb, hs)) {
01879       /* If we wrote anything to be sent, go ahead and send it now. */
01880       LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("tcp_output\n"));
01881       tcp_output(hs->pcb);
01882     }
01883   }
01884 }
01885 #endif /* LWIP_HTTPD_FS_ASYNC_READ */
01886 
01887 /**
01888  * When data has been received in the correct state, try to parse it
01889  * as a HTTP request.
01890  *
01891  * @param inp the received pbuf
01892  * @param hs the connection state
01893  * @param pcb the tcp_pcb which received this packet
01894  * @return ERR_OK if request was OK and hs has been initialized correctly
01895  *         ERR_INPROGRESS if request was OK so far but not fully received
01896  *         another err_t otherwise
01897  */
01898 static err_t
01899 http_parse_request(struct pbuf *inp, struct http_state *hs, struct tcp_pcb *pcb)
01900 {
01901   char *data;
01902   char *crlf;
01903   u16_t data_len;
01904   struct pbuf *p = inp;
01905 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
01906   u16_t clen;
01907 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
01908 #if LWIP_HTTPD_SUPPORT_POST
01909   err_t err;
01910 #endif /* LWIP_HTTPD_SUPPORT_POST */
01911 
01912   LWIP_UNUSED_ARG(pcb); /* only used for post */
01913   LWIP_ASSERT("p != NULL", p != NULL);
01914   LWIP_ASSERT("hs != NULL", hs != NULL);
01915 
01916   if ((hs->handle != NULL) || (hs->file != NULL)) {
01917     LWIP_DEBUGF(HTTPD_DEBUG, ("Received data while sending a file\n"));
01918     /* already sending a file */
01919     /* @todo: abort? */
01920     return ERR_USE;
01921   }
01922 
01923 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
01924 
01925   LWIP_DEBUGF(HTTPD_DEBUG, ("Received %"U16_F" bytes\n", p->tot_len));
01926 
01927   /* first check allowed characters in this pbuf? */
01928 
01929   /* enqueue the pbuf */
01930   if (hs->req == NULL) {
01931     LWIP_DEBUGF(HTTPD_DEBUG, ("First pbuf\n"));
01932     hs->req = p;
01933   } else {
01934     LWIP_DEBUGF(HTTPD_DEBUG, ("pbuf enqueued\n"));
01935     pbuf_cat(hs->req, p);
01936   }
01937   /* increase pbuf ref counter as it is freed when we return but we want to
01938      keep it on the req list */
01939   pbuf_ref(p);
01940 
01941   if (hs->req->next != NULL) {
01942     data_len = LWIP_MIN(hs->req->tot_len, LWIP_HTTPD_MAX_REQ_LENGTH);
01943     pbuf_copy_partial(hs->req, httpd_req_buf, data_len, 0);
01944     data = httpd_req_buf;
01945   } else
01946 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
01947   {
01948     data = (char *)p->payload;
01949     data_len = p->len;
01950     if (p->len != p->tot_len) {
01951       LWIP_DEBUGF(HTTPD_DEBUG, ("Warning: incomplete header due to chained pbufs\n"));
01952     }
01953   }
01954 
01955   /* received enough data for minimal request? */
01956   if (data_len >= MIN_REQ_LEN) {
01957     /* wait for CRLF before parsing anything */
01958     crlf = lwip_strnstr(data, CRLF, data_len);
01959     if (crlf != NULL) {
01960 #if LWIP_HTTPD_SUPPORT_POST
01961       int is_post = 0;
01962 #endif /* LWIP_HTTPD_SUPPORT_POST */
01963       int is_09 = 0;
01964       char *sp1, *sp2;
01965       u16_t left_len, uri_len;
01966       LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("CRLF received, parsing request\n"));
01967       /* parse method */
01968       if (!strncmp(data, "GET ", 4)) {
01969         sp1 = data + 3;
01970         /* received GET request */
01971         LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received GET request\"\n"));
01972 #if LWIP_HTTPD_SUPPORT_POST
01973       } else if (!strncmp(data, "POST ", 5)) {
01974         /* store request type */
01975         is_post = 1;
01976         sp1 = data + 4;
01977         /* received GET request */
01978         LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received POST request\n"));
01979 #endif /* LWIP_HTTPD_SUPPORT_POST */
01980       } else {
01981         /* null-terminate the METHOD (pbuf is freed anyway wen returning) */
01982         data[4] = 0;
01983         /* unsupported method! */
01984         LWIP_DEBUGF(HTTPD_DEBUG, ("Unsupported request method (not implemented): \"%s\"\n",
01985           data));
01986         return http_find_error_file(hs, 501);
01987       }
01988       /* if we come here, method is OK, parse URI */
01989       left_len = (u16_t)(data_len - ((sp1 +1) - data));
01990       sp2 = lwip_strnstr(sp1 + 1, " ", left_len);
01991 #if LWIP_HTTPD_SUPPORT_V09
01992       if (sp2 == NULL) {
01993         /* HTTP 0.9: respond with correct protocol version */
01994         sp2 = lwip_strnstr(sp1 + 1, CRLF, left_len);
01995         is_09 = 1;
01996 #if LWIP_HTTPD_SUPPORT_POST
01997         if (is_post) {
01998           /* HTTP/0.9 does not support POST */
01999           goto badrequest;
02000         }
02001 #endif /* LWIP_HTTPD_SUPPORT_POST */
02002       }
02003 #endif /* LWIP_HTTPD_SUPPORT_V09 */
02004       uri_len = (u16_t)(sp2 - (sp1 + 1));
02005       if ((sp2 != 0) && (sp2 > sp1)) {
02006         /* wait for CRLFCRLF (indicating end of HTTP headers) before parsing anything */
02007         if (lwip_strnstr(data, CRLF CRLF, data_len) != NULL) {
02008           char *uri = sp1 + 1;
02009 #if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
02010           /* This is HTTP/1.0 compatible: for strict 1.1, a connection
02011              would always be persistent unless "close" was specified. */
02012           if (!is_09 && (lwip_strnstr(data, HTTP11_CONNECTIONKEEPALIVE, data_len) ||
02013               lwip_strnstr(data, HTTP11_CONNECTIONKEEPALIVE2, data_len))) {
02014             hs->keepalive = 1;
02015           } else {
02016             hs->keepalive = 0;
02017           }
02018 #endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
02019           /* null-terminate the METHOD (pbuf is freed anyway wen returning) */
02020           *sp1 = 0;
02021           uri[uri_len] = 0;
02022           LWIP_DEBUGF(HTTPD_DEBUG, ("Received \"%s\" request for URI: \"%s\"\n",
02023                       data, uri));
02024 #if LWIP_HTTPD_SUPPORT_POST
02025           if (is_post) {
02026 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
02027             struct pbuf *q = hs->req;
02028 #else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
02029             struct pbuf *q = inp;
02030 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
02031             err = http_post_request(q, hs, data, data_len, uri, sp2);
02032             if (err != ERR_OK) {
02033               /* restore header for next try */
02034               *sp1 = ' ';
02035               *sp2 = ' ';
02036               uri[uri_len] = ' ';
02037             }
02038             if (err == ERR_ARG) {
02039               goto badrequest;
02040             }
02041             return err;
02042           } else
02043 #endif /* LWIP_HTTPD_SUPPORT_POST */
02044           {
02045             return http_find_file(hs, uri, is_09);
02046           }
02047         }
02048       } else {
02049         LWIP_DEBUGF(HTTPD_DEBUG, ("invalid URI\n"));
02050       }
02051     }
02052   }
02053 
02054 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
02055   clen = pbuf_clen(hs->req);
02056   if ((hs->req->tot_len <= LWIP_HTTPD_REQ_BUFSIZE) &&
02057     (clen <= LWIP_HTTPD_REQ_QUEUELEN)) {
02058     /* request not fully received (too short or CRLF is missing) */
02059     return ERR_INPROGRESS;
02060   } else
02061 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
02062   {
02063 #if LWIP_HTTPD_SUPPORT_POST
02064 badrequest:
02065 #endif /* LWIP_HTTPD_SUPPORT_POST */
02066     LWIP_DEBUGF(HTTPD_DEBUG, ("bad request\n"));
02067     /* could not parse request */
02068     return http_find_error_file(hs, 400);
02069   }
02070 }
02071 
02072 /** Try to find the file specified by uri and, if found, initialize hs
02073  * accordingly.
02074  *
02075  * @param hs the connection state
02076  * @param uri the HTTP header URI
02077  * @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response)
02078  * @return ERR_OK if file was found and hs has been initialized correctly
02079  *         another err_t otherwise
02080  */
02081 static err_t
02082 http_find_file(struct http_state *hs, const char *uri, int is_09)
02083 {
02084   size_t loop;
02085   struct fs_file *file = NULL;
02086   char *params = NULL;
02087   err_t err;
02088 #if LWIP_HTTPD_CGI
02089   int i;
02090 #endif /* LWIP_HTTPD_CGI */
02091 #if !LWIP_HTTPD_SSI
02092   const
02093 #endif /* !LWIP_HTTPD_SSI */
02094   /* By default, assume we will not be processing server-side-includes tags */
02095   u8_t tag_check = 0;
02096 
02097   /* Have we been asked for the default file (in root or a directory) ? */
02098 #if LWIP_HTTPD_MAX_REQUEST_URI_LEN
02099   size_t uri_len = strlen(uri);
02100   if ((uri_len > 0) && (uri[uri_len-1] == '/') &&
02101       ((uri != http_uri_buf) || (uri_len == 1))) {
02102     size_t copy_len = LWIP_MIN(sizeof(http_uri_buf) - 1, uri_len - 1);
02103     if (copy_len > 0) {
02104       MEMCPY(http_uri_buf, uri, copy_len);
02105       http_uri_buf[copy_len] = 0;
02106     }
02107 #else /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */
02108   if ((uri[0] == '/') &&  (uri[1] == 0)) {
02109 #endif /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */
02110     /* Try each of the configured default filenames until we find one
02111        that exists. */
02112     for (loop = 0; loop < NUM_DEFAULT_FILENAMES; loop++) {
02113       const char* file_name;
02114 #if LWIP_HTTPD_MAX_REQUEST_URI_LEN
02115       if (copy_len > 0) {
02116         size_t len_left = sizeof(http_uri_buf) - copy_len - 1;
02117         if (len_left > 0) {
02118           size_t name_len = strlen(g_psDefaultFilenames[loop].name);
02119           size_t name_copy_len = LWIP_MIN(len_left, name_len);
02120           MEMCPY(&http_uri_buf[copy_len], g_psDefaultFilenames[loop].name, name_copy_len);
02121         }
02122         file_name = http_uri_buf;
02123       } else
02124 #endif /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */
02125       {
02126         file_name = g_psDefaultFilenames[loop].name;
02127       }
02128       LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Looking for %s...\n", file_name));
02129       err = fs_open(&hs->file_handle, file_name);
02130       if(err == ERR_OK) {
02131         uri = file_name;
02132         file = &hs->file_handle;
02133         LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opened.\n"));
02134 #if LWIP_HTTPD_SSI
02135         tag_check = g_psDefaultFilenames[loop].shtml;
02136 #endif /* LWIP_HTTPD_SSI */
02137         break;
02138       }
02139     }
02140   }
02141   if (file == NULL) {
02142     /* No - we've been asked for a specific file. */
02143     /* First, isolate the base URI (without any parameters) */
02144     params = (char *)strchr(uri, '?');
02145     if (params != NULL) {
02146       /* URI contains parameters. NULL-terminate the base URI */
02147       *params = '\0';
02148       params++;
02149     }
02150 
02151 #if LWIP_HTTPD_CGI
02152     http_cgi_paramcount = -1;
02153     /* Does the base URI we have isolated correspond to a CGI handler? */
02154     if (g_iNumCGIs && g_pCGIs) {
02155       for (i = 0; i < g_iNumCGIs; i++) {
02156         if (strcmp(uri, g_pCGIs[i].pcCGIName) == 0) {
02157           /*
02158            * We found a CGI that handles this URI so extract the
02159            * parameters and call the handler.
02160            */
02161            http_cgi_paramcount = extract_uri_parameters(hs, params);
02162            uri = g_pCGIs[i].pfnCGIHandler(i, http_cgi_paramcount, hs->params,
02163                                           hs->param_vals);
02164            break;
02165         }
02166       }
02167     }
02168 #endif /* LWIP_HTTPD_CGI */
02169 
02170     LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opening %s\n", uri));
02171 
02172     err = fs_open(&hs->file_handle, uri);
02173     if (err == ERR_OK) {
02174        file = &hs->file_handle;
02175     } else {
02176       file = http_get_404_file(hs, &uri);
02177     }
02178 #if LWIP_HTTPD_SSI
02179     if (file != NULL) {
02180       /* See if we have been asked for an shtml file and, if so,
02181          enable tag checking. */
02182       const char* ext = NULL, *sub;
02183       char* param = (char*)strstr(uri, "?");
02184       if (param != NULL) {
02185          /* separate uri from parameters for now, set back later */
02186          *param = 0;
02187       }
02188       sub = uri;
02189       ext = uri;
02190       for (sub = strstr(sub, "."); sub != NULL; sub = strstr(sub, "."))
02191       {
02192          ext = sub;
02193          sub++;
02194       }
02195       tag_check = 0;
02196       for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) {
02197         if (!lwip_stricmp(ext, g_pcSSIExtensions[loop])) {
02198           tag_check = 1;
02199           break;
02200         }
02201       }
02202       if (param != NULL) {
02203          *param = '?';
02204       }
02205     }
02206 #endif /* LWIP_HTTPD_SSI */
02207   }
02208   if (file == NULL) {
02209     /* None of the default filenames exist so send back a 404 page */
02210     file = http_get_404_file(hs, &uri);
02211   }
02212   return http_init_file(hs, file, is_09, uri, tag_check, params);
02213 }
02214 
02215 /** Initialize a http connection with a file to send (if found).
02216  * Called by http_find_file and http_find_error_file.
02217  *
02218  * @param hs http connection state
02219  * @param file file structure to send (or NULL if not found)
02220  * @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response)
02221  * @param uri the HTTP header URI
02222  * @param tag_check enable SSI tag checking
02223  * @param params != NULL if URI has parameters (separated by '?')
02224  * @return ERR_OK if file was found and hs has been initialized correctly
02225  *         another err_t otherwise
02226  */
02227 static err_t
02228 http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri,
02229                u8_t tag_check, char* params)
02230 {
02231   if (file != NULL) {
02232     /* file opened, initialise struct http_state */
02233 #if LWIP_HTTPD_SSI
02234     if (tag_check) {
02235       struct http_ssi_state *ssi = http_ssi_state_alloc();
02236       if (ssi != NULL) {
02237         ssi->tag_index = 0;
02238         ssi->tag_state = TAG_NONE;
02239         ssi->parsed = file->data;
02240         ssi->parse_left = file->len;
02241         ssi->tag_end = file->data;
02242         hs->ssi = ssi;
02243       }
02244     }
02245 #else /* LWIP_HTTPD_SSI */
02246     LWIP_UNUSED_ARG(tag_check);
02247 #endif /* LWIP_HTTPD_SSI */
02248     hs->handle = file;
02249     hs->file = file->data;
02250     LWIP_ASSERT("File length must be positive!", (file->len >= 0));
02251 #if LWIP_HTTPD_CUSTOM_FILES
02252     if (file->is_custom_file && (file->data == NULL)) {
02253       /* custom file, need to read data first (via fs_read_custom) */
02254       hs->left = 0;
02255     } else
02256 #endif /* LWIP_HTTPD_CUSTOM_FILES */
02257     {
02258       hs->left = file->len;
02259     }
02260     hs->retries = 0;
02261 #if LWIP_HTTPD_TIMING
02262     hs->time_started = sys_now();
02263 #endif /* LWIP_HTTPD_TIMING */
02264 #if !LWIP_HTTPD_DYNAMIC_HEADERS
02265     LWIP_ASSERT("HTTP headers not included in file system",
02266        (hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) != 0);
02267 #endif /* !LWIP_HTTPD_DYNAMIC_HEADERS */
02268 #if LWIP_HTTPD_SUPPORT_V09
02269     if (is_09 && ((hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) != 0)) {
02270       /* HTTP/0.9 responses are sent without HTTP header,
02271          search for the end of the header. */
02272       char *file_start = lwip_strnstr(hs->file, CRLF CRLF, hs->left);
02273       if (file_start != NULL) {
02274         size_t diff = file_start + 4 - hs->file;
02275         hs->file += diff;
02276         hs->left -= (u32_t)diff;
02277       }
02278     }
02279 #endif /* LWIP_HTTPD_SUPPORT_V09*/
02280 #if LWIP_HTTPD_CGI_SSI
02281     if (params != NULL) {
02282       /* URI contains parameters, call generic CGI handler */
02283       int count;
02284 #if LWIP_HTTPD_CGI
02285       if (http_cgi_paramcount >= 0) {
02286         count = http_cgi_paramcount;
02287       } else
02288 #endif
02289       {
02290         count = extract_uri_parameters(hs, params);
02291       }
02292       httpd_cgi_handler(uri, count, http_cgi_params, http_cgi_param_vals
02293 #if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE
02294          , hs->handle->state
02295 #endif /* LWIP_HTTPD_FILE_STATE */
02296                         );
02297     }
02298 #else /* LWIP_HTTPD_CGI_SSI */
02299     LWIP_UNUSED_ARG(params);
02300 #endif /* LWIP_HTTPD_CGI_SSI */
02301   } else {
02302     hs->handle = NULL;
02303     hs->file = NULL;
02304     hs->left = 0;
02305     hs->retries = 0;
02306   }
02307 #if LWIP_HTTPD_DYNAMIC_HEADERS
02308   /* Determine the HTTP headers to send based on the file extension of
02309    * the requested URI. */
02310   if ((hs->handle == NULL) || ((hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) == 0)) {
02311     get_http_headers(hs, uri);
02312   }
02313 #else /* LWIP_HTTPD_DYNAMIC_HEADERS */
02314   LWIP_UNUSED_ARG(uri);
02315 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
02316 #if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
02317   if (hs->keepalive) {
02318 #if LWIP_HTTPD_SSI
02319      if (hs->ssi != NULL) {
02320        hs->keepalive = 0;
02321      } else
02322 #endif /* LWIP_HTTPD_SSI */
02323      {
02324        if ((hs->handle != NULL) &&
02325            ((hs->handle->flags & (FS_FILE_FLAGS_HEADER_INCLUDED|FS_FILE_FLAGS_HEADER_PERSISTENT)) == FS_FILE_FLAGS_HEADER_INCLUDED)) {
02326          hs->keepalive = 0;
02327        }
02328      }
02329   }
02330 #endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
02331   return ERR_OK;
02332 }
02333 
02334 /**
02335  * The pcb had an error and is already deallocated.
02336  * The argument might still be valid (if != NULL).
02337  */
02338 static void
02339 http_err(void *arg, err_t err)
02340 {
02341   struct http_state *hs = (struct http_state *)arg;
02342   LWIP_UNUSED_ARG(err);
02343 
02344   LWIP_DEBUGF(HTTPD_DEBUG, ("http_err: %s", lwip_strerr(err)));
02345 
02346   if (hs != NULL) {
02347     http_state_free(hs);
02348   }
02349 }
02350 
02351 /**
02352  * Data has been sent and acknowledged by the remote host.
02353  * This means that more data can be sent.
02354  */
02355 static err_t
02356 http_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
02357 {
02358   struct http_state *hs = (struct http_state *)arg;
02359 
02360   LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_sent %p\n", (void*)pcb));
02361 
02362   LWIP_UNUSED_ARG(len);
02363 
02364   if (hs == NULL) {
02365     return ERR_OK;
02366   }
02367 
02368   hs->retries = 0;
02369 
02370   http_send(pcb, hs);
02371 
02372   return ERR_OK;
02373 }
02374 
02375 /**
02376  * The poll function is called every 2nd second.
02377  * If there has been no data sent (which resets the retries) in 8 seconds, close.
02378  * If the last portion of a file has not been sent in 2 seconds, close.
02379  *
02380  * This could be increased, but we don't want to waste resources for bad connections.
02381  */
02382 static err_t
02383 http_poll(void *arg, struct tcp_pcb *pcb)
02384 {
02385   struct http_state *hs = (struct http_state *)arg;
02386   LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_poll: pcb=%p hs=%p pcb_state=%s\n",
02387     (void*)pcb, (void*)hs, tcp_debug_state_str(pcb->state)));
02388 
02389   if (hs == NULL) {
02390     err_t closed;
02391     /* arg is null, close. */
02392     LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: arg is NULL, close\n"));
02393     closed = http_close_conn(pcb, NULL);
02394     LWIP_UNUSED_ARG(closed);
02395 #if LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR
02396     if (closed == ERR_MEM) {
02397        tcp_abort(pcb);
02398        return ERR_ABRT;
02399     }
02400 #endif /* LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR */
02401     return ERR_OK;
02402   } else {
02403     hs->retries++;
02404     if (hs->retries == HTTPD_MAX_RETRIES) {
02405       LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: too many retries, close\n"));
02406       http_close_conn(pcb, hs);
02407       return ERR_OK;
02408     }
02409 
02410     /* If this connection has a file open, try to send some more data. If
02411      * it has not yet received a GET request, don't do this since it will
02412      * cause the connection to close immediately. */
02413     if(hs && (hs->handle)) {
02414       LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_poll: try to send more data\n"));
02415       if(http_send(pcb, hs)) {
02416         /* If we wrote anything to be sent, go ahead and send it now. */
02417         LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("tcp_output\n"));
02418         tcp_output(pcb);
02419       }
02420     }
02421   }
02422 
02423   return ERR_OK;
02424 }
02425 
02426 /**
02427  * Data has been received on this pcb.
02428  * For HTTP 1.0, this should normally only happen once (if the request fits in one packet).
02429  */
02430 static err_t
02431 http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
02432 {
02433   struct http_state *hs = (struct http_state *)arg;
02434   LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_recv: pcb=%p pbuf=%p err=%s\n", (void*)pcb,
02435     (void*)p, lwip_strerr(err)));
02436 
02437   if ((err != ERR_OK) || (p == NULL) || (hs == NULL)) {
02438     /* error or closed by other side? */
02439     if (p != NULL) {
02440       /* Inform TCP that we have taken the data. */
02441       tcp_recved(pcb, p->tot_len);
02442       pbuf_free(p);
02443     }
02444     if (hs == NULL) {
02445       /* this should not happen, only to be robust */
02446       LWIP_DEBUGF(HTTPD_DEBUG, ("Error, http_recv: hs is NULL, close\n"));
02447     }
02448     http_close_conn(pcb, hs);
02449     return ERR_OK;
02450   }
02451 
02452 #if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
02453   if (hs->no_auto_wnd) {
02454      hs->unrecved_bytes += p->tot_len;
02455   } else
02456 #endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
02457   {
02458     /* Inform TCP that we have taken the data. */
02459     tcp_recved(pcb, p->tot_len);
02460   }
02461 
02462 #if LWIP_HTTPD_SUPPORT_POST
02463   if (hs->post_content_len_left > 0) {
02464     /* reset idle counter when POST data is received */
02465     hs->retries = 0;
02466     /* this is data for a POST, pass the complete pbuf to the application */
02467     http_post_rxpbuf(hs, p);
02468     /* pbuf is passed to the application, don't free it! */
02469     if (hs->post_content_len_left == 0) {
02470       /* all data received, send response or close connection */
02471       http_send(pcb, hs);
02472     }
02473     return ERR_OK;
02474   } else
02475 #endif /* LWIP_HTTPD_SUPPORT_POST */
02476   {
02477     if (hs->handle == NULL) {
02478       err_t parsed = http_parse_request(p, hs, pcb);
02479       LWIP_ASSERT("http_parse_request: unexpected return value", parsed == ERR_OK
02480         || parsed == ERR_INPROGRESS ||parsed == ERR_ARG || parsed == ERR_USE);
02481 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
02482       if (parsed != ERR_INPROGRESS) {
02483         /* request fully parsed or error */
02484         if (hs->req != NULL) {
02485           pbuf_free(hs->req);
02486           hs->req = NULL;
02487         }
02488       }
02489 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
02490       pbuf_free(p);
02491       if (parsed == ERR_OK) {
02492 #if LWIP_HTTPD_SUPPORT_POST
02493        if (hs->post_content_len_left == 0)
02494 #endif /* LWIP_HTTPD_SUPPORT_POST */
02495         {
02496           LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_recv: data %p len %"S32_F"\n", (const void*)hs->file, hs->left));
02497           http_send(pcb, hs);
02498         }
02499       } else if (parsed == ERR_ARG) {
02500         /* @todo: close on ERR_USE? */
02501         http_close_conn(pcb, hs);
02502       }
02503     } else {
02504       LWIP_DEBUGF(HTTPD_DEBUG, ("http_recv: already sending data\n"));
02505       /* already sending but still receiving data, we might want to RST here? */
02506       pbuf_free(p);
02507     }
02508   }
02509   return ERR_OK;
02510 }
02511 
02512 /**
02513  * A new incoming connection has been accepted.
02514  */
02515 static err_t
02516 http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
02517 {
02518   struct http_state *hs;
02519   LWIP_UNUSED_ARG(err);
02520   LWIP_UNUSED_ARG(arg);
02521   LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept %p / %p\n", (void*)pcb, arg));
02522 
02523   if ((err != ERR_OK) || (pcb == NULL)) {
02524     return ERR_VAL;
02525   }
02526 
02527   /* Set priority */
02528   tcp_setprio(pcb, HTTPD_TCP_PRIO);
02529 
02530   /* Allocate memory for the structure that holds the state of the
02531      connection - initialized by that function. */
02532   hs = http_state_alloc();
02533   if (hs == NULL) {
02534     LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept: Out of memory, RST\n"));
02535     return ERR_MEM;
02536   }
02537   hs->pcb = pcb;
02538 
02539   /* Tell TCP that this is the structure we wish to be passed for our
02540      callbacks. */
02541   tcp_arg(pcb, hs);
02542 
02543   /* Set up the various callback functions */
02544   tcp_recv(pcb, http_recv);
02545   tcp_err(pcb, http_err);
02546   tcp_poll(pcb, http_poll, HTTPD_POLL_INTERVAL);
02547   tcp_sent(pcb, http_sent);
02548 
02549   return ERR_OK;
02550 }
02551 
02552 /**
02553  * @ingroup httpd
02554  * Initialize the httpd: set up a listening PCB and bind it to the defined port
02555  */
02556 void
02557 httpd_init(void)
02558 {
02559   struct tcp_pcb *pcb;
02560   err_t err;
02561 
02562 #if HTTPD_USE_MEM_POOL
02563   LWIP_MEMPOOL_INIT(HTTPD_STATE);
02564 #if LWIP_HTTPD_SSI
02565   LWIP_MEMPOOL_INIT(HTTPD_SSI_STATE);
02566 #endif
02567 #endif
02568   LWIP_DEBUGF(HTTPD_DEBUG, ("httpd_init\n"));
02569 
02570   pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
02571   LWIP_ASSERT("httpd_init: tcp_new failed", pcb != NULL);
02572   tcp_setprio(pcb, HTTPD_TCP_PRIO);
02573   /* set SOF_REUSEADDR here to explicitly bind httpd to multiple interfaces */
02574   err = tcp_bind(pcb, IP_ANY_TYPE, HTTPD_SERVER_PORT);
02575   LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
02576   LWIP_ASSERT("httpd_init: tcp_bind failed", err == ERR_OK);
02577   pcb = tcp_listen(pcb);
02578   LWIP_ASSERT("httpd_init: tcp_listen failed", pcb != NULL);
02579   tcp_accept(pcb, http_accept);
02580 }
02581 
02582 #if LWIP_HTTPD_SSI
02583 /**
02584  * Set the SSI handler function.
02585  *
02586  * @param ssi_handler the SSI handler function
02587  * @param tags an array of SSI tag strings to search for in SSI-enabled files
02588  * @param num_tags number of tags in the 'tags' array
02589  */
02590 void
02591 http_set_ssi_handler(tSSIHandler ssi_handler, const char **tags, int num_tags)
02592 {
02593   LWIP_DEBUGF(HTTPD_DEBUG, ("http_set_ssi_handler\n"));
02594 
02595   LWIP_ASSERT("no ssi_handler given", ssi_handler != NULL);
02596   g_pfnSSIHandler = ssi_handler;
02597 
02598 #if LWIP_HTTPD_SSI_RAW
02599   LWIP_UNUSED_ARG(tags);
02600   LWIP_UNUSED_ARG(num_tags);
02601 #else /* LWIP_HTTPD_SSI_RAW */
02602   LWIP_ASSERT("no tags given", tags != NULL);
02603   LWIP_ASSERT("invalid number of tags", num_tags > 0);
02604 
02605   g_ppcTags = tags;
02606   g_iNumTags = num_tags;
02607 #endif /* !LWIP_HTTPD_SSI_RAW */
02608 }
02609 #endif /* LWIP_HTTPD_SSI */
02610 
02611 #if LWIP_HTTPD_CGI
02612 /**
02613  * Set an array of CGI filenames/handler functions
02614  *
02615  * @param cgis an array of CGI filenames/handler functions
02616  * @param num_handlers number of elements in the 'cgis' array
02617  */
02618 void
02619 http_set_cgi_handlers(const tCGI *cgis, int num_handlers)
02620 {
02621   LWIP_ASSERT("no cgis given", cgis != NULL);
02622   LWIP_ASSERT("invalid number of handlers", num_handlers > 0);
02623 
02624   g_pCGIs = cgis;
02625   g_iNumCGIs = num_handlers;
02626 }
02627 #endif /* LWIP_HTTPD_CGI */
02628 
02629 #endif /* LWIP_TCP && LWIP_CALLBACK_API */