1/**
2 * @file
3 * LWIP HTTP server implementation
4 */
5
6/*
7 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright notice,
14 *    this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 *    this list of conditions and the following disclaimer in the documentation
17 *    and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30 * OF SUCH DAMAGE.
31 *
32 * This file is part of the lwIP TCP/IP stack.
33 *
34 * Author: Adam Dunkels <adam@sics.se>
35 *         Simon Goldschmidt
36 *
37 */
38
39/**
40 * @defgroup httpd HTTP server
41 * @ingroup apps
42 *
43 * This httpd supports for a
44 * rudimentary server-side-include facility which will replace tags of the form
45 * <!--#tag--> in any file whose extension is .shtml, .shtm or .ssi with
46 * strings provided by an include handler whose pointer is provided to the
47 * module via function http_set_ssi_handler().
48 * Additionally, a simple common
49 * gateway interface (CGI) handling mechanism has been added to allow clients
50 * to hook functions to particular request URIs.
51 *
52 * To enable SSI support, define label LWIP_HTTPD_SSI in lwipopts.h.
53 * To enable CGI support, define label LWIP_HTTPD_CGI in lwipopts.h.
54 *
55 * By default, the server assumes that HTTP headers are already present in
56 * each file stored in the file system.  By defining LWIP_HTTPD_DYNAMIC_HEADERS in
57 * lwipopts.h, this behavior can be changed such that the server inserts the
58 * headers automatically based on the extension of the file being served.  If
59 * this mode is used, be careful to ensure that the file system image used
60 * does not already contain the header information.
61 *
62 * File system images without headers can be created using the makefsfile
63 * tool with the -h command line option.
64 *
65 *
66 * Notes about valid SSI tags
67 * --------------------------
68 *
69 * The following assumptions are made about tags used in SSI markers:
70 *
71 * 1. No tag may contain '-' or whitespace characters within the tag name.
72 * 2. Whitespace is allowed between the tag leadin "<!--#" and the start of
73 *    the tag name and between the tag name and the leadout string "-->".
74 * 3. The maximum tag name length is LWIP_HTTPD_MAX_TAG_NAME_LEN, currently 8 characters.
75 *
76 * Notes on CGI usage
77 * ------------------
78 *
79 * The simple CGI support offered here works with GET method requests only
80 * and can handle up to 16 parameters encoded into the URI. The handler
81 * function may not write directly to the HTTP output but must return a
82 * filename that the HTTP server will send to the browser as a response to
83 * the incoming CGI request.
84 *
85 *
86 *
87 * The list of supported file types is quite short, so if makefsdata complains
88 * about an unknown extension, make sure to add it (and its doctype) to
89 * the 'g_psHTTPHeaders' list.
90 */
91#include "lwip/init.h"
92#include "lwip/apps/httpd.h"
93#include "lwip/debug.h"
94#include "lwip/stats.h"
95#include "lwip/apps/fs.h"
96#include "httpd_structs.h"
97#include "lwip/def.h"
98#include "lwip/ip.h"
99#include "lwip/tcp.h"
100
101#include <string.h> /* memset */
102#include <stdlib.h> /* atoi */
103#include <stdio.h>
104
105#if LWIP_TCP && LWIP_CALLBACK_API
106
107/** Minimum length for a valid HTTP/0.9 request: "GET /\r\n" -> 7 bytes */
108#define MIN_REQ_LEN   7
109
110#define CRLF "\r\n"
111#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
112#define HTTP11_CONNECTIONKEEPALIVE  "Connection: keep-alive"
113#define HTTP11_CONNECTIONKEEPALIVE2 "Connection: Keep-Alive"
114#endif
115
116/** These defines check whether tcp_write has to copy data or not */
117
118/** This was TI's check whether to let TCP copy data or not
119 * \#define HTTP_IS_DATA_VOLATILE(hs) ((hs->file < (char *)0x20000000) ? 0 : TCP_WRITE_FLAG_COPY)
120 */
121#ifndef HTTP_IS_DATA_VOLATILE
122#if LWIP_HTTPD_SSI
123/* Copy for SSI files, no copy for non-SSI files */
124#define HTTP_IS_DATA_VOLATILE(hs)   ((hs)->ssi ? TCP_WRITE_FLAG_COPY : 0)
125#else /* LWIP_HTTPD_SSI */
126/** Default: don't copy if the data is sent from file-system directly */
127#define HTTP_IS_DATA_VOLATILE(hs) (((hs->file != NULL) && (hs->handle != NULL) && (hs->file == \
128                                   (const char*)hs->handle->data + hs->handle->len - hs->left)) \
129                                   ? 0 : TCP_WRITE_FLAG_COPY)
130#endif /* LWIP_HTTPD_SSI */
131#endif
132
133/** Default: headers are sent from ROM */
134#ifndef HTTP_IS_HDR_VOLATILE
135#define HTTP_IS_HDR_VOLATILE(hs, ptr) 0
136#endif
137
138/* Return values for http_send_*() */
139#define HTTP_DATA_TO_SEND_BREAK    2
140#define HTTP_DATA_TO_SEND_CONTINUE 1
141#define HTTP_NO_DATA_TO_SEND       0
142
143typedef struct
144{
145  const char *name;
146  u8_t shtml;
147} default_filename;
148
149const default_filename g_psDefaultFilenames[] = {
150  {"/index.shtml", 1 },
151  {"/index.ssi",   1 },
152  {"/index.shtm",  1 },
153  {"/index.html",  0 },
154  {"/index.htm",   0 }
155};
156
157#define NUM_DEFAULT_FILENAMES (sizeof(g_psDefaultFilenames) /   \
158                               sizeof(default_filename))
159
160#if LWIP_HTTPD_SUPPORT_REQUESTLIST
161/** HTTP request is copied here from pbufs for simple parsing */
162static char httpd_req_buf[LWIP_HTTPD_MAX_REQ_LENGTH+1];
163#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
164
165#if LWIP_HTTPD_SUPPORT_POST
166#if LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN > LWIP_HTTPD_MAX_REQUEST_URI_LEN
167#define LWIP_HTTPD_URI_BUF_LEN LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN
168#endif
169#endif
170#ifndef LWIP_HTTPD_URI_BUF_LEN
171#define LWIP_HTTPD_URI_BUF_LEN LWIP_HTTPD_MAX_REQUEST_URI_LEN
172#endif
173#if LWIP_HTTPD_URI_BUF_LEN
174/* Filename for response file to send when POST is finished or
175 * search for default files when a directory is requested. */
176static char http_uri_buf[LWIP_HTTPD_URI_BUF_LEN+1];
177#endif
178
179#if LWIP_HTTPD_DYNAMIC_HEADERS
180/* The number of individual strings that comprise the headers sent before each
181 * requested file.
182 */
183#define NUM_FILE_HDR_STRINGS 5
184#define HDR_STRINGS_IDX_HTTP_STATUS          0 /* e.g. "HTTP/1.0 200 OK\r\n" */
185#define HDR_STRINGS_IDX_SERVER_NAME          1 /* e.g. "Server: "HTTPD_SERVER_AGENT"\r\n" */
186#define HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE 2 /* e.g. "Content-Length: xy\r\n" and/or "Connection: keep-alive\r\n" */
187#define HDR_STRINGS_IDX_CONTENT_LEN_NR       3 /* the byte count, when content-length is used */
188#define HDR_STRINGS_IDX_CONTENT_TYPE         4 /* the content type (or default answer content type including default document) */
189
190/* The dynamically generated Content-Length buffer needs space for CRLF + NULL */
191#define LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET 3
192#ifndef LWIP_HTTPD_MAX_CONTENT_LEN_SIZE
193/* The dynamically generated Content-Length buffer shall be able to work with
194   ~953 MB (9 digits) */
195#define LWIP_HTTPD_MAX_CONTENT_LEN_SIZE   (9 + LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET)
196#endif
197#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
198
199#if LWIP_HTTPD_SSI
200
201#define HTTPD_LAST_TAG_PART 0xFFFF
202
203enum tag_check_state {
204  TAG_NONE,       /* Not processing an SSI tag */
205  TAG_LEADIN,     /* Tag lead in "<!--#" being processed */
206  TAG_FOUND,      /* Tag name being read, looking for lead-out start */
207  TAG_LEADOUT,    /* Tag lead out "-->" being processed */
208  TAG_SENDING     /* Sending tag replacement string */
209};
210
211struct http_ssi_state {
212  const char *parsed;     /* Pointer to the first unparsed byte in buf. */
213#if !LWIP_HTTPD_SSI_INCLUDE_TAG
214  const char *tag_started;/* Pointer to the first opening '<' of the tag. */
215#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */
216  const char *tag_end;    /* Pointer to char after the closing '>' of the tag. */
217  u32_t parse_left; /* Number of unparsed bytes in buf. */
218  u16_t tag_index;   /* Counter used by tag parsing state machine */
219  u16_t tag_insert_len; /* Length of insert in string tag_insert */
220#if LWIP_HTTPD_SSI_MULTIPART
221  u16_t tag_part; /* Counter passed to and changed by tag insertion function to insert multiple times */
222#endif /* LWIP_HTTPD_SSI_MULTIPART */
223  u8_t tag_name_len; /* Length of the tag name in string tag_name */
224  char tag_name[LWIP_HTTPD_MAX_TAG_NAME_LEN + 1]; /* Last tag name extracted */
225  char tag_insert[LWIP_HTTPD_MAX_TAG_INSERT_LEN + 1]; /* Insert string for tag_name */
226  enum tag_check_state tag_state; /* State of the tag processor */
227};
228#endif /* LWIP_HTTPD_SSI */
229
230struct http_state {
231#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
232  struct http_state *next;
233#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
234  struct fs_file file_handle;
235  struct fs_file *handle;
236  const char *file;       /* Pointer to first unsent byte in buf. */
237
238  struct tcp_pcb *pcb;
239#if LWIP_HTTPD_SUPPORT_REQUESTLIST
240  struct pbuf *req;
241#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
242
243#if LWIP_HTTPD_DYNAMIC_FILE_READ
244  char *buf;        /* File read buffer. */
245  int buf_len;      /* Size of file read buffer, buf. */
246#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
247  u32_t left;       /* Number of unsent bytes in buf. */
248  u8_t retries;
249#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
250  u8_t keepalive;
251#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
252#if LWIP_HTTPD_SSI
253  struct http_ssi_state *ssi;
254#endif /* LWIP_HTTPD_SSI */
255#if LWIP_HTTPD_CGI
256  char *params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */
257  char *param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */
258#endif /* LWIP_HTTPD_CGI */
259#if LWIP_HTTPD_DYNAMIC_HEADERS
260  const char *hdrs[NUM_FILE_HDR_STRINGS]; /* HTTP headers to be sent. */
261  char hdr_content_len[LWIP_HTTPD_MAX_CONTENT_LEN_SIZE];
262  u16_t hdr_pos;     /* The position of the first unsent header byte in the
263                        current string */
264  u16_t hdr_index;   /* The index of the hdr string currently being sent. */
265#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
266#if LWIP_HTTPD_TIMING
267  u32_t time_started;
268#endif /* LWIP_HTTPD_TIMING */
269#if LWIP_HTTPD_SUPPORT_POST
270  u32_t post_content_len_left;
271#if LWIP_HTTPD_POST_MANUAL_WND
272  u32_t unrecved_bytes;
273  u8_t no_auto_wnd;
274  u8_t post_finished;
275#endif /* LWIP_HTTPD_POST_MANUAL_WND */
276#endif /* LWIP_HTTPD_SUPPORT_POST*/
277};
278
279#if HTTPD_USE_MEM_POOL
280LWIP_MEMPOOL_DECLARE(HTTPD_STATE,     MEMP_NUM_PARALLEL_HTTPD_CONNS,     sizeof(struct http_state),     "HTTPD_STATE")
281#if LWIP_HTTPD_SSI
282LWIP_MEMPOOL_DECLARE(HTTPD_SSI_STATE, MEMP_NUM_PARALLEL_HTTPD_SSI_CONNS, sizeof(struct http_ssi_state), "HTTPD_SSI_STATE")
283#define HTTP_FREE_SSI_STATE(x)  LWIP_MEMPOOL_FREE(HTTPD_SSI_STATE, (x))
284#define HTTP_ALLOC_SSI_STATE()  (struct http_ssi_state *)LWIP_MEMPOOL_ALLOC(HTTPD_SSI_STATE)
285#endif /* LWIP_HTTPD_SSI */
286#define HTTP_ALLOC_HTTP_STATE() (struct http_state *)LWIP_MEMPOOL_ALLOC(HTTPD_STATE)
287#define HTTP_FREE_HTTP_STATE(x) LWIP_MEMPOOL_FREE(HTTPD_STATE, (x))
288#else /* HTTPD_USE_MEM_POOL */
289#define HTTP_ALLOC_HTTP_STATE() (struct http_state *)mem_malloc(sizeof(struct http_state))
290#define HTTP_FREE_HTTP_STATE(x) mem_free(x)
291#if LWIP_HTTPD_SSI
292#define HTTP_ALLOC_SSI_STATE()  (struct http_ssi_state *)mem_malloc(sizeof(struct http_ssi_state))
293#define HTTP_FREE_SSI_STATE(x)  mem_free(x)
294#endif /* LWIP_HTTPD_SSI */
295#endif /* HTTPD_USE_MEM_POOL */
296
297static err_t http_close_conn(struct tcp_pcb *pcb, struct http_state *hs);
298static err_t http_close_or_abort_conn(struct tcp_pcb *pcb, struct http_state *hs, u8_t abort_conn);
299static err_t http_find_file(struct http_state *hs, const char *uri, int is_09);
300static 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);
301static err_t http_poll(void *arg, struct tcp_pcb *pcb);
302static u8_t http_check_eof(struct tcp_pcb *pcb, struct http_state *hs);
303#if LWIP_HTTPD_FS_ASYNC_READ
304static void http_continue(void *connection);
305#endif /* LWIP_HTTPD_FS_ASYNC_READ */
306
307#if LWIP_HTTPD_SSI
308/* SSI insert handler function pointer. */
309tSSIHandler g_pfnSSIHandler;
310#if !LWIP_HTTPD_SSI_RAW
311int g_iNumTags;
312const char **g_ppcTags;
313#endif /* !LWIP_HTTPD_SSI_RAW */
314
315#define LEN_TAG_LEAD_IN 5
316const char * const g_pcTagLeadIn = "<!--#";
317
318#define LEN_TAG_LEAD_OUT 3
319const char * const g_pcTagLeadOut = "-->";
320#endif /* LWIP_HTTPD_SSI */
321
322#if LWIP_HTTPD_CGI
323/* CGI handler information */
324const tCGI *g_pCGIs;
325int g_iNumCGIs;
326int http_cgi_paramcount;
327#define http_cgi_params     hs->params
328#define http_cgi_param_vals hs->param_vals
329#elif LWIP_HTTPD_CGI_SSI
330char *http_cgi_params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */
331char *http_cgi_param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */
332#endif /* LWIP_HTTPD_CGI */
333
334#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
335/** global list of active HTTP connections, use to kill the oldest when
336    running out of memory */
337static struct http_state *http_connections;
338
339static void
340http_add_connection(struct http_state *hs)
341{
342  /* add the connection to the list */
343  hs->next = http_connections;
344  http_connections = hs;
345}
346
347static void
348http_remove_connection(struct http_state *hs)
349{
350  /* take the connection off the list */
351  if (http_connections) {
352    if (http_connections == hs) {
353      http_connections = hs->next;
354    } else {
355      struct http_state *last;
356      for(last = http_connections; last->next != NULL; last = last->next) {
357        if (last->next == hs) {
358          last->next = hs->next;
359          break;
360        }
361      }
362    }
363  }
364}
365
366static void
367http_kill_oldest_connection(u8_t ssi_required)
368{
369  struct http_state *hs = http_connections;
370  struct http_state *hs_free_next = NULL;
371  while(hs && hs->next) {
372#if LWIP_HTTPD_SSI
373    if (ssi_required) {
374      if (hs->next->ssi != NULL) {
375        hs_free_next = hs;
376      }
377    } else
378#else /* LWIP_HTTPD_SSI */
379    LWIP_UNUSED_ARG(ssi_required);
380#endif /* LWIP_HTTPD_SSI */
381    {
382      hs_free_next = hs;
383    }
384    LWIP_ASSERT("broken list", hs != hs->next);
385    hs = hs->next;
386  }
387  if (hs_free_next != NULL) {
388    LWIP_ASSERT("hs_free_next->next != NULL", hs_free_next->next != NULL);
389    LWIP_ASSERT("hs_free_next->next->pcb != NULL", hs_free_next->next->pcb != NULL);
390    /* send RST when killing a connection because of memory shortage */
391    http_close_or_abort_conn(hs_free_next->next->pcb, hs_free_next->next, 1); /* this also unlinks the http_state from the list */
392  }
393}
394#else /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
395
396#define http_add_connection(hs)
397#define http_remove_connection(hs)
398
399#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
400
401#if LWIP_HTTPD_SSI
402/** Allocate as struct http_ssi_state. */
403static struct http_ssi_state*
404http_ssi_state_alloc(void)
405{
406  struct http_ssi_state *ret = HTTP_ALLOC_SSI_STATE();
407#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
408  if (ret == NULL) {
409    http_kill_oldest_connection(1);
410    ret = HTTP_ALLOC_SSI_STATE();
411  }
412#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
413  if (ret != NULL) {
414    memset(ret, 0, sizeof(struct http_ssi_state));
415  }
416  return ret;
417}
418
419/** Free a struct http_ssi_state. */
420static void
421http_ssi_state_free(struct http_ssi_state *ssi)
422{
423  if (ssi != NULL) {
424    HTTP_FREE_SSI_STATE(ssi);
425  }
426}
427#endif /* LWIP_HTTPD_SSI */
428
429/** Initialize a struct http_state.
430 */
431static void
432http_state_init(struct http_state* hs)
433{
434  /* Initialize the structure. */
435  memset(hs, 0, sizeof(struct http_state));
436#if LWIP_HTTPD_DYNAMIC_HEADERS
437  /* Indicate that the headers are not yet valid */
438  hs->hdr_index = NUM_FILE_HDR_STRINGS;
439#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
440}
441
442/** Allocate a struct http_state. */
443static struct http_state*
444http_state_alloc(void)
445{
446  struct http_state *ret = HTTP_ALLOC_HTTP_STATE();
447#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
448  if (ret == NULL) {
449    http_kill_oldest_connection(0);
450    ret = HTTP_ALLOC_HTTP_STATE();
451  }
452#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
453  if (ret != NULL) {
454    http_state_init(ret);
455    http_add_connection(ret);
456  }
457  return ret;
458}
459
460/** Free a struct http_state.
461 * Also frees the file data if dynamic.
462 */
463static void
464http_state_eof(struct http_state *hs)
465{
466  if(hs->handle) {
467#if LWIP_HTTPD_TIMING
468    u32_t ms_needed = sys_now() - hs->time_started;
469    u32_t needed = LWIP_MAX(1, (ms_needed/100));
470    LWIP_DEBUGF(HTTPD_DEBUG_TIMING, ("httpd: needed %"U32_F" ms to send file of %d bytes -> %"U32_F" bytes/sec\n",
471      ms_needed, hs->handle->len, ((((u32_t)hs->handle->len) * 10) / needed)));
472#endif /* LWIP_HTTPD_TIMING */
473    fs_close(hs->handle);
474    hs->handle = NULL;
475  }
476#if LWIP_HTTPD_DYNAMIC_FILE_READ
477  if (hs->buf != NULL) {
478    mem_free(hs->buf);
479    hs->buf = NULL;
480  }
481#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
482#if LWIP_HTTPD_SSI
483  if (hs->ssi) {
484    http_ssi_state_free(hs->ssi);
485    hs->ssi = NULL;
486  }
487#endif /* LWIP_HTTPD_SSI */
488#if LWIP_HTTPD_SUPPORT_REQUESTLIST
489  if (hs->req) {
490    pbuf_free(hs->req);
491    hs->req = NULL;
492  }
493#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
494}
495
496/** Free a struct http_state.
497 * Also frees the file data if dynamic.
498 */
499static void
500http_state_free(struct http_state *hs)
501{
502  if (hs != NULL) {
503    http_state_eof(hs);
504    http_remove_connection(hs);
505    HTTP_FREE_HTTP_STATE(hs);
506  }
507}
508
509/** Call tcp_write() in a loop trying smaller and smaller length
510 *
511 * @param pcb tcp_pcb to send
512 * @param ptr Data to send
513 * @param length Length of data to send (in/out: on return, contains the
514 *        amount of data sent)
515 * @param apiflags directly passed to tcp_write
516 * @return the return value of tcp_write
517 */
518static err_t
519http_write(struct tcp_pcb *pcb, const void* ptr, u16_t *length, u8_t apiflags)
520{
521  u16_t len, max_len;
522  err_t err;
523  LWIP_ASSERT("length != NULL", length != NULL);
524  len = *length;
525  if (len == 0) {
526    return ERR_OK;
527  }
528  /* We cannot send more data than space available in the send buffer. */
529  max_len = tcp_sndbuf(pcb);
530  if (max_len < len) {
531    len = max_len;
532  }
533#ifdef HTTPD_MAX_WRITE_LEN
534  /* Additional limitation: e.g. don't enqueue more than 2*mss at once */
535  max_len = HTTPD_MAX_WRITE_LEN(pcb);
536  if(len > max_len) {
537    len = max_len;
538  }
539#endif /* HTTPD_MAX_WRITE_LEN */
540  do {
541    LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Trying go send %d bytes\n", len));
542    err = tcp_write(pcb, ptr, len, apiflags);
543    if (err == ERR_MEM) {
544      if ((tcp_sndbuf(pcb) == 0) ||
545        (tcp_sndqueuelen(pcb) >= TCP_SND_QUEUELEN)) {
546          /* no need to try smaller sizes */
547          len = 1;
548      } else {
549        len /= 2;
550      }
551      LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE,
552        ("Send failed, trying less (%d bytes)\n", len));
553    }
554  } while ((err == ERR_MEM) && (len > 1));
555
556  if (err == ERR_OK) {
557    LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Sent %d bytes\n", len));
558    *length = len;
559  } else {
560    LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Send failed with err %d (\"%s\")\n", err, lwip_strerr(err)));
561    *length = 0;
562  }
563
564#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
565   /* ensure nagle is normally enabled (only disabled for persistent connections
566      when all data has been enqueued but the connection stays open for the next
567      request */
568   tcp_nagle_enable(pcb);
569#endif
570
571  return err;
572}
573
574/**
575 * The connection shall be actively closed (using RST to close from fault states).
576 * Reset the sent- and recv-callbacks.
577 *
578 * @param pcb the tcp pcb to reset callbacks
579 * @param hs connection state to free
580 */
581static err_t
582http_close_or_abort_conn(struct tcp_pcb *pcb, struct http_state *hs, u8_t abort_conn)
583{
584  err_t err;
585  LWIP_DEBUGF(HTTPD_DEBUG, ("Closing connection %p\n", (void*)pcb));
586
587#if LWIP_HTTPD_SUPPORT_POST
588  if (hs != NULL) {
589    if ((hs->post_content_len_left != 0)
590#if LWIP_HTTPD_POST_MANUAL_WND
591       || ((hs->no_auto_wnd != 0) && (hs->unrecved_bytes != 0))
592#endif /* LWIP_HTTPD_POST_MANUAL_WND */
593       ) {
594      /* make sure the post code knows that the connection is closed */
595      http_uri_buf[0] = 0;
596      httpd_post_finished(hs, http_uri_buf, LWIP_HTTPD_URI_BUF_LEN);
597    }
598  }
599#endif /* LWIP_HTTPD_SUPPORT_POST*/
600
601
602  tcp_arg(pcb, NULL);
603  tcp_recv(pcb, NULL);
604  tcp_err(pcb, NULL);
605  tcp_poll(pcb, NULL, 0);
606  tcp_sent(pcb, NULL);
607  if (hs != NULL) {
608    http_state_free(hs);
609  }
610
611  if (abort_conn) {
612    tcp_abort(pcb);
613    return ERR_OK;
614  }
615  err = tcp_close(pcb);
616  if (err != ERR_OK) {
617    LWIP_DEBUGF(HTTPD_DEBUG, ("Error %d closing %p\n", err, (void*)pcb));
618    /* error closing, try again later in poll */
619    tcp_poll(pcb, http_poll, HTTPD_POLL_INTERVAL);
620  }
621  return err;
622}
623
624/**
625 * The connection shall be actively closed.
626 * Reset the sent- and recv-callbacks.
627 *
628 * @param pcb the tcp pcb to reset callbacks
629 * @param hs connection state to free
630 */
631static err_t
632http_close_conn(struct tcp_pcb *pcb, struct http_state *hs)
633{
634   return http_close_or_abort_conn(pcb, hs, 0);
635}
636
637/** End of file: either close the connection (Connection: close) or
638 * close the file (Connection: keep-alive)
639 */
640static void
641http_eof(struct tcp_pcb *pcb, struct http_state *hs)
642{
643  /* HTTP/1.1 persistent connection? (Not supported for SSI) */
644#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
645  if (hs->keepalive) {
646    http_remove_connection(hs);
647
648    http_state_eof(hs);
649    http_state_init(hs);
650    /* restore state: */
651    hs->pcb = pcb;
652    hs->keepalive = 1;
653    http_add_connection(hs);
654    /* ensure nagle doesn't interfere with sending all data as fast as possible: */
655    tcp_nagle_disable(pcb);
656  } else
657#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
658  {
659    http_close_conn(pcb, hs);
660  }
661}
662
663#if LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI
664/**
665 * Extract URI parameters from the parameter-part of an URI in the form
666 * "test.cgi?x=y" @todo: better explanation!
667 * Pointers to the parameters are stored in hs->param_vals.
668 *
669 * @param hs http connection state
670 * @param params pointer to the NULL-terminated parameter string from the URI
671 * @return number of parameters extracted
672 */
673static int
674extract_uri_parameters(struct http_state *hs, char *params)
675{
676  char *pair;
677  char *equals;
678  int loop;
679
680  LWIP_UNUSED_ARG(hs);
681
682  /* If we have no parameters at all, return immediately. */
683  if(!params || (params[0] == '\0')) {
684      return(0);
685  }
686
687  /* Get a pointer to our first parameter */
688  pair = params;
689
690  /* Parse up to LWIP_HTTPD_MAX_CGI_PARAMETERS from the passed string and ignore the
691   * remainder (if any) */
692  for(loop = 0; (loop < LWIP_HTTPD_MAX_CGI_PARAMETERS) && pair; loop++) {
693
694    /* Save the name of the parameter */
695    http_cgi_params[loop] = pair;
696
697    /* Remember the start of this name=value pair */
698    equals = pair;
699
700    /* Find the start of the next name=value pair and replace the delimiter
701     * with a 0 to terminate the previous pair string. */
702    pair = strchr(pair, '&');
703    if(pair) {
704      *pair = '\0';
705      pair++;
706    } else {
707       /* We didn't find a new parameter so find the end of the URI and
708        * replace the space with a '\0' */
709        pair = strchr(equals, ' ');
710        if(pair) {
711            *pair = '\0';
712        }
713
714        /* Revert to NULL so that we exit the loop as expected. */
715        pair = NULL;
716    }
717
718    /* Now find the '=' in the previous pair, replace it with '\0' and save
719     * the parameter value string. */
720    equals = strchr(equals, '=');
721    if(equals) {
722      *equals = '\0';
723      http_cgi_param_vals[loop] = equals + 1;
724    } else {
725      http_cgi_param_vals[loop] = NULL;
726    }
727  }
728
729  return loop;
730}
731#endif /* LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI */
732
733#if LWIP_HTTPD_SSI
734/**
735 * Insert a tag (found in an shtml in the form of "<!--#tagname-->" into the file.
736 * The tag's name is stored in ssi->tag_name (NULL-terminated), the replacement
737 * should be written to hs->tag_insert (up to a length of LWIP_HTTPD_MAX_TAG_INSERT_LEN).
738 * The amount of data written is stored to ssi->tag_insert_len.
739 *
740 * @todo: return tag_insert_len - maybe it can be removed from struct http_state?
741 *
742 * @param hs http connection state
743 */
744static void
745get_tag_insert(struct http_state *hs)
746{
747#if LWIP_HTTPD_SSI_RAW
748  const char* tag;
749#else /* LWIP_HTTPD_SSI_RAW */
750  int tag;
751#endif /* LWIP_HTTPD_SSI_RAW */
752  size_t len;
753  struct http_ssi_state *ssi;
754#if LWIP_HTTPD_SSI_MULTIPART
755  u16_t current_tag_part;
756#endif /* LWIP_HTTPD_SSI_MULTIPART */
757
758  LWIP_ASSERT("hs != NULL", hs != NULL);
759  ssi = hs->ssi;
760  LWIP_ASSERT("ssi != NULL", ssi != NULL);
761#if LWIP_HTTPD_SSI_MULTIPART
762  current_tag_part = ssi->tag_part;
763  ssi->tag_part = HTTPD_LAST_TAG_PART;
764#endif /* LWIP_HTTPD_SSI_MULTIPART */
765#if LWIP_HTTPD_SSI_RAW
766  tag = ssi->tag_name;
767#endif
768
769  if(g_pfnSSIHandler
770#if !LWIP_HTTPD_SSI_RAW
771     && g_ppcTags && g_iNumTags
772#endif /* !LWIP_HTTPD_SSI_RAW */
773     ) {
774
775    /* Find this tag in the list we have been provided. */
776#if LWIP_HTTPD_SSI_RAW
777    {
778#else /* LWIP_HTTPD_SSI_RAW */
779    for(tag = 0; tag < g_iNumTags; tag++) {
780      if(strcmp(ssi->tag_name, g_ppcTags[tag]) == 0)
781#endif /* LWIP_HTTPD_SSI_RAW */
782      {
783        ssi->tag_insert_len = g_pfnSSIHandler(tag, ssi->tag_insert,
784           LWIP_HTTPD_MAX_TAG_INSERT_LEN
785#if LWIP_HTTPD_SSI_MULTIPART
786           , current_tag_part, &ssi->tag_part
787#endif /* LWIP_HTTPD_SSI_MULTIPART */
788#if LWIP_HTTPD_FILE_STATE
789           , (hs->handle ? hs->handle->state : NULL)
790#endif /* LWIP_HTTPD_FILE_STATE */
791           );
792#if LWIP_HTTPD_SSI_RAW
793        if (ssi->tag_insert_len != HTTPD_SSI_TAG_UNKNOWN)
794#endif /* LWIP_HTTPD_SSI_RAW */
795        {
796          return;
797        }
798      }
799    }
800  }
801
802  /* If we drop out, we were asked to serve a page which contains tags that
803   * we don't have a handler for. Merely echo back the tags with an error
804   * marker. */
805#define UNKNOWN_TAG1_TEXT "<b>***UNKNOWN TAG "
806#define UNKNOWN_TAG1_LEN  18
807#define UNKNOWN_TAG2_TEXT "***</b>"
808#define UNKNOWN_TAG2_LEN  7
809  len = LWIP_MIN(sizeof(ssi->tag_name), LWIP_MIN(strlen(ssi->tag_name),
810    LWIP_HTTPD_MAX_TAG_INSERT_LEN - (UNKNOWN_TAG1_LEN + UNKNOWN_TAG2_LEN)));
811  MEMCPY(ssi->tag_insert, UNKNOWN_TAG1_TEXT, UNKNOWN_TAG1_LEN);
812  MEMCPY(&ssi->tag_insert[UNKNOWN_TAG1_LEN], ssi->tag_name, len);
813  MEMCPY(&ssi->tag_insert[UNKNOWN_TAG1_LEN + len], UNKNOWN_TAG2_TEXT, UNKNOWN_TAG2_LEN);
814  ssi->tag_insert[UNKNOWN_TAG1_LEN + len + UNKNOWN_TAG2_LEN] = 0;
815
816  len = strlen(ssi->tag_insert);
817  LWIP_ASSERT("len <= 0xffff", len <= 0xffff);
818  ssi->tag_insert_len = (u16_t)len;
819}
820#endif /* LWIP_HTTPD_SSI */
821
822#if LWIP_HTTPD_DYNAMIC_HEADERS
823/**
824 * Generate the relevant HTTP headers for the given filename and write
825 * them into the supplied buffer.
826 */
827static void
828get_http_headers(struct http_state *hs, const char *uri)
829{
830  size_t content_type;
831  char *tmp;
832  char *ext;
833  char *vars;
834  u8_t add_content_len;
835
836  /* In all cases, the second header we send is the server identification
837     so set it here. */
838  hs->hdrs[HDR_STRINGS_IDX_SERVER_NAME] = g_psHTTPHeaderStrings[HTTP_HDR_SERVER];
839  hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE] = NULL;
840  hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_NR] = NULL;
841
842  /* Is this a normal file or the special case we use to send back the
843     default "404: Page not found" response? */
844  if (uri == NULL) {
845    hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND];
846#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
847    if (hs->keepalive) {
848      hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = g_psHTTPHeaderStrings[DEFAULT_404_HTML_PERSISTENT];
849    } else
850#endif
851    {
852      hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = g_psHTTPHeaderStrings[DEFAULT_404_HTML];
853    }
854
855    /* Set up to send the first header string. */
856    hs->hdr_index = 0;
857    hs->hdr_pos = 0;
858    return;
859  }
860  /* We are dealing with a particular filename. Look for one other
861      special case.  We assume that any filename with "404" in it must be
862      indicative of a 404 server error whereas all other files require
863      the 200 OK header. */
864  if (strstr(uri, "404")) {
865    hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND];
866  } else if (strstr(uri, "400")) {
867    hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_BAD_REQUEST];
868  } else if (strstr(uri, "501")) {
869    hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_IMPL];
870  } else {
871    hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_OK];
872  }
873
874  /* Determine if the URI has any variables and, if so, temporarily remove
875      them. */
876  vars = strchr(uri, '?');
877  if(vars) {
878    *vars = '\0';
879  }
880
881  /* Get a pointer to the file extension.  We find this by looking for the
882      last occurrence of "." in the filename passed. */
883  ext = NULL;
884  tmp = strchr(uri, '.');
885  while (tmp) {
886    ext = tmp + 1;
887    tmp = strchr(ext, '.');
888  }
889  if (ext != NULL) {
890    /* Now determine the content type and add the relevant header for that. */
891    for (content_type = 0; content_type < NUM_HTTP_HEADERS; content_type++) {
892      /* Have we found a matching extension? */
893      if(!lwip_stricmp(g_psHTTPHeaders[content_type].extension, ext)) {
894        break;
895      }
896    }
897  } else {
898    content_type = NUM_HTTP_HEADERS;
899  }
900
901  /* Reinstate the parameter marker if there was one in the original URI. */
902  if (vars) {
903    *vars = '?';
904  }
905
906#if LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI
907  /* Does the URL passed have any file extension?  If not, we assume it
908     is a special-case URL used for control state notification and we do
909     not send any HTTP headers with the response. */
910  if (!ext) {
911    /* Force the header index to a value indicating that all headers
912       have already been sent. */
913    hs->hdr_index = NUM_FILE_HDR_STRINGS;
914    return;
915  }
916#endif /* LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI */
917  add_content_len = 1;
918  /* Did we find a matching extension? */
919  if(content_type < NUM_HTTP_HEADERS) {
920    /* yes, store it */
921    hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = g_psHTTPHeaders[content_type].content_type;
922  } else if (!ext) {
923    /* no, no extension found -> use binary transfer to prevent the browser adding '.txt' on save */
924    hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = HTTP_HDR_APP;
925  } else {
926    /* No - use the default, plain text file type. */
927    hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = HTTP_HDR_DEFAULT_TYPE;
928  }
929  /* Add content-length header? */
930#if LWIP_HTTPD_SSI
931  if (hs->ssi != NULL) {
932    add_content_len = 0; /* @todo: get maximum file length from SSI */
933  } else
934#endif /* LWIP_HTTPD_SSI */
935  if ((hs->handle == NULL) ||
936      ((hs->handle->flags & (FS_FILE_FLAGS_HEADER_INCLUDED|FS_FILE_FLAGS_HEADER_PERSISTENT)) == FS_FILE_FLAGS_HEADER_INCLUDED)) {
937    add_content_len = 0;
938  }
939  if (add_content_len) {
940    size_t len;
941    lwip_itoa(hs->hdr_content_len, (size_t)LWIP_HTTPD_MAX_CONTENT_LEN_SIZE,
942      hs->handle->len);
943    len = strlen(hs->hdr_content_len);
944    if (len <= LWIP_HTTPD_MAX_CONTENT_LEN_SIZE - LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET) {
945      SMEMCPY(&hs->hdr_content_len[len], CRLF "\0", 3);
946      hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_NR] = hs->hdr_content_len;
947    } else {
948      add_content_len = 0;
949    }
950  }
951#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
952  if (add_content_len) {
953    hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE] = g_psHTTPHeaderStrings[HTTP_HDR_KEEPALIVE_LEN];
954  } else {
955    hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE] = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE];
956  }
957#else /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
958  if (add_content_len) {
959    hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEPALIVE] = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH];
960  }
961#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
962
963  /* Set up to send the first header string. */
964  hs->hdr_index = 0;
965  hs->hdr_pos = 0;
966}
967
968/** Sub-function of http_send(): send dynamic headers
969 *
970 * @returns: - HTTP_NO_DATA_TO_SEND: no new data has been enqueued
971 *           - HTTP_DATA_TO_SEND_CONTINUE: continue with sending HTTP body
972 *           - HTTP_DATA_TO_SEND_BREAK: data has been enqueued, headers pending,
973 *                                      so don't send HTTP body yet
974 */
975static u8_t
976http_send_headers(struct tcp_pcb *pcb, struct http_state *hs)
977{
978  err_t err;
979  u16_t len;
980  u8_t data_to_send = HTTP_NO_DATA_TO_SEND;
981  u16_t hdrlen, sendlen;
982
983  /* How much data can we send? */
984  len = tcp_sndbuf(pcb);
985  sendlen = len;
986
987  while(len && (hs->hdr_index < NUM_FILE_HDR_STRINGS) && sendlen) {
988    const void *ptr;
989    u16_t old_sendlen;
990    u8_t apiflags;
991    /* How much do we have to send from the current header? */
992    hdrlen = (u16_t)strlen(hs->hdrs[hs->hdr_index]);
993
994    /* How much of this can we send? */
995    sendlen = (len < (hdrlen - hs->hdr_pos)) ? len : (hdrlen - hs->hdr_pos);
996
997    /* Send this amount of data or as much as we can given memory
998     * constraints. */
999    ptr = (const void *)(hs->hdrs[hs->hdr_index] + hs->hdr_pos);
1000    old_sendlen = sendlen;
1001    apiflags = HTTP_IS_HDR_VOLATILE(hs, ptr);
1002    if (hs->hdr_index == HDR_STRINGS_IDX_CONTENT_LEN_NR) {
1003      /* content-length is always volatile */
1004      apiflags |= TCP_WRITE_FLAG_COPY;
1005    }
1006    if (hs->hdr_index < NUM_FILE_HDR_STRINGS - 1) {
1007      apiflags |= TCP_WRITE_FLAG_MORE;
1008    }
1009    err = http_write(pcb, ptr, &sendlen, apiflags);
1010    if ((err == ERR_OK) && (old_sendlen != sendlen)) {
1011      /* Remember that we added some more data to be transmitted. */
1012      data_to_send = HTTP_DATA_TO_SEND_CONTINUE;
1013    } else if (err != ERR_OK) {
1014       /* special case: http_write does not try to send 1 byte */
1015      sendlen = 0;
1016    }
1017
1018    /* Fix up the header position for the next time round. */
1019    hs->hdr_pos += sendlen;
1020    len -= sendlen;
1021
1022    /* Have we finished sending this string? */
1023    if(hs->hdr_pos == hdrlen) {
1024      /* Yes - move on to the next one */
1025      hs->hdr_index++;
1026      /* skip headers that are NULL (not all headers are required) */
1027      while ((hs->hdr_index < NUM_FILE_HDR_STRINGS) &&
1028         (hs->hdrs[hs->hdr_index] == NULL)) {
1029        hs->hdr_index++;
1030      }
1031      hs->hdr_pos = 0;
1032    }
1033  }
1034
1035  if ((hs->hdr_index >= NUM_FILE_HDR_STRINGS) && (hs->file == NULL)) {
1036    /* When we are at the end of the headers, check for data to send
1037     * instead of waiting for ACK from remote side to continue
1038     * (which would happen when sending files from async read). */
1039    if(http_check_eof(pcb, hs)) {
1040      data_to_send = HTTP_DATA_TO_SEND_CONTINUE;
1041    }
1042  }
1043  /* If we get here and there are still header bytes to send, we send
1044   * the header information we just wrote immediately. If there are no
1045   * more headers to send, but we do have file data to send, drop through
1046   * to try to send some file data too. */
1047  if((hs->hdr_index < NUM_FILE_HDR_STRINGS) || !hs->file) {
1048    LWIP_DEBUGF(HTTPD_DEBUG, ("tcp_output\n"));
1049    return HTTP_DATA_TO_SEND_BREAK;
1050  }
1051  return data_to_send;
1052}
1053#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
1054
1055/** Sub-function of http_send(): end-of-file (or block) is reached,
1056 * either close the file or read the next block (if supported).
1057 *
1058 * @returns: 0 if the file is finished or no data has been read
1059 *           1 if the file is not finished and data has been read
1060 */
1061static u8_t
1062http_check_eof(struct tcp_pcb *pcb, struct http_state *hs)
1063{
1064  int bytes_left;
1065#if LWIP_HTTPD_DYNAMIC_FILE_READ
1066  int count;
1067#ifdef HTTPD_MAX_WRITE_LEN
1068  int max_write_len;
1069#endif /* HTTPD_MAX_WRITE_LEN */
1070#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
1071
1072  /* Do we have a valid file handle? */
1073  if (hs->handle == NULL) {
1074    /* No - close the connection. */
1075    http_eof(pcb, hs);
1076    return 0;
1077  }
1078  bytes_left = fs_bytes_left(hs->handle);
1079  if (bytes_left <= 0) {
1080    /* We reached the end of the file so this request is done. */
1081    LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
1082    http_eof(pcb, hs);
1083    return 0;
1084  }
1085#if LWIP_HTTPD_DYNAMIC_FILE_READ
1086  /* Do we already have a send buffer allocated? */
1087  if(hs->buf) {
1088    /* Yes - get the length of the buffer */
1089    count = LWIP_MIN(hs->buf_len, bytes_left);
1090  } else {
1091    /* We don't have a send buffer so allocate one now */
1092    count = tcp_sndbuf(pcb);
1093    if(bytes_left < count) {
1094      count = bytes_left;
1095    }
1096#ifdef HTTPD_MAX_WRITE_LEN
1097    /* Additional limitation: e.g. don't enqueue more than 2*mss at once */
1098    max_write_len = HTTPD_MAX_WRITE_LEN(pcb);
1099    if (count > max_write_len) {
1100      count = max_write_len;
1101    }
1102#endif /* HTTPD_MAX_WRITE_LEN */
1103    do {
1104      hs->buf = (char*)mem_malloc((mem_size_t)count);
1105      if (hs->buf != NULL) {
1106        hs->buf_len = count;
1107        break;
1108      }
1109      count = count / 2;
1110    } while (count > 100);
1111
1112    /* Did we get a send buffer? If not, return immediately. */
1113    if (hs->buf == NULL) {
1114      LWIP_DEBUGF(HTTPD_DEBUG, ("No buff\n"));
1115      return 0;
1116    }
1117  }
1118
1119  /* Read a block of data from the file. */
1120  LWIP_DEBUGF(HTTPD_DEBUG, ("Trying to read %d bytes.\n", count));
1121
1122#if LWIP_HTTPD_FS_ASYNC_READ
1123  count = fs_read_async(hs->handle, hs->buf, count, http_continue, hs);
1124#else /* LWIP_HTTPD_FS_ASYNC_READ */
1125  count = fs_read(hs->handle, hs->buf, count);
1126#endif /* LWIP_HTTPD_FS_ASYNC_READ */
1127  if (count < 0) {
1128    if (count == FS_READ_DELAYED) {
1129      /* Delayed read, wait for FS to unblock us */
1130      return 0;
1131    }
1132    /* We reached the end of the file so this request is done.
1133     * @todo: close here for HTTP/1.1 when reading file fails */
1134    LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
1135    http_eof(pcb, hs);
1136    return 0;
1137  }
1138
1139  /* Set up to send the block of data we just read */
1140  LWIP_DEBUGF(HTTPD_DEBUG, ("Read %d bytes.\n", count));
1141  hs->left = count;
1142  hs->file = hs->buf;
1143#if LWIP_HTTPD_SSI
1144  if (hs->ssi) {
1145    hs->ssi->parse_left = count;
1146    hs->ssi->parsed = hs->buf;
1147  }
1148#endif /* LWIP_HTTPD_SSI */
1149#else /* LWIP_HTTPD_DYNAMIC_FILE_READ */
1150  LWIP_ASSERT("SSI and DYNAMIC_HEADERS turned off but eof not reached", 0);
1151#endif /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */
1152  return 1;
1153}
1154
1155/** Sub-function of http_send(): This is the normal send-routine for non-ssi files
1156 *
1157 * @returns: - 1: data has been written (so call tcp_ouput)
1158 *           - 0: no data has been written (no need to call tcp_output)
1159 */
1160static u8_t
1161http_send_data_nonssi(struct tcp_pcb *pcb, struct http_state *hs)
1162{
1163  err_t err;
1164  u16_t len;
1165  u8_t data_to_send = 0;
1166
1167  /* We are not processing an SHTML file so no tag checking is necessary.
1168   * Just send the data as we received it from the file. */
1169  len = (u16_t)LWIP_MIN(hs->left, 0xffff);
1170
1171  err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1172  if (err == ERR_OK) {
1173    data_to_send = 1;
1174    hs->file += len;
1175    hs->left -= len;
1176  }
1177
1178  return data_to_send;
1179}
1180
1181#if LWIP_HTTPD_SSI
1182/** Sub-function of http_send(): This is the send-routine for ssi files
1183 *
1184 * @returns: - 1: data has been written (so call tcp_ouput)
1185 *           - 0: no data has been written (no need to call tcp_output)
1186 */
1187static u8_t
1188http_send_data_ssi(struct tcp_pcb *pcb, struct http_state *hs)
1189{
1190  err_t err = ERR_OK;
1191  u16_t len;
1192  u8_t data_to_send = 0;
1193
1194  struct http_ssi_state *ssi = hs->ssi;
1195  LWIP_ASSERT("ssi != NULL", ssi != NULL);
1196  /* We are processing an SHTML file so need to scan for tags and replace
1197   * them with insert strings. We need to be careful here since a tag may
1198   * straddle the boundary of two blocks read from the file and we may also
1199   * have to split the insert string between two tcp_write operations. */
1200
1201  /* How much data could we send? */
1202  len = tcp_sndbuf(pcb);
1203
1204  /* Do we have remaining data to send before parsing more? */
1205  if(ssi->parsed > hs->file) {
1206    len = (u16_t)LWIP_MIN(ssi->parsed - hs->file, 0xffff);
1207
1208    err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1209    if (err == ERR_OK) {
1210      data_to_send = 1;
1211      hs->file += len;
1212      hs->left -= len;
1213    }
1214
1215    /* If the send buffer is full, return now. */
1216    if(tcp_sndbuf(pcb) == 0) {
1217      return data_to_send;
1218    }
1219  }
1220
1221  LWIP_DEBUGF(HTTPD_DEBUG, ("State %d, %d left\n", ssi->tag_state, (int)ssi->parse_left));
1222
1223  /* We have sent all the data that was already parsed so continue parsing
1224   * the buffer contents looking for SSI tags. */
1225  while((ssi->parse_left) && (err == ERR_OK)) {
1226    if (len == 0) {
1227      return data_to_send;
1228    }
1229    switch(ssi->tag_state) {
1230      case TAG_NONE:
1231        /* We are not currently processing an SSI tag so scan for the
1232         * start of the lead-in marker. */
1233        if(*ssi->parsed == g_pcTagLeadIn[0]) {
1234          /* We found what could be the lead-in for a new tag so change
1235           * state appropriately. */
1236          ssi->tag_state = TAG_LEADIN;
1237          ssi->tag_index = 1;
1238#if !LWIP_HTTPD_SSI_INCLUDE_TAG
1239          ssi->tag_started = ssi->parsed;
1240#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */
1241        }
1242
1243        /* Move on to the next character in the buffer */
1244        ssi->parse_left--;
1245        ssi->parsed++;
1246        break;
1247
1248      case TAG_LEADIN:
1249        /* We are processing the lead-in marker, looking for the start of
1250         * the tag name. */
1251
1252        /* Have we reached the end of the leadin? */
1253        if(ssi->tag_index == LEN_TAG_LEAD_IN) {
1254          ssi->tag_index = 0;
1255          ssi->tag_state = TAG_FOUND;
1256        } else {
1257          /* Have we found the next character we expect for the tag leadin? */
1258          if(*ssi->parsed == g_pcTagLeadIn[ssi->tag_index]) {
1259            /* Yes - move to the next one unless we have found the complete
1260             * leadin, in which case we start looking for the tag itself */
1261            ssi->tag_index++;
1262          } else {
1263            /* We found an unexpected character so this is not a tag. Move
1264             * back to idle state. */
1265            ssi->tag_state = TAG_NONE;
1266          }
1267
1268          /* Move on to the next character in the buffer */
1269          ssi->parse_left--;
1270          ssi->parsed++;
1271        }
1272        break;
1273
1274      case TAG_FOUND:
1275        /* We are reading the tag name, looking for the start of the
1276         * lead-out marker and removing any whitespace found. */
1277
1278        /* Remove leading whitespace between the tag leading and the first
1279         * tag name character. */
1280        if((ssi->tag_index == 0) && ((*ssi->parsed == ' ') ||
1281           (*ssi->parsed == '\t') || (*ssi->parsed == '\n') ||
1282           (*ssi->parsed == '\r'))) {
1283          /* Move on to the next character in the buffer */
1284          ssi->parse_left--;
1285          ssi->parsed++;
1286          break;
1287        }
1288
1289        /* Have we found the end of the tag name? This is signalled by
1290         * us finding the first leadout character or whitespace */
1291        if((*ssi->parsed == g_pcTagLeadOut[0]) ||
1292           (*ssi->parsed == ' ')  || (*ssi->parsed == '\t') ||
1293           (*ssi->parsed == '\n') || (*ssi->parsed == '\r')) {
1294
1295          if(ssi->tag_index == 0) {
1296            /* We read a zero length tag so ignore it. */
1297            ssi->tag_state = TAG_NONE;
1298          } else {
1299            /* We read a non-empty tag so go ahead and look for the
1300             * leadout string. */
1301            ssi->tag_state = TAG_LEADOUT;
1302            LWIP_ASSERT("ssi->tag_index <= 0xff", ssi->tag_index <= 0xff);
1303            ssi->tag_name_len = (u8_t)ssi->tag_index;
1304            ssi->tag_name[ssi->tag_index] = '\0';
1305            if(*ssi->parsed == g_pcTagLeadOut[0]) {
1306              ssi->tag_index = 1;
1307            } else {
1308              ssi->tag_index = 0;
1309            }
1310          }
1311        } else {
1312          /* This character is part of the tag name so save it */
1313          if(ssi->tag_index < LWIP_HTTPD_MAX_TAG_NAME_LEN) {
1314            ssi->tag_name[ssi->tag_index++] = *ssi->parsed;
1315          } else {
1316            /* The tag was too long so ignore it. */
1317            ssi->tag_state = TAG_NONE;
1318          }
1319        }
1320
1321        /* Move on to the next character in the buffer */
1322        ssi->parse_left--;
1323        ssi->parsed++;
1324
1325        break;
1326
1327      /* We are looking for the end of the lead-out marker. */
1328      case TAG_LEADOUT:
1329        /* Remove leading whitespace between the tag leading and the first
1330         * tag leadout character. */
1331        if((ssi->tag_index == 0) && ((*ssi->parsed == ' ') ||
1332           (*ssi->parsed == '\t') || (*ssi->parsed == '\n') ||
1333           (*ssi->parsed == '\r'))) {
1334          /* Move on to the next character in the buffer */
1335          ssi->parse_left--;
1336          ssi->parsed++;
1337          break;
1338        }
1339
1340        /* Have we found the next character we expect for the tag leadout? */
1341        if(*ssi->parsed == g_pcTagLeadOut[ssi->tag_index]) {
1342          /* Yes - move to the next one unless we have found the complete
1343           * leadout, in which case we need to call the client to process
1344           * the tag. */
1345
1346          /* Move on to the next character in the buffer */
1347          ssi->parse_left--;
1348          ssi->parsed++;
1349
1350          if(ssi->tag_index == (LEN_TAG_LEAD_OUT - 1)) {
1351            /* Call the client to ask for the insert string for the
1352             * tag we just found. */
1353#if LWIP_HTTPD_SSI_MULTIPART
1354            ssi->tag_part = 0; /* start with tag part 0 */
1355#endif /* LWIP_HTTPD_SSI_MULTIPART */
1356            get_tag_insert(hs);
1357
1358            /* Next time through, we are going to be sending data
1359             * immediately, either the end of the block we start
1360             * sending here or the insert string. */
1361            ssi->tag_index = 0;
1362            ssi->tag_state = TAG_SENDING;
1363            ssi->tag_end = ssi->parsed;
1364#if !LWIP_HTTPD_SSI_INCLUDE_TAG
1365            ssi->parsed = ssi->tag_started;
1366#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
1367
1368            /* If there is any unsent data in the buffer prior to the
1369             * tag, we need to send it now. */
1370            if (ssi->tag_end > hs->file) {
1371              /* How much of the data can we send? */
1372#if LWIP_HTTPD_SSI_INCLUDE_TAG
1373              len = (u16_t)LWIP_MIN(ssi->tag_end - hs->file, 0xffff);
1374#else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
1375              /* we would include the tag in sending */
1376              len = (u16_t)LWIP_MIN(ssi->tag_started - hs->file, 0xffff);
1377#endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
1378
1379              err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1380              if (err == ERR_OK) {
1381                data_to_send = 1;
1382#if !LWIP_HTTPD_SSI_INCLUDE_TAG
1383                if(ssi->tag_started <= hs->file) {
1384                  /* pretend to have sent the tag, too */
1385                  len += ssi->tag_end - ssi->tag_started;
1386                }
1387#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
1388                hs->file += len;
1389                hs->left -= len;
1390              }
1391            }
1392          } else {
1393            ssi->tag_index++;
1394          }
1395        } else {
1396          /* We found an unexpected character so this is not a tag. Move
1397           * back to idle state. */
1398          ssi->parse_left--;
1399          ssi->parsed++;
1400          ssi->tag_state = TAG_NONE;
1401        }
1402        break;
1403
1404      /*
1405       * We have found a valid tag and are in the process of sending
1406       * data as a result of that discovery. We send either remaining data
1407       * from the file prior to the insert point or the insert string itself.
1408       */
1409      case TAG_SENDING:
1410        /* Do we have any remaining file data to send from the buffer prior
1411         * to the tag? */
1412        if(ssi->tag_end > hs->file) {
1413          /* How much of the data can we send? */
1414#if LWIP_HTTPD_SSI_INCLUDE_TAG
1415          len = (u16_t)LWIP_MIN(ssi->tag_end - hs->file, 0xffff);
1416#else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
1417          LWIP_ASSERT("hs->started >= hs->file", ssi->tag_started >= hs->file);
1418          /* we would include the tag in sending */
1419          len = (u16_t)LWIP_MIN(ssi->tag_started - hs->file, 0xffff);
1420#endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
1421          if (len != 0) {
1422            err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1423          } else {
1424            err = ERR_OK;
1425          }
1426          if (err == ERR_OK) {
1427            data_to_send = 1;
1428#if !LWIP_HTTPD_SSI_INCLUDE_TAG
1429            if(ssi->tag_started <= hs->file) {
1430              /* pretend to have sent the tag, too */
1431              len += ssi->tag_end - ssi->tag_started;
1432            }
1433#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
1434            hs->file += len;
1435            hs->left -= len;
1436          }
1437        } else {
1438#if LWIP_HTTPD_SSI_MULTIPART
1439          if(ssi->tag_index >= ssi->tag_insert_len) {
1440            /* Did the last SSIHandler have more to send? */
1441            if (ssi->tag_part != HTTPD_LAST_TAG_PART) {
1442              /* If so, call it again */
1443              ssi->tag_index = 0;
1444              get_tag_insert(hs);
1445            }
1446          }
1447#endif /* LWIP_HTTPD_SSI_MULTIPART */
1448
1449          /* Do we still have insert data left to send? */
1450          if(ssi->tag_index < ssi->tag_insert_len) {
1451            /* We are sending the insert string itself. How much of the
1452             * insert can we send? */
1453            len = (ssi->tag_insert_len - ssi->tag_index);
1454
1455            /* Note that we set the copy flag here since we only have a
1456             * single tag insert buffer per connection. If we don't do
1457             * this, insert corruption can occur if more than one insert
1458             * is processed before we call tcp_output. */
1459            err = http_write(pcb, &(ssi->tag_insert[ssi->tag_index]), &len,
1460                             HTTP_IS_TAG_VOLATILE(hs));
1461            if (err == ERR_OK) {
1462              data_to_send = 1;
1463              ssi->tag_index += len;
1464              /* Don't return here: keep on sending data */
1465            }
1466          } else {
1467#if LWIP_HTTPD_SSI_MULTIPART
1468            if (ssi->tag_part == HTTPD_LAST_TAG_PART)
1469#endif /* LWIP_HTTPD_SSI_MULTIPART */
1470            {
1471              /* We have sent all the insert data so go back to looking for
1472               * a new tag. */
1473              LWIP_DEBUGF(HTTPD_DEBUG, ("Everything sent.\n"));
1474              ssi->tag_index = 0;
1475              ssi->tag_state = TAG_NONE;
1476#if !LWIP_HTTPD_SSI_INCLUDE_TAG
1477              ssi->parsed = ssi->tag_end;
1478#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
1479            }
1480          }
1481          break;
1482        default:
1483          break;
1484      }
1485    }
1486  }
1487
1488  /* If we drop out of the end of the for loop, this implies we must have
1489   * file data to send so send it now. In TAG_SENDING state, we've already
1490   * handled this so skip the send if that's the case. */
1491  if((ssi->tag_state != TAG_SENDING) && (ssi->parsed > hs->file)) {
1492    len = (u16_t)LWIP_MIN(ssi->parsed - hs->file, 0xffff);
1493
1494    err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1495    if (err == ERR_OK) {
1496      data_to_send = 1;
1497      hs->file += len;
1498      hs->left -= len;
1499    }
1500  }
1501  return data_to_send;
1502}
1503#endif /* LWIP_HTTPD_SSI */
1504
1505/**
1506 * Try to send more data on this pcb.
1507 *
1508 * @param pcb the pcb to send data
1509 * @param hs connection state
1510 */
1511static u8_t
1512http_send(struct tcp_pcb *pcb, struct http_state *hs)
1513{
1514  u8_t data_to_send = HTTP_NO_DATA_TO_SEND;
1515
1516  LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_send: pcb=%p hs=%p left=%d\n", (void*)pcb,
1517    (void*)hs, hs != NULL ? (int)hs->left : 0));
1518
1519#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
1520  if (hs->unrecved_bytes != 0) {
1521    return 0;
1522  }
1523#endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
1524
1525  /* If we were passed a NULL state structure pointer, ignore the call. */
1526  if (hs == NULL) {
1527    return 0;
1528  }
1529
1530#if LWIP_HTTPD_FS_ASYNC_READ
1531  /* Check if we are allowed to read from this file.
1532     (e.g. SSI might want to delay sending until data is available) */
1533  if (!fs_is_file_ready(hs->handle, http_continue, hs)) {
1534    return 0;
1535  }
1536#endif /* LWIP_HTTPD_FS_ASYNC_READ */
1537
1538#if LWIP_HTTPD_DYNAMIC_HEADERS
1539  /* Do we have any more header data to send for this file? */
1540  if (hs->hdr_index < NUM_FILE_HDR_STRINGS) {
1541    data_to_send = http_send_headers(pcb, hs);
1542    if ((data_to_send != HTTP_DATA_TO_SEND_CONTINUE) &&
1543        (hs->hdr_index < NUM_FILE_HDR_STRINGS)) {
1544      return data_to_send;
1545    }
1546  }
1547#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
1548
1549  /* Have we run out of file data to send? If so, we need to read the next
1550   * block from the file. */
1551  if (hs->left == 0) {
1552    if (!http_check_eof(pcb, hs)) {
1553      return 0;
1554    }
1555  }
1556
1557#if LWIP_HTTPD_SSI
1558  if(hs->ssi) {
1559    data_to_send = http_send_data_ssi(pcb, hs);
1560  } else
1561#endif /* LWIP_HTTPD_SSI */
1562  {
1563    data_to_send = http_send_data_nonssi(pcb, hs);
1564  }
1565
1566  if((hs->left == 0) && (fs_bytes_left(hs->handle) <= 0)) {
1567    /* We reached the end of the file so this request is done.
1568     * This adds the FIN flag right into the last data segment. */
1569    LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
1570    http_eof(pcb, hs);
1571    return 0;
1572  }
1573  LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("send_data end.\n"));
1574  return data_to_send;
1575}
1576
1577#if LWIP_HTTPD_SUPPORT_EXTSTATUS
1578/** Initialize a http connection with a file to send for an error message
1579 *
1580 * @param hs http connection state
1581 * @param error_nr HTTP error number
1582 * @return ERR_OK if file was found and hs has been initialized correctly
1583 *         another err_t otherwise
1584 */
1585static err_t
1586http_find_error_file(struct http_state *hs, u16_t error_nr)
1587{
1588  const char *uri1, *uri2, *uri3;
1589  err_t err;
1590
1591  if (error_nr == 501) {
1592    uri1 = "/501.html";
1593    uri2 = "/501.htm";
1594    uri3 = "/501.shtml";
1595  } else {
1596    /* 400 (bad request is the default) */
1597    uri1 = "/400.html";
1598    uri2 = "/400.htm";
1599    uri3 = "/400.shtml";
1600  }
1601  err = fs_open(&hs->file_handle, uri1);
1602  if (err != ERR_OK) {
1603    err = fs_open(&hs->file_handle, uri2);
1604    if (err != ERR_OK) {
1605      err = fs_open(&hs->file_handle, uri3);
1606      if (err != ERR_OK) {
1607        LWIP_DEBUGF(HTTPD_DEBUG, ("Error page for error %"U16_F" not found\n",
1608          error_nr));
1609        return ERR_ARG;
1610      }
1611    }
1612  }
1613  return http_init_file(hs, &hs->file_handle, 0, NULL, 0, NULL);
1614}
1615#else /* LWIP_HTTPD_SUPPORT_EXTSTATUS */
1616#define http_find_error_file(hs, error_nr) ERR_ARG
1617#endif /* LWIP_HTTPD_SUPPORT_EXTSTATUS */
1618
1619/**
1620 * Get the file struct for a 404 error page.
1621 * Tries some file names and returns NULL if none found.
1622 *
1623 * @param uri pointer that receives the actual file name URI
1624 * @return file struct for the error page or NULL no matching file was found
1625 */
1626static struct fs_file *
1627http_get_404_file(struct http_state *hs, const char **uri)
1628{
1629  err_t err;
1630
1631  *uri = "/404.html";
1632  err = fs_open(&hs->file_handle, *uri);
1633  if (err != ERR_OK) {
1634    /* 404.html doesn't exist. Try 404.htm instead. */
1635    *uri = "/404.htm";
1636    err = fs_open(&hs->file_handle, *uri);
1637    if (err != ERR_OK) {
1638      /* 404.htm doesn't exist either. Try 404.shtml instead. */
1639      *uri = "/404.shtml";
1640      err = fs_open(&hs->file_handle, *uri);
1641      if (err != ERR_OK) {
1642        /* 404.htm doesn't exist either. Indicate to the caller that it should
1643         * send back a default 404 page.
1644         */
1645        *uri = NULL;
1646        return NULL;
1647      }
1648    }
1649  }
1650
1651  return &hs->file_handle;
1652}
1653
1654#if LWIP_HTTPD_SUPPORT_POST
1655static err_t
1656http_handle_post_finished(struct http_state *hs)
1657{
1658#if LWIP_HTTPD_POST_MANUAL_WND
1659  /* Prevent multiple calls to httpd_post_finished, since it might have already
1660     been called before from httpd_post_data_recved(). */
1661  if (hs->post_finished) {
1662    return ERR_OK;
1663  }
1664  hs->post_finished = 1;
1665#endif /* LWIP_HTTPD_POST_MANUAL_WND */
1666  /* application error or POST finished */
1667  /* NULL-terminate the buffer */
1668  http_uri_buf[0] = 0;
1669  httpd_post_finished(hs, http_uri_buf, LWIP_HTTPD_URI_BUF_LEN);
1670  return http_find_file(hs, http_uri_buf, 0);
1671}
1672
1673/** Pass received POST body data to the application and correctly handle
1674 * returning a response document or closing the connection.
1675 * ATTENTION: The application is responsible for the pbuf now, so don't free it!
1676 *
1677 * @param hs http connection state
1678 * @param p pbuf to pass to the application
1679 * @return ERR_OK if passed successfully, another err_t if the response file
1680 *         hasn't been found (after POST finished)
1681 */
1682static err_t
1683http_post_rxpbuf(struct http_state *hs, struct pbuf *p)
1684{
1685  err_t err;
1686
1687  if (p != NULL) {
1688    /* adjust remaining Content-Length */
1689    if (hs->post_content_len_left < p->tot_len) {
1690      hs->post_content_len_left = 0;
1691    } else {
1692      hs->post_content_len_left -= p->tot_len;
1693    }
1694  }
1695#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
1696  /* prevent connection being closed if httpd_post_data_recved() is called nested */
1697  hs->unrecved_bytes++;
1698#endif
1699  err = httpd_post_receive_data(hs, p);
1700#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
1701  hs->unrecved_bytes--;
1702#endif
1703  if (err != ERR_OK) {
1704    /* Ignore remaining content in case of application error */
1705    hs->post_content_len_left = 0;
1706  }
1707  if (hs->post_content_len_left == 0) {
1708#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
1709    if (hs->unrecved_bytes != 0) {
1710       return ERR_OK;
1711    }
1712#endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
1713    /* application error or POST finished */
1714    return http_handle_post_finished(hs);
1715  }
1716
1717  return ERR_OK;
1718}
1719
1720/** Handle a post request. Called from http_parse_request when method 'POST'
1721 * is found.
1722 *
1723 * @param p The input pbuf (containing the POST header and body).
1724 * @param hs The http connection state.
1725 * @param data HTTP request (header and part of body) from input pbuf(s).
1726 * @param data_len Size of 'data'.
1727 * @param uri The HTTP URI parsed from input pbuf(s).
1728 * @param uri_end Pointer to the end of 'uri' (here, the rest of the HTTP
1729 *                header starts).
1730 * @return ERR_OK: POST correctly parsed and accepted by the application.
1731 *         ERR_INPROGRESS: POST not completely parsed (no error yet)
1732 *         another err_t: Error parsing POST or denied by the application
1733 */
1734static err_t
1735http_post_request(struct pbuf *inp, struct http_state *hs,
1736                  char *data, u16_t data_len, char *uri, char *uri_end)
1737{
1738  err_t err;
1739  /* search for end-of-header (first double-CRLF) */
1740  char* crlfcrlf = lwip_strnstr(uri_end + 1, CRLF CRLF, data_len - (uri_end + 1 - data));
1741
1742  if (crlfcrlf != NULL) {
1743    /* search for "Content-Length: " */
1744#define HTTP_HDR_CONTENT_LEN                "Content-Length: "
1745#define HTTP_HDR_CONTENT_LEN_LEN            16
1746#define HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN  10
1747    char *scontent_len = lwip_strnstr(uri_end + 1, HTTP_HDR_CONTENT_LEN, crlfcrlf - (uri_end + 1));
1748    if (scontent_len != NULL) {
1749      char *scontent_len_end = lwip_strnstr(scontent_len + HTTP_HDR_CONTENT_LEN_LEN, CRLF, HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN);
1750      if (scontent_len_end != NULL) {
1751        int content_len;
1752        char *content_len_num = scontent_len + HTTP_HDR_CONTENT_LEN_LEN;
1753        content_len = atoi(content_len_num);
1754        if (content_len == 0) {
1755          /* if atoi returns 0 on error, fix this */
1756          if ((content_len_num[0] != '0') || (content_len_num[1] != '\r')) {
1757            content_len = -1;
1758          }
1759        }
1760        if (content_len >= 0) {
1761          /* adjust length of HTTP header passed to application */
1762          const char *hdr_start_after_uri = uri_end + 1;
1763          u16_t hdr_len = (u16_t)LWIP_MIN(data_len, crlfcrlf + 4 - data);
1764          u16_t hdr_data_len = (u16_t)LWIP_MIN(data_len, crlfcrlf + 4 - hdr_start_after_uri);
1765          u8_t post_auto_wnd = 1;
1766          http_uri_buf[0] = 0;
1767          /* trim http header */
1768          *crlfcrlf = 0;
1769          err = httpd_post_begin(hs, uri, hdr_start_after_uri, hdr_data_len, content_len,
1770            http_uri_buf, LWIP_HTTPD_URI_BUF_LEN, &post_auto_wnd);
1771          if (err == ERR_OK) {
1772            /* try to pass in data of the first pbuf(s) */
1773            struct pbuf *q = inp;
1774            u16_t start_offset = hdr_len;
1775#if LWIP_HTTPD_POST_MANUAL_WND
1776            hs->no_auto_wnd = !post_auto_wnd;
1777#endif /* LWIP_HTTPD_POST_MANUAL_WND */
1778            /* set the Content-Length to be received for this POST */
1779            hs->post_content_len_left = (u32_t)content_len;
1780
1781            /* get to the pbuf where the body starts */
1782            while((q != NULL) && (q->len <= start_offset)) {
1783              start_offset -= q->len;
1784              q = q->next;
1785            }
1786            if (q != NULL) {
1787              /* hide the remaining HTTP header */
1788              pbuf_header(q, -(s16_t)start_offset);
1789#if LWIP_HTTPD_POST_MANUAL_WND
1790              if (!post_auto_wnd) {
1791                /* already tcp_recved() this data... */
1792                hs->unrecved_bytes = q->tot_len;
1793              }
1794#endif /* LWIP_HTTPD_POST_MANUAL_WND */
1795              pbuf_ref(q);
1796              return http_post_rxpbuf(hs, q);
1797            } else if (hs->post_content_len_left == 0) {
1798              q = pbuf_alloc(PBUF_RAW, 0, PBUF_REF);
1799              return http_post_rxpbuf(hs, q);
1800            } else {
1801              return ERR_OK;
1802            }
1803          } else {
1804            /* return file passed from application */
1805            return http_find_file(hs, http_uri_buf, 0);
1806          }
1807        } else {
1808          LWIP_DEBUGF(HTTPD_DEBUG, ("POST received invalid Content-Length: %s\n",
1809            content_len_num));
1810          return ERR_ARG;
1811        }
1812      }
1813    }
1814    /* If we come here, headers are fully received (double-crlf), but Content-Length
1815       was not included. Since this is currently the only supported method, we have
1816       to fail in this case! */
1817    LWIP_DEBUGF(HTTPD_DEBUG, ("Error when parsing Content-Length\n"));
1818    return ERR_ARG;
1819  }
1820  /* if we come here, the POST is incomplete */
1821#if LWIP_HTTPD_SUPPORT_REQUESTLIST
1822  return ERR_INPROGRESS;
1823#else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1824  return ERR_ARG;
1825#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1826}
1827
1828#if LWIP_HTTPD_POST_MANUAL_WND
1829/** A POST implementation can call this function to update the TCP window.
1830 * This can be used to throttle data reception (e.g. when received data is
1831 * programmed to flash and data is received faster than programmed).
1832 *
1833 * @param connection A connection handle passed to httpd_post_begin for which
1834 *        httpd_post_finished has *NOT* been called yet!
1835 * @param recved_len Length of data received (for window update)
1836 */
1837void httpd_post_data_recved(void *connection, u16_t recved_len)
1838{
1839  struct http_state *hs = (struct http_state*)connection;
1840  if (hs != NULL) {
1841    if (hs->no_auto_wnd) {
1842      u16_t len = recved_len;
1843      if (hs->unrecved_bytes >= recved_len) {
1844        hs->unrecved_bytes -= recved_len;
1845      } else {
1846        LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_LEVEL_WARNING, ("httpd_post_data_recved: recved_len too big\n"));
1847        len = (u16_t)hs->unrecved_bytes;
1848        hs->unrecved_bytes = 0;
1849      }
1850      if (hs->pcb != NULL) {
1851        if (len != 0) {
1852          tcp_recved(hs->pcb, len);
1853        }
1854        if ((hs->post_content_len_left == 0) && (hs->unrecved_bytes == 0)) {
1855          /* finished handling POST */
1856          http_handle_post_finished(hs);
1857          http_send(hs->pcb, hs);
1858        }
1859      }
1860    }
1861  }
1862}
1863#endif /* LWIP_HTTPD_POST_MANUAL_WND */
1864
1865#endif /* LWIP_HTTPD_SUPPORT_POST */
1866
1867#if LWIP_HTTPD_FS_ASYNC_READ
1868/** Try to send more data if file has been blocked before
1869 * This is a callback function passed to fs_read_async().
1870 */
1871static void
1872http_continue(void *connection)
1873{
1874  struct http_state *hs = (struct http_state*)connection;
1875  if (hs && (hs->pcb) && (hs->handle)) {
1876    LWIP_ASSERT("hs->pcb != NULL", hs->pcb != NULL);
1877    LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("httpd_continue: try to send more data\n"));
1878    if (http_send(hs->pcb, hs)) {
1879      /* If we wrote anything to be sent, go ahead and send it now. */
1880      LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("tcp_output\n"));
1881      tcp_output(hs->pcb);
1882    }
1883  }
1884}
1885#endif /* LWIP_HTTPD_FS_ASYNC_READ */
1886
1887/**
1888 * When data has been received in the correct state, try to parse it
1889 * as a HTTP request.
1890 *
1891 * @param inp the received pbuf
1892 * @param hs the connection state
1893 * @param pcb the tcp_pcb which received this packet
1894 * @return ERR_OK if request was OK and hs has been initialized correctly
1895 *         ERR_INPROGRESS if request was OK so far but not fully received
1896 *         another err_t otherwise
1897 */
1898static err_t
1899http_parse_request(struct pbuf *inp, struct http_state *hs, struct tcp_pcb *pcb)
1900{
1901  char *data;
1902  char *crlf;
1903  u16_t data_len;
1904  struct pbuf *p = inp;
1905#if LWIP_HTTPD_SUPPORT_REQUESTLIST
1906  u16_t clen;
1907#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1908#if LWIP_HTTPD_SUPPORT_POST
1909  err_t err;
1910#endif /* LWIP_HTTPD_SUPPORT_POST */
1911
1912  LWIP_UNUSED_ARG(pcb); /* only used for post */
1913  LWIP_ASSERT("p != NULL", p != NULL);
1914  LWIP_ASSERT("hs != NULL", hs != NULL);
1915
1916  if ((hs->handle != NULL) || (hs->file != NULL)) {
1917    LWIP_DEBUGF(HTTPD_DEBUG, ("Received data while sending a file\n"));
1918    /* already sending a file */
1919    /* @todo: abort? */
1920    return ERR_USE;
1921  }
1922
1923#if LWIP_HTTPD_SUPPORT_REQUESTLIST
1924
1925  LWIP_DEBUGF(HTTPD_DEBUG, ("Received %"U16_F" bytes\n", p->tot_len));
1926
1927  /* first check allowed characters in this pbuf? */
1928
1929  /* enqueue the pbuf */
1930  if (hs->req == NULL) {
1931    LWIP_DEBUGF(HTTPD_DEBUG, ("First pbuf\n"));
1932    hs->req = p;
1933  } else {
1934    LWIP_DEBUGF(HTTPD_DEBUG, ("pbuf enqueued\n"));
1935    pbuf_cat(hs->req, p);
1936  }
1937  /* increase pbuf ref counter as it is freed when we return but we want to
1938     keep it on the req list */
1939  pbuf_ref(p);
1940
1941  if (hs->req->next != NULL) {
1942    data_len = LWIP_MIN(hs->req->tot_len, LWIP_HTTPD_MAX_REQ_LENGTH);
1943    pbuf_copy_partial(hs->req, httpd_req_buf, data_len, 0);
1944    data = httpd_req_buf;
1945  } else
1946#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1947  {
1948    data = (char *)p->payload;
1949    data_len = p->len;
1950    if (p->len != p->tot_len) {
1951      LWIP_DEBUGF(HTTPD_DEBUG, ("Warning: incomplete header due to chained pbufs\n"));
1952    }
1953  }
1954
1955  /* received enough data for minimal request? */
1956  if (data_len >= MIN_REQ_LEN) {
1957    /* wait for CRLF before parsing anything */
1958    crlf = lwip_strnstr(data, CRLF, data_len);
1959    if (crlf != NULL) {
1960#if LWIP_HTTPD_SUPPORT_POST
1961      int is_post = 0;
1962#endif /* LWIP_HTTPD_SUPPORT_POST */
1963      int is_09 = 0;
1964      char *sp1, *sp2;
1965      u16_t left_len, uri_len;
1966      LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("CRLF received, parsing request\n"));
1967      /* parse method */
1968      if (!strncmp(data, "GET ", 4)) {
1969        sp1 = data + 3;
1970        /* received GET request */
1971        LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received GET request\"\n"));
1972#if LWIP_HTTPD_SUPPORT_POST
1973      } else if (!strncmp(data, "POST ", 5)) {
1974        /* store request type */
1975        is_post = 1;
1976        sp1 = data + 4;
1977        /* received GET request */
1978        LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received POST request\n"));
1979#endif /* LWIP_HTTPD_SUPPORT_POST */
1980      } else {
1981        /* null-terminate the METHOD (pbuf is freed anyway wen returning) */
1982        data[4] = 0;
1983        /* unsupported method! */
1984        LWIP_DEBUGF(HTTPD_DEBUG, ("Unsupported request method (not implemented): \"%s\"\n",
1985          data));
1986        return http_find_error_file(hs, 501);
1987      }
1988      /* if we come here, method is OK, parse URI */
1989      left_len = (u16_t)(data_len - ((sp1 +1) - data));
1990      sp2 = lwip_strnstr(sp1 + 1, " ", left_len);
1991#if LWIP_HTTPD_SUPPORT_V09
1992      if (sp2 == NULL) {
1993        /* HTTP 0.9: respond with correct protocol version */
1994        sp2 = lwip_strnstr(sp1 + 1, CRLF, left_len);
1995        is_09 = 1;
1996#if LWIP_HTTPD_SUPPORT_POST
1997        if (is_post) {
1998          /* HTTP/0.9 does not support POST */
1999          goto badrequest;
2000        }
2001#endif /* LWIP_HTTPD_SUPPORT_POST */
2002      }
2003#endif /* LWIP_HTTPD_SUPPORT_V09 */
2004      uri_len = (u16_t)(sp2 - (sp1 + 1));
2005      if ((sp2 != 0) && (sp2 > sp1)) {
2006        /* wait for CRLFCRLF (indicating end of HTTP headers) before parsing anything */
2007        if (lwip_strnstr(data, CRLF CRLF, data_len) != NULL) {
2008          char *uri = sp1 + 1;
2009#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
2010          /* This is HTTP/1.0 compatible: for strict 1.1, a connection
2011             would always be persistent unless "close" was specified. */
2012          if (!is_09 && (lwip_strnstr(data, HTTP11_CONNECTIONKEEPALIVE, data_len) ||
2013              lwip_strnstr(data, HTTP11_CONNECTIONKEEPALIVE2, data_len))) {
2014            hs->keepalive = 1;
2015          } else {
2016            hs->keepalive = 0;
2017          }
2018#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
2019          /* null-terminate the METHOD (pbuf is freed anyway wen returning) */
2020          *sp1 = 0;
2021          uri[uri_len] = 0;
2022          LWIP_DEBUGF(HTTPD_DEBUG, ("Received \"%s\" request for URI: \"%s\"\n",
2023                      data, uri));
2024#if LWIP_HTTPD_SUPPORT_POST
2025          if (is_post) {
2026#if LWIP_HTTPD_SUPPORT_REQUESTLIST
2027            struct pbuf *q = hs->req;
2028#else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
2029            struct pbuf *q = inp;
2030#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
2031            err = http_post_request(q, hs, data, data_len, uri, sp2);
2032            if (err != ERR_OK) {
2033              /* restore header for next try */
2034              *sp1 = ' ';
2035              *sp2 = ' ';
2036              uri[uri_len] = ' ';
2037            }
2038            if (err == ERR_ARG) {
2039              goto badrequest;
2040            }
2041            return err;
2042          } else
2043#endif /* LWIP_HTTPD_SUPPORT_POST */
2044          {
2045            return http_find_file(hs, uri, is_09);
2046          }
2047        }
2048      } else {
2049        LWIP_DEBUGF(HTTPD_DEBUG, ("invalid URI\n"));
2050      }
2051    }
2052  }
2053
2054#if LWIP_HTTPD_SUPPORT_REQUESTLIST
2055  clen = pbuf_clen(hs->req);
2056  if ((hs->req->tot_len <= LWIP_HTTPD_REQ_BUFSIZE) &&
2057    (clen <= LWIP_HTTPD_REQ_QUEUELEN)) {
2058    /* request not fully received (too short or CRLF is missing) */
2059    return ERR_INPROGRESS;
2060  } else
2061#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
2062  {
2063#if LWIP_HTTPD_SUPPORT_POST
2064badrequest:
2065#endif /* LWIP_HTTPD_SUPPORT_POST */
2066    LWIP_DEBUGF(HTTPD_DEBUG, ("bad request\n"));
2067    /* could not parse request */
2068    return http_find_error_file(hs, 400);
2069  }
2070}
2071
2072/** Try to find the file specified by uri and, if found, initialize hs
2073 * accordingly.
2074 *
2075 * @param hs the connection state
2076 * @param uri the HTTP header URI
2077 * @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response)
2078 * @return ERR_OK if file was found and hs has been initialized correctly
2079 *         another err_t otherwise
2080 */
2081static err_t
2082http_find_file(struct http_state *hs, const char *uri, int is_09)
2083{
2084  size_t loop;
2085  struct fs_file *file = NULL;
2086  char *params = NULL;
2087  err_t err;
2088#if LWIP_HTTPD_CGI
2089  int i;
2090#endif /* LWIP_HTTPD_CGI */
2091#if !LWIP_HTTPD_SSI
2092  const
2093#endif /* !LWIP_HTTPD_SSI */
2094  /* By default, assume we will not be processing server-side-includes tags */
2095  u8_t tag_check = 0;
2096
2097  /* Have we been asked for the default file (in root or a directory) ? */
2098#if LWIP_HTTPD_MAX_REQUEST_URI_LEN
2099  size_t uri_len = strlen(uri);
2100  if ((uri_len > 0) && (uri[uri_len-1] == '/') &&
2101      ((uri != http_uri_buf) || (uri_len == 1))) {
2102    size_t copy_len = LWIP_MIN(sizeof(http_uri_buf) - 1, uri_len - 1);
2103    if (copy_len > 0) {
2104      MEMCPY(http_uri_buf, uri, copy_len);
2105      http_uri_buf[copy_len] = 0;
2106    }
2107#else /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */
2108  if ((uri[0] == '/') &&  (uri[1] == 0)) {
2109#endif /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */
2110    /* Try each of the configured default filenames until we find one
2111       that exists. */
2112    for (loop = 0; loop < NUM_DEFAULT_FILENAMES; loop++) {
2113      const char* file_name;
2114#if LWIP_HTTPD_MAX_REQUEST_URI_LEN
2115      if (copy_len > 0) {
2116        size_t len_left = sizeof(http_uri_buf) - copy_len - 1;
2117        if (len_left > 0) {
2118          size_t name_len = strlen(g_psDefaultFilenames[loop].name);
2119          size_t name_copy_len = LWIP_MIN(len_left, name_len);
2120          MEMCPY(&http_uri_buf[copy_len], g_psDefaultFilenames[loop].name, name_copy_len);
2121        }
2122        file_name = http_uri_buf;
2123      } else
2124#endif /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */
2125      {
2126        file_name = g_psDefaultFilenames[loop].name;
2127      }
2128      LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Looking for %s...\n", file_name));
2129      err = fs_open(&hs->file_handle, file_name);
2130      if(err == ERR_OK) {
2131        uri = file_name;
2132        file = &hs->file_handle;
2133        LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opened.\n"));
2134#if LWIP_HTTPD_SSI
2135        tag_check = g_psDefaultFilenames[loop].shtml;
2136#endif /* LWIP_HTTPD_SSI */
2137        break;
2138      }
2139    }
2140  }
2141  if (file == NULL) {
2142    /* No - we've been asked for a specific file. */
2143    /* First, isolate the base URI (without any parameters) */
2144    params = (char *)strchr(uri, '?');
2145    if (params != NULL) {
2146      /* URI contains parameters. NULL-terminate the base URI */
2147      *params = '\0';
2148      params++;
2149    }
2150
2151#if LWIP_HTTPD_CGI
2152    http_cgi_paramcount = -1;
2153    /* Does the base URI we have isolated correspond to a CGI handler? */
2154    if (g_iNumCGIs && g_pCGIs) {
2155      for (i = 0; i < g_iNumCGIs; i++) {
2156        if (strcmp(uri, g_pCGIs[i].pcCGIName) == 0) {
2157          /*
2158           * We found a CGI that handles this URI so extract the
2159           * parameters and call the handler.
2160           */
2161           http_cgi_paramcount = extract_uri_parameters(hs, params);
2162           uri = g_pCGIs[i].pfnCGIHandler(i, http_cgi_paramcount, hs->params,
2163                                          hs->param_vals);
2164           break;
2165        }
2166      }
2167    }
2168#endif /* LWIP_HTTPD_CGI */
2169
2170    LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opening %s\n", uri));
2171
2172    err = fs_open(&hs->file_handle, uri);
2173    if (err == ERR_OK) {
2174       file = &hs->file_handle;
2175    } else {
2176      file = http_get_404_file(hs, &uri);
2177    }
2178#if LWIP_HTTPD_SSI
2179    if (file != NULL) {
2180      /* See if we have been asked for an shtml file and, if so,
2181         enable tag checking. */
2182      const char* ext = NULL, *sub;
2183      char* param = (char*)strstr(uri, "?");
2184      if (param != NULL) {
2185         /* separate uri from parameters for now, set back later */
2186         *param = 0;
2187      }
2188      sub = uri;
2189      ext = uri;
2190      for (sub = strstr(sub, "."); sub != NULL; sub = strstr(sub, "."))
2191      {
2192         ext = sub;
2193         sub++;
2194      }
2195      tag_check = 0;
2196      for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) {
2197        if (!lwip_stricmp(ext, g_pcSSIExtensions[loop])) {
2198          tag_check = 1;
2199          break;
2200        }
2201      }
2202      if (param != NULL) {
2203         *param = '?';
2204      }
2205    }
2206#endif /* LWIP_HTTPD_SSI */
2207  }
2208  if (file == NULL) {
2209    /* None of the default filenames exist so send back a 404 page */
2210    file = http_get_404_file(hs, &uri);
2211  }
2212  return http_init_file(hs, file, is_09, uri, tag_check, params);
2213}
2214
2215/** Initialize a http connection with a file to send (if found).
2216 * Called by http_find_file and http_find_error_file.
2217 *
2218 * @param hs http connection state
2219 * @param file file structure to send (or NULL if not found)
2220 * @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response)
2221 * @param uri the HTTP header URI
2222 * @param tag_check enable SSI tag checking
2223 * @param params != NULL if URI has parameters (separated by '?')
2224 * @return ERR_OK if file was found and hs has been initialized correctly
2225 *         another err_t otherwise
2226 */
2227static err_t
2228http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri,
2229               u8_t tag_check, char* params)
2230{
2231  if (file != NULL) {
2232    /* file opened, initialise struct http_state */
2233#if LWIP_HTTPD_SSI
2234    if (tag_check) {
2235      struct http_ssi_state *ssi = http_ssi_state_alloc();
2236      if (ssi != NULL) {
2237        ssi->tag_index = 0;
2238        ssi->tag_state = TAG_NONE;
2239        ssi->parsed = file->data;
2240        ssi->parse_left = file->len;
2241        ssi->tag_end = file->data;
2242        hs->ssi = ssi;
2243      }
2244    }
2245#else /* LWIP_HTTPD_SSI */
2246    LWIP_UNUSED_ARG(tag_check);
2247#endif /* LWIP_HTTPD_SSI */
2248    hs->handle = file;
2249    hs->file = file->data;
2250    LWIP_ASSERT("File length must be positive!", (file->len >= 0));
2251#if LWIP_HTTPD_CUSTOM_FILES
2252    if (file->is_custom_file && (file->data == NULL)) {
2253      /* custom file, need to read data first (via fs_read_custom) */
2254      hs->left = 0;
2255    } else
2256#endif /* LWIP_HTTPD_CUSTOM_FILES */
2257    {
2258      hs->left = file->len;
2259    }
2260    hs->retries = 0;
2261#if LWIP_HTTPD_TIMING
2262    hs->time_started = sys_now();
2263#endif /* LWIP_HTTPD_TIMING */
2264#if !LWIP_HTTPD_DYNAMIC_HEADERS
2265    LWIP_ASSERT("HTTP headers not included in file system",
2266       (hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) != 0);
2267#endif /* !LWIP_HTTPD_DYNAMIC_HEADERS */
2268#if LWIP_HTTPD_SUPPORT_V09
2269    if (is_09 && ((hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) != 0)) {
2270      /* HTTP/0.9 responses are sent without HTTP header,
2271         search for the end of the header. */
2272      char *file_start = lwip_strnstr(hs->file, CRLF CRLF, hs->left);
2273      if (file_start != NULL) {
2274        size_t diff = file_start + 4 - hs->file;
2275        hs->file += diff;
2276        hs->left -= (u32_t)diff;
2277      }
2278    }
2279#endif /* LWIP_HTTPD_SUPPORT_V09*/
2280#if LWIP_HTTPD_CGI_SSI
2281    if (params != NULL) {
2282      /* URI contains parameters, call generic CGI handler */
2283      int count;
2284#if LWIP_HTTPD_CGI
2285      if (http_cgi_paramcount >= 0) {
2286        count = http_cgi_paramcount;
2287      } else
2288#endif
2289      {
2290        count = extract_uri_parameters(hs, params);
2291      }
2292      httpd_cgi_handler(uri, count, http_cgi_params, http_cgi_param_vals
2293#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE
2294         , hs->handle->state
2295#endif /* LWIP_HTTPD_FILE_STATE */
2296                        );
2297    }
2298#else /* LWIP_HTTPD_CGI_SSI */
2299    LWIP_UNUSED_ARG(params);
2300#endif /* LWIP_HTTPD_CGI_SSI */
2301  } else {
2302    hs->handle = NULL;
2303    hs->file = NULL;
2304    hs->left = 0;
2305    hs->retries = 0;
2306  }
2307#if LWIP_HTTPD_DYNAMIC_HEADERS
2308  /* Determine the HTTP headers to send based on the file extension of
2309   * the requested URI. */
2310  if ((hs->handle == NULL) || ((hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) == 0)) {
2311    get_http_headers(hs, uri);
2312  }
2313#else /* LWIP_HTTPD_DYNAMIC_HEADERS */
2314  LWIP_UNUSED_ARG(uri);
2315#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
2316#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
2317  if (hs->keepalive) {
2318#if LWIP_HTTPD_SSI
2319     if (hs->ssi != NULL) {
2320       hs->keepalive = 0;
2321     } else
2322#endif /* LWIP_HTTPD_SSI */
2323     {
2324       if ((hs->handle != NULL) &&
2325           ((hs->handle->flags & (FS_FILE_FLAGS_HEADER_INCLUDED|FS_FILE_FLAGS_HEADER_PERSISTENT)) == FS_FILE_FLAGS_HEADER_INCLUDED)) {
2326         hs->keepalive = 0;
2327       }
2328     }
2329  }
2330#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
2331  return ERR_OK;
2332}
2333
2334/**
2335 * The pcb had an error and is already deallocated.
2336 * The argument might still be valid (if != NULL).
2337 */
2338static void
2339http_err(void *arg, err_t err)
2340{
2341  struct http_state *hs = (struct http_state *)arg;
2342  LWIP_UNUSED_ARG(err);
2343
2344  LWIP_DEBUGF(HTTPD_DEBUG, ("http_err: %s", lwip_strerr(err)));
2345
2346  if (hs != NULL) {
2347    http_state_free(hs);
2348  }
2349}
2350
2351/**
2352 * Data has been sent and acknowledged by the remote host.
2353 * This means that more data can be sent.
2354 */
2355static err_t
2356http_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
2357{
2358  struct http_state *hs = (struct http_state *)arg;
2359
2360  LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_sent %p\n", (void*)pcb));
2361
2362  LWIP_UNUSED_ARG(len);
2363
2364  if (hs == NULL) {
2365    return ERR_OK;
2366  }
2367
2368  hs->retries = 0;
2369
2370  http_send(pcb, hs);
2371
2372  return ERR_OK;
2373}
2374
2375/**
2376 * The poll function is called every 2nd second.
2377 * If there has been no data sent (which resets the retries) in 8 seconds, close.
2378 * If the last portion of a file has not been sent in 2 seconds, close.
2379 *
2380 * This could be increased, but we don't want to waste resources for bad connections.
2381 */
2382static err_t
2383http_poll(void *arg, struct tcp_pcb *pcb)
2384{
2385  struct http_state *hs = (struct http_state *)arg;
2386  LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_poll: pcb=%p hs=%p pcb_state=%s\n",
2387    (void*)pcb, (void*)hs, tcp_debug_state_str(pcb->state)));
2388
2389  if (hs == NULL) {
2390    err_t closed;
2391    /* arg is null, close. */
2392    LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: arg is NULL, close\n"));
2393    closed = http_close_conn(pcb, NULL);
2394    LWIP_UNUSED_ARG(closed);
2395#if LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR
2396    if (closed == ERR_MEM) {
2397       tcp_abort(pcb);
2398       return ERR_ABRT;
2399    }
2400#endif /* LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR */
2401    return ERR_OK;
2402  } else {
2403    hs->retries++;
2404    if (hs->retries == HTTPD_MAX_RETRIES) {
2405      LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: too many retries, close\n"));
2406      http_close_conn(pcb, hs);
2407      return ERR_OK;
2408    }
2409
2410    /* If this connection has a file open, try to send some more data. If
2411     * it has not yet received a GET request, don't do this since it will
2412     * cause the connection to close immediately. */
2413    if(hs && (hs->handle)) {
2414      LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_poll: try to send more data\n"));
2415      if(http_send(pcb, hs)) {
2416        /* If we wrote anything to be sent, go ahead and send it now. */
2417        LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("tcp_output\n"));
2418        tcp_output(pcb);
2419      }
2420    }
2421  }
2422
2423  return ERR_OK;
2424}
2425
2426/**
2427 * Data has been received on this pcb.
2428 * For HTTP 1.0, this should normally only happen once (if the request fits in one packet).
2429 */
2430static err_t
2431http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
2432{
2433  struct http_state *hs = (struct http_state *)arg;
2434  LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_recv: pcb=%p pbuf=%p err=%s\n", (void*)pcb,
2435    (void*)p, lwip_strerr(err)));
2436
2437  if ((err != ERR_OK) || (p == NULL) || (hs == NULL)) {
2438    /* error or closed by other side? */
2439    if (p != NULL) {
2440      /* Inform TCP that we have taken the data. */
2441      tcp_recved(pcb, p->tot_len);
2442      pbuf_free(p);
2443    }
2444    if (hs == NULL) {
2445      /* this should not happen, only to be robust */
2446      LWIP_DEBUGF(HTTPD_DEBUG, ("Error, http_recv: hs is NULL, close\n"));
2447    }
2448    http_close_conn(pcb, hs);
2449    return ERR_OK;
2450  }
2451
2452#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
2453  if (hs->no_auto_wnd) {
2454     hs->unrecved_bytes += p->tot_len;
2455  } else
2456#endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
2457  {
2458    /* Inform TCP that we have taken the data. */
2459    tcp_recved(pcb, p->tot_len);
2460  }
2461
2462#if LWIP_HTTPD_SUPPORT_POST
2463  if (hs->post_content_len_left > 0) {
2464    /* reset idle counter when POST data is received */
2465    hs->retries = 0;
2466    /* this is data for a POST, pass the complete pbuf to the application */
2467    http_post_rxpbuf(hs, p);
2468    /* pbuf is passed to the application, don't free it! */
2469    if (hs->post_content_len_left == 0) {
2470      /* all data received, send response or close connection */
2471      http_send(pcb, hs);
2472    }
2473    return ERR_OK;
2474  } else
2475#endif /* LWIP_HTTPD_SUPPORT_POST */
2476  {
2477    if (hs->handle == NULL) {
2478      err_t parsed = http_parse_request(p, hs, pcb);
2479      LWIP_ASSERT("http_parse_request: unexpected return value", parsed == ERR_OK
2480        || parsed == ERR_INPROGRESS ||parsed == ERR_ARG || parsed == ERR_USE);
2481#if LWIP_HTTPD_SUPPORT_REQUESTLIST
2482      if (parsed != ERR_INPROGRESS) {
2483        /* request fully parsed or error */
2484        if (hs->req != NULL) {
2485          pbuf_free(hs->req);
2486          hs->req = NULL;
2487        }
2488      }
2489#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
2490      pbuf_free(p);
2491      if (parsed == ERR_OK) {
2492#if LWIP_HTTPD_SUPPORT_POST
2493       if (hs->post_content_len_left == 0)
2494#endif /* LWIP_HTTPD_SUPPORT_POST */
2495        {
2496          LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_recv: data %p len %"S32_F"\n", (const void*)hs->file, hs->left));
2497          http_send(pcb, hs);
2498        }
2499      } else if (parsed == ERR_ARG) {
2500        /* @todo: close on ERR_USE? */
2501        http_close_conn(pcb, hs);
2502      }
2503    } else {
2504      LWIP_DEBUGF(HTTPD_DEBUG, ("http_recv: already sending data\n"));
2505      /* already sending but still receiving data, we might want to RST here? */
2506      pbuf_free(p);
2507    }
2508  }
2509  return ERR_OK;
2510}
2511
2512/**
2513 * A new incoming connection has been accepted.
2514 */
2515static err_t
2516http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
2517{
2518  struct http_state *hs;
2519  LWIP_UNUSED_ARG(err);
2520  LWIP_UNUSED_ARG(arg);
2521  LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept %p / %p\n", (void*)pcb, arg));
2522
2523  if ((err != ERR_OK) || (pcb == NULL)) {
2524    return ERR_VAL;
2525  }
2526
2527  /* Set priority */
2528  tcp_setprio(pcb, HTTPD_TCP_PRIO);
2529
2530  /* Allocate memory for the structure that holds the state of the
2531     connection - initialized by that function. */
2532  hs = http_state_alloc();
2533  if (hs == NULL) {
2534    LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept: Out of memory, RST\n"));
2535    return ERR_MEM;
2536  }
2537  hs->pcb = pcb;
2538
2539  /* Tell TCP that this is the structure we wish to be passed for our
2540     callbacks. */
2541  tcp_arg(pcb, hs);
2542
2543  /* Set up the various callback functions */
2544  tcp_recv(pcb, http_recv);
2545  tcp_err(pcb, http_err);
2546  tcp_poll(pcb, http_poll, HTTPD_POLL_INTERVAL);
2547  tcp_sent(pcb, http_sent);
2548
2549  return ERR_OK;
2550}
2551
2552/**
2553 * @ingroup httpd
2554 * Initialize the httpd: set up a listening PCB and bind it to the defined port
2555 */
2556void
2557httpd_init(void)
2558{
2559  struct tcp_pcb *pcb;
2560  err_t err;
2561
2562#if HTTPD_USE_MEM_POOL
2563  LWIP_MEMPOOL_INIT(HTTPD_STATE);
2564#if LWIP_HTTPD_SSI
2565  LWIP_MEMPOOL_INIT(HTTPD_SSI_STATE);
2566#endif
2567#endif
2568  LWIP_DEBUGF(HTTPD_DEBUG, ("httpd_init\n"));
2569
2570  pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
2571  LWIP_ASSERT("httpd_init: tcp_new failed", pcb != NULL);
2572  tcp_setprio(pcb, HTTPD_TCP_PRIO);
2573  /* set SOF_REUSEADDR here to explicitly bind httpd to multiple interfaces */
2574  err = tcp_bind(pcb, IP_ANY_TYPE, HTTPD_SERVER_PORT);
2575  LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
2576  LWIP_ASSERT("httpd_init: tcp_bind failed", err == ERR_OK);
2577  pcb = tcp_listen(pcb);
2578  LWIP_ASSERT("httpd_init: tcp_listen failed", pcb != NULL);
2579  tcp_accept(pcb, http_accept);
2580}
2581
2582#if LWIP_HTTPD_SSI
2583/**
2584 * Set the SSI handler function.
2585 *
2586 * @param ssi_handler the SSI handler function
2587 * @param tags an array of SSI tag strings to search for in SSI-enabled files
2588 * @param num_tags number of tags in the 'tags' array
2589 */
2590void
2591http_set_ssi_handler(tSSIHandler ssi_handler, const char **tags, int num_tags)
2592{
2593  LWIP_DEBUGF(HTTPD_DEBUG, ("http_set_ssi_handler\n"));
2594
2595  LWIP_ASSERT("no ssi_handler given", ssi_handler != NULL);
2596  g_pfnSSIHandler = ssi_handler;
2597
2598#if LWIP_HTTPD_SSI_RAW
2599  LWIP_UNUSED_ARG(tags);
2600  LWIP_UNUSED_ARG(num_tags);
2601#else /* LWIP_HTTPD_SSI_RAW */
2602  LWIP_ASSERT("no tags given", tags != NULL);
2603  LWIP_ASSERT("invalid number of tags", num_tags > 0);
2604
2605  g_ppcTags = tags;
2606  g_iNumTags = num_tags;
2607#endif /* !LWIP_HTTPD_SSI_RAW */
2608}
2609#endif /* LWIP_HTTPD_SSI */
2610
2611#if LWIP_HTTPD_CGI
2612/**
2613 * Set an array of CGI filenames/handler functions
2614 *
2615 * @param cgis an array of CGI filenames/handler functions
2616 * @param num_handlers number of elements in the 'cgis' array
2617 */
2618void
2619http_set_cgi_handlers(const tCGI *cgis, int num_handlers)
2620{
2621  LWIP_ASSERT("no cgis given", cgis != NULL);
2622  LWIP_ASSERT("invalid number of handlers", num_handlers > 0);
2623
2624  g_pCGIs = cgis;
2625  g_iNumCGIs = num_handlers;
2626}
2627#endif /* LWIP_HTTPD_CGI */
2628
2629#endif /* LWIP_TCP && LWIP_CALLBACK_API */
2630