Daiki Kato / mbed-os-lychee

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

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