ReactOS 0.4.16-dev-927-g467dec4
httpd.c
Go to the documentation of this file.
1
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
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
99#include "lwip/altcp.h"
100#include "lwip/altcp_tcp.h"
101#if HTTPD_ENABLE_HTTPS
102#include "lwip/altcp_tls.h"
103#endif
104#ifdef LWIP_HOOK_FILENAME
105#include LWIP_HOOK_FILENAME
106#endif
107#if LWIP_HTTPD_TIMING
108#include "lwip/sys.h"
109#endif /* LWIP_HTTPD_TIMING */
110
111#include <string.h> /* memset */
112#include <stdlib.h> /* atoi */
113#include <stdio.h>
114
115#if LWIP_TCP && LWIP_CALLBACK_API
116
118#define MIN_REQ_LEN 7
119
120#define CRLF "\r\n"
121#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
122#define HTTP11_CONNECTIONKEEPALIVE "Connection: keep-alive"
123#define HTTP11_CONNECTIONKEEPALIVE2 "Connection: Keep-Alive"
124#endif
125
126#if LWIP_HTTPD_DYNAMIC_FILE_READ
127#define HTTP_IS_DYNAMIC_FILE(hs) ((hs)->buf != NULL)
128#else
129#define HTTP_IS_DYNAMIC_FILE(hs) 0
130#endif
131
132/* This defines checks whether tcp_write has to copy data or not */
133
134#ifndef HTTP_IS_DATA_VOLATILE
136#define HTTP_IS_DATA_VOLATILE(hs) (HTTP_IS_DYNAMIC_FILE(hs) ? TCP_WRITE_FLAG_COPY : 0)
137#endif
139#ifndef HTTP_IS_HDR_VOLATILE
140#define HTTP_IS_HDR_VOLATILE(hs, ptr) 0
141#endif
142
143/* Return values for http_send_*() */
144#define HTTP_DATA_TO_SEND_FREED 3
145#define HTTP_DATA_TO_SEND_BREAK 2
146#define HTTP_DATA_TO_SEND_CONTINUE 1
147#define HTTP_NO_DATA_TO_SEND 0
148
149typedef struct {
150 const char *name;
151 u8_t shtml;
152} default_filename;
153
154static const default_filename httpd_default_filenames[] = {
155 {"/index.shtml", 1 },
156 {"/index.ssi", 1 },
157 {"/index.shtm", 1 },
158 {"/index.html", 0 },
159 {"/index.htm", 0 }
160};
161
162#define NUM_DEFAULT_FILENAMES LWIP_ARRAYSIZE(httpd_default_filenames)
163
164#if LWIP_HTTPD_SUPPORT_REQUESTLIST
166static char httpd_req_buf[LWIP_HTTPD_MAX_REQ_LENGTH + 1];
167#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
168
169#if LWIP_HTTPD_SUPPORT_POST
170#if LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN > LWIP_HTTPD_MAX_REQUEST_URI_LEN
171#define LWIP_HTTPD_URI_BUF_LEN LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN
172#endif
173#endif
174#ifndef LWIP_HTTPD_URI_BUF_LEN
175#define LWIP_HTTPD_URI_BUF_LEN LWIP_HTTPD_MAX_REQUEST_URI_LEN
176#endif
177#if LWIP_HTTPD_URI_BUF_LEN
178/* Filename for response file to send when POST is finished or
179 * search for default files when a directory is requested. */
180static char http_uri_buf[LWIP_HTTPD_URI_BUF_LEN + 1];
181#endif
182
183#if LWIP_HTTPD_DYNAMIC_HEADERS
184/* The number of individual strings that comprise the headers sent before each
185 * requested file.
186 */
187#define NUM_FILE_HDR_STRINGS 5
188#define HDR_STRINGS_IDX_HTTP_STATUS 0 /* e.g. "HTTP/1.0 200 OK\r\n" */
189#define HDR_STRINGS_IDX_SERVER_NAME 1 /* e.g. "Server: "HTTPD_SERVER_AGENT"\r\n" */
190#define HDR_STRINGS_IDX_CONTENT_LEN_KEEPALIVE 2 /* e.g. "Content-Length: xy\r\n" and/or "Connection: keep-alive\r\n" */
191#define HDR_STRINGS_IDX_CONTENT_LEN_NR 3 /* the byte count, when content-length is used */
192#define HDR_STRINGS_IDX_CONTENT_TYPE 4 /* the content type (or default answer content type including default document) */
193
194/* The dynamically generated Content-Length buffer needs space for CRLF + NULL */
195#define LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET 3
196#ifndef LWIP_HTTPD_MAX_CONTENT_LEN_SIZE
197/* The dynamically generated Content-Length buffer shall be able to work with
198 ~953 MB (9 digits) */
199#define LWIP_HTTPD_MAX_CONTENT_LEN_SIZE (9 + LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET)
200#endif
201#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
202
203#if LWIP_HTTPD_SSI
204
205#define HTTPD_LAST_TAG_PART 0xFFFF
206
207enum tag_check_state {
208 TAG_NONE, /* Not processing an SSI tag */
209 TAG_LEADIN, /* Tag lead in "<!--#" being processed */
210 TAG_FOUND, /* Tag name being read, looking for lead-out start */
211 TAG_LEADOUT, /* Tag lead out "-->" being processed */
212 TAG_SENDING /* Sending tag replacement string */
213};
214
215struct http_ssi_state {
216 const char *parsed; /* Pointer to the first unparsed byte in buf. */
217#if !LWIP_HTTPD_SSI_INCLUDE_TAG
218 const char *tag_started;/* Pointer to the first opening '<' of the tag. */
219#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */
220 const char *tag_end; /* Pointer to char after the closing '>' of the tag. */
221 u32_t parse_left; /* Number of unparsed bytes in buf. */
222 u16_t tag_index; /* Counter used by tag parsing state machine */
223 u16_t tag_insert_len; /* Length of insert in string tag_insert */
224#if LWIP_HTTPD_SSI_MULTIPART
225 u16_t tag_part; /* Counter passed to and changed by tag insertion function to insert multiple times */
226#endif /* LWIP_HTTPD_SSI_MULTIPART */
227 u8_t tag_type; /* index into http_ssi_tag_desc array */
228 u8_t tag_name_len; /* Length of the tag name in string tag_name */
229 char tag_name[LWIP_HTTPD_MAX_TAG_NAME_LEN + 1]; /* Last tag name extracted */
230 char tag_insert[LWIP_HTTPD_MAX_TAG_INSERT_LEN + 1]; /* Insert string for tag_name */
231 enum tag_check_state tag_state; /* State of the tag processor */
232};
233
234struct http_ssi_tag_description {
235 const char *lead_in;
236 const char *lead_out;
237};
238
239#endif /* LWIP_HTTPD_SSI */
240
241struct http_state {
242#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
243 struct http_state *next;
244#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
245 struct fs_file file_handle;
246 struct fs_file *handle;
247 const char *file; /* Pointer to first unsent byte in buf. */
248
249 struct altcp_pcb *pcb;
250#if LWIP_HTTPD_SUPPORT_REQUESTLIST
251 struct pbuf *req;
252#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
253
254#if LWIP_HTTPD_DYNAMIC_FILE_READ
255 char *buf; /* File read buffer. */
256 int buf_len; /* Size of file read buffer, buf. */
257#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
258 u32_t left; /* Number of unsent bytes in buf. */
259 u8_t retries;
260#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
261 u8_t keepalive;
262#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
263#if LWIP_HTTPD_SSI
264 struct http_ssi_state *ssi;
265#endif /* LWIP_HTTPD_SSI */
266#if LWIP_HTTPD_CGI
267 char *params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */
268 char *param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */
269#endif /* LWIP_HTTPD_CGI */
270#if LWIP_HTTPD_DYNAMIC_HEADERS
271 const char *hdrs[NUM_FILE_HDR_STRINGS]; /* HTTP headers to be sent. */
272 char hdr_content_len[LWIP_HTTPD_MAX_CONTENT_LEN_SIZE];
273 u16_t hdr_pos; /* The position of the first unsent header byte in the
274 current string */
275 u16_t hdr_index; /* The index of the hdr string currently being sent. */
276#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
277#if LWIP_HTTPD_TIMING
278 u32_t time_started;
279#endif /* LWIP_HTTPD_TIMING */
280#if LWIP_HTTPD_SUPPORT_POST
281 u32_t post_content_len_left;
282#if LWIP_HTTPD_POST_MANUAL_WND
283 u32_t unrecved_bytes;
284 u8_t no_auto_wnd;
285 u8_t post_finished;
286#endif /* LWIP_HTTPD_POST_MANUAL_WND */
287#endif /* LWIP_HTTPD_SUPPORT_POST*/
288};
289
290#if HTTPD_USE_MEM_POOL
291LWIP_MEMPOOL_DECLARE(HTTPD_STATE, MEMP_NUM_PARALLEL_HTTPD_CONNS, sizeof(struct http_state), "HTTPD_STATE")
292#if LWIP_HTTPD_SSI
293LWIP_MEMPOOL_DECLARE(HTTPD_SSI_STATE, MEMP_NUM_PARALLEL_HTTPD_SSI_CONNS, sizeof(struct http_ssi_state), "HTTPD_SSI_STATE")
294#define HTTP_FREE_SSI_STATE(x) LWIP_MEMPOOL_FREE(HTTPD_SSI_STATE, (x))
295#define HTTP_ALLOC_SSI_STATE() (struct http_ssi_state *)LWIP_MEMPOOL_ALLOC(HTTPD_SSI_STATE)
296#endif /* LWIP_HTTPD_SSI */
297#define HTTP_ALLOC_HTTP_STATE() (struct http_state *)LWIP_MEMPOOL_ALLOC(HTTPD_STATE)
298#define HTTP_FREE_HTTP_STATE(x) LWIP_MEMPOOL_FREE(HTTPD_STATE, (x))
299#else /* HTTPD_USE_MEM_POOL */
300#define HTTP_ALLOC_HTTP_STATE() (struct http_state *)mem_malloc(sizeof(struct http_state))
301#define HTTP_FREE_HTTP_STATE(x) mem_free(x)
302#if LWIP_HTTPD_SSI
303#define HTTP_ALLOC_SSI_STATE() (struct http_ssi_state *)mem_malloc(sizeof(struct http_ssi_state))
304#define HTTP_FREE_SSI_STATE(x) mem_free(x)
305#endif /* LWIP_HTTPD_SSI */
306#endif /* HTTPD_USE_MEM_POOL */
307
308static err_t http_close_conn(struct altcp_pcb *pcb, struct http_state *hs);
309static err_t http_close_or_abort_conn(struct altcp_pcb *pcb, struct http_state *hs, u8_t abort_conn);
310static err_t http_find_file(struct http_state *hs, const char *uri, int is_09);
311static 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);
312static err_t http_poll(void *arg, struct altcp_pcb *pcb);
313static u8_t http_check_eof(struct altcp_pcb *pcb, struct http_state *hs);
314#if LWIP_HTTPD_FS_ASYNC_READ
315static void http_continue(void *connection);
316#endif /* LWIP_HTTPD_FS_ASYNC_READ */
317
318#if LWIP_HTTPD_SSI
319/* SSI insert handler function pointer. */
320static tSSIHandler httpd_ssi_handler;
321#if !LWIP_HTTPD_SSI_RAW
322static int httpd_num_tags;
323static const char **httpd_tags;
324#endif /* !LWIP_HTTPD_SSI_RAW */
325
326/* Define the available tag lead-ins and corresponding lead-outs.
327 * ATTENTION: for the algorithm below using this array, it is essential
328 * that the lead in differs in the first character! */
329const struct http_ssi_tag_description http_ssi_tag_desc[] = {
330 {"<!--#", "-->"},
331 {"/*#", "*/"}
332};
333
334#endif /* LWIP_HTTPD_SSI */
335
336#if LWIP_HTTPD_CGI
337/* CGI handler information */
338static const tCGI *httpd_cgis;
339static int httpd_num_cgis;
340static int http_cgi_paramcount;
341#define http_cgi_params hs->params
342#define http_cgi_param_vals hs->param_vals
343#elif LWIP_HTTPD_CGI_SSI
344static char *http_cgi_params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */
345static char *http_cgi_param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */
346#endif /* LWIP_HTTPD_CGI */
347
348#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
351static struct http_state *http_connections;
352
353static void
354http_add_connection(struct http_state *hs)
355{
356 /* add the connection to the list */
357 hs->next = http_connections;
358 http_connections = hs;
359}
360
361static void
362http_remove_connection(struct http_state *hs)
363{
364 /* take the connection off the list */
365 if (http_connections) {
366 if (http_connections == hs) {
367 http_connections = hs->next;
368 } else {
369 struct http_state *last;
370 for (last = http_connections; last->next != NULL; last = last->next) {
371 if (last->next == hs) {
372 last->next = hs->next;
373 break;
374 }
375 }
376 }
377 }
378}
379
380static void
381http_kill_oldest_connection(u8_t ssi_required)
382{
383 struct http_state *hs = http_connections;
384 struct http_state *hs_free_next = NULL;
385 while (hs && hs->next) {
386#if LWIP_HTTPD_SSI
387 if (ssi_required) {
388 if (hs->next->ssi != NULL) {
389 hs_free_next = hs;
390 }
391 } else
392#else /* LWIP_HTTPD_SSI */
393 LWIP_UNUSED_ARG(ssi_required);
394#endif /* LWIP_HTTPD_SSI */
395 {
396 hs_free_next = hs;
397 }
398 LWIP_ASSERT("broken list", hs != hs->next);
399 hs = hs->next;
400 }
401 if (hs_free_next != NULL) {
402 LWIP_ASSERT("hs_free_next->next != NULL", hs_free_next->next != NULL);
403 LWIP_ASSERT("hs_free_next->next->pcb != NULL", hs_free_next->next->pcb != NULL);
404 /* send RST when killing a connection because of memory shortage */
405 http_close_or_abort_conn(hs_free_next->next->pcb, hs_free_next->next, 1); /* this also unlinks the http_state from the list */
406 }
407}
408#else /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
409
410#define http_add_connection(hs)
411#define http_remove_connection(hs)
412
413#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
414
415#if LWIP_HTTPD_SSI
417static struct http_ssi_state *
418http_ssi_state_alloc(void)
419{
420 struct http_ssi_state *ret = HTTP_ALLOC_SSI_STATE();
421#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
422 if (ret == NULL) {
423 http_kill_oldest_connection(1);
424 ret = HTTP_ALLOC_SSI_STATE();
425 }
426#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
427 if (ret != NULL) {
428 memset(ret, 0, sizeof(struct http_ssi_state));
429 }
430 return ret;
431}
432
434static void
435http_ssi_state_free(struct http_ssi_state *ssi)
436{
437 if (ssi != NULL) {
438 HTTP_FREE_SSI_STATE(ssi);
439 }
440}
441#endif /* LWIP_HTTPD_SSI */
442
445static void
446http_state_init(struct http_state *hs)
447{
448 /* Initialize the structure. */
449 memset(hs, 0, sizeof(struct http_state));
450#if LWIP_HTTPD_DYNAMIC_HEADERS
451 /* Indicate that the headers are not yet valid */
452 hs->hdr_index = NUM_FILE_HDR_STRINGS;
453#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
454}
455
457static struct http_state *
458http_state_alloc(void)
459{
460 struct http_state *ret = HTTP_ALLOC_HTTP_STATE();
461#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
462 if (ret == NULL) {
463 http_kill_oldest_connection(0);
464 ret = HTTP_ALLOC_HTTP_STATE();
465 }
466#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
467 if (ret != NULL) {
468 http_state_init(ret);
469 http_add_connection(ret);
470 }
471 return ret;
472}
473
477static void
478http_state_eof(struct http_state *hs)
479{
480 if (hs->handle) {
481#if LWIP_HTTPD_TIMING
482 u32_t ms_needed = sys_now() - hs->time_started;
483 u32_t needed = LWIP_MAX(1, (ms_needed / 100));
484 LWIP_DEBUGF(HTTPD_DEBUG_TIMING, ("httpd: needed %"U32_F" ms to send file of %d bytes -> %"U32_F" bytes/sec\n",
485 ms_needed, hs->handle->len, ((((u32_t)hs->handle->len) * 10) / needed)));
486#endif /* LWIP_HTTPD_TIMING */
487 fs_close(hs->handle);
488 hs->handle = NULL;
489 }
490#if LWIP_HTTPD_DYNAMIC_FILE_READ
491 if (hs->buf != NULL) {
492 mem_free(hs->buf);
493 hs->buf = NULL;
494 }
495#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
496#if LWIP_HTTPD_SSI
497 if (hs->ssi) {
498 http_ssi_state_free(hs->ssi);
499 hs->ssi = NULL;
500 }
501#endif /* LWIP_HTTPD_SSI */
502#if LWIP_HTTPD_SUPPORT_REQUESTLIST
503 if (hs->req) {
504 pbuf_free(hs->req);
505 hs->req = NULL;
506 }
507#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
508}
509
513static void
514http_state_free(struct http_state *hs)
515{
516 if (hs != NULL) {
517 http_state_eof(hs);
518 http_remove_connection(hs);
519 HTTP_FREE_HTTP_STATE(hs);
520 }
521}
522
532static err_t
533http_write(struct altcp_pcb *pcb, const void *ptr, u16_t *length, u8_t apiflags)
534{
535 u16_t len, max_len;
536 err_t err;
537 LWIP_ASSERT("length != NULL", length != NULL);
538 len = *length;
539 if (len == 0) {
540 return ERR_OK;
541 }
542 /* We cannot send more data than space available in the send buffer. */
543 max_len = altcp_sndbuf(pcb);
544 if (max_len < len) {
545 len = max_len;
546 }
547#ifdef HTTPD_MAX_WRITE_LEN
548 /* Additional limitation: e.g. don't enqueue more than 2*mss at once */
549 max_len = HTTPD_MAX_WRITE_LEN(pcb);
550 if (len > max_len) {
551 len = max_len;
552 }
553#endif /* HTTPD_MAX_WRITE_LEN */
554 do {
555 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Trying to send %d bytes\n", len));
556 err = altcp_write(pcb, ptr, len, apiflags);
557 if (err == ERR_MEM) {
558 if ((altcp_sndbuf(pcb) == 0) ||
560 /* no need to try smaller sizes */
561 len = 1;
562 } else {
563 len /= 2;
564 }
566 ("Send failed, trying less (%d bytes)\n", len));
567 }
568 } while ((err == ERR_MEM) && (len > 1));
569
570 if (err == ERR_OK) {
571 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Sent %d bytes\n", len));
572 *length = len;
573 } else {
574 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Send failed with err %d (\"%s\")\n", err, lwip_strerr(err)));
575 *length = 0;
576 }
577
578#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
579 /* ensure nagle is normally enabled (only disabled for persistent connections
580 when all data has been enqueued but the connection stays open for the next
581 request */
583#endif
584
585 return err;
586}
587
595static err_t
596http_close_or_abort_conn(struct altcp_pcb *pcb, struct http_state *hs, u8_t abort_conn)
597{
598 err_t err;
599 LWIP_DEBUGF(HTTPD_DEBUG, ("Closing connection %p\n", (void *)pcb));
600
601#if LWIP_HTTPD_SUPPORT_POST
602 if (hs != NULL) {
603 if ((hs->post_content_len_left != 0)
605 || ((hs->no_auto_wnd != 0) && (hs->unrecved_bytes != 0))
606#endif /* LWIP_HTTPD_POST_MANUAL_WND */
607 ) {
608 /* make sure the post code knows that the connection is closed */
609 http_uri_buf[0] = 0;
610 httpd_post_finished(hs, http_uri_buf, LWIP_HTTPD_URI_BUF_LEN);
611 }
612 }
613#endif /* LWIP_HTTPD_SUPPORT_POST*/
614
615
616 altcp_arg(pcb, NULL);
617 altcp_recv(pcb, NULL);
618 altcp_err(pcb, NULL);
619 altcp_poll(pcb, NULL, 0);
620 altcp_sent(pcb, NULL);
621 if (hs != NULL) {
622 http_state_free(hs);
623 }
624
625 if (abort_conn) {
626 altcp_abort(pcb);
627 return ERR_OK;
628 }
629 err = altcp_close(pcb);
630 if (err != ERR_OK) {
631 LWIP_DEBUGF(HTTPD_DEBUG, ("Error %d closing %p\n", err, (void *)pcb));
632 /* error closing, try again later in poll */
633 altcp_poll(pcb, http_poll, HTTPD_POLL_INTERVAL);
634 }
635 return err;
636}
637
645static err_t
646http_close_conn(struct altcp_pcb *pcb, struct http_state *hs)
647{
648 return http_close_or_abort_conn(pcb, hs, 0);
649}
650
654static void
655http_eof(struct altcp_pcb *pcb, struct http_state *hs)
656{
657 /* HTTP/1.1 persistent connection? (Not supported for SSI) */
658#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
659 if (hs->keepalive) {
660 http_remove_connection(hs);
661
662 http_state_eof(hs);
663 http_state_init(hs);
664 /* restore state: */
665 hs->pcb = pcb;
666 hs->keepalive = 1;
667 http_add_connection(hs);
668 /* ensure nagle doesn't interfere with sending all data as fast as possible: */
670 } else
671#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
672 {
673 http_close_conn(pcb, hs);
674 }
675}
676
677#if LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI
687static int
688extract_uri_parameters(struct http_state *hs, char *params)
689{
690 char *pair;
691 char *equals;
692 int loop;
693
694 LWIP_UNUSED_ARG(hs);
695
696 /* If we have no parameters at all, return immediately. */
697 if (!params || (params[0] == '\0')) {
698 return (0);
699 }
700
701 /* Get a pointer to our first parameter */
702 pair = params;
703
704 /* Parse up to LWIP_HTTPD_MAX_CGI_PARAMETERS from the passed string and ignore the
705 * remainder (if any) */
706 for (loop = 0; (loop < LWIP_HTTPD_MAX_CGI_PARAMETERS) && pair; loop++) {
707
708 /* Save the name of the parameter */
709 http_cgi_params[loop] = pair;
710
711 /* Remember the start of this name=value pair */
712 equals = pair;
713
714 /* Find the start of the next name=value pair and replace the delimiter
715 * with a 0 to terminate the previous pair string. */
716 pair = strchr(pair, '&');
717 if (pair) {
718 *pair = '\0';
719 pair++;
720 } else {
721 /* We didn't find a new parameter so find the end of the URI and
722 * replace the space with a '\0' */
723 pair = strchr(equals, ' ');
724 if (pair) {
725 *pair = '\0';
726 }
727
728 /* Revert to NULL so that we exit the loop as expected. */
729 pair = NULL;
730 }
731
732 /* Now find the '=' in the previous pair, replace it with '\0' and save
733 * the parameter value string. */
734 equals = strchr(equals, '=');
735 if (equals) {
736 *equals = '\0';
737 http_cgi_param_vals[loop] = equals + 1;
738 } else {
739 http_cgi_param_vals[loop] = NULL;
740 }
741 }
742
743 return loop;
744}
745#endif /* LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI */
746
747#if LWIP_HTTPD_SSI
758static void
759get_tag_insert(struct http_state *hs)
760{
761#if LWIP_HTTPD_SSI_RAW
762 const char *tag;
763#else /* LWIP_HTTPD_SSI_RAW */
764 int tag;
765#endif /* LWIP_HTTPD_SSI_RAW */
766 size_t len;
767 struct http_ssi_state *ssi;
768#if LWIP_HTTPD_SSI_MULTIPART
769 u16_t current_tag_part;
770#endif /* LWIP_HTTPD_SSI_MULTIPART */
771
772 LWIP_ASSERT("hs != NULL", hs != NULL);
773 ssi = hs->ssi;
774 LWIP_ASSERT("ssi != NULL", ssi != NULL);
775#if LWIP_HTTPD_SSI_MULTIPART
776 current_tag_part = ssi->tag_part;
777 ssi->tag_part = HTTPD_LAST_TAG_PART;
778#endif /* LWIP_HTTPD_SSI_MULTIPART */
779#if LWIP_HTTPD_SSI_RAW
780 tag = ssi->tag_name;
781#endif
782
783 if (httpd_ssi_handler
785 && httpd_tags && httpd_num_tags
786#endif /* !LWIP_HTTPD_SSI_RAW */
787 ) {
788
789 /* Find this tag in the list we have been provided. */
790#if LWIP_HTTPD_SSI_RAW
791 {
792#else /* LWIP_HTTPD_SSI_RAW */
793 for (tag = 0; tag < httpd_num_tags; tag++) {
794 if (strcmp(ssi->tag_name, httpd_tags[tag]) == 0)
795#endif /* LWIP_HTTPD_SSI_RAW */
796 {
797 ssi->tag_insert_len = httpd_ssi_handler(tag, ssi->tag_insert,
800 , current_tag_part, &ssi->tag_part
801#endif /* LWIP_HTTPD_SSI_MULTIPART */
803 , (hs->handle ? hs->handle->state : NULL)
804#endif /* LWIP_HTTPD_FILE_STATE */
805 );
806#if LWIP_HTTPD_SSI_RAW
807 if (ssi->tag_insert_len != HTTPD_SSI_TAG_UNKNOWN)
808#endif /* LWIP_HTTPD_SSI_RAW */
809 {
810 return;
811 }
812 }
813 }
814 }
815
816 /* If we drop out, we were asked to serve a page which contains tags that
817 * we don't have a handler for. Merely echo back the tags with an error
818 * marker. */
819#define UNKNOWN_TAG1_TEXT "<b>***UNKNOWN TAG "
820#define UNKNOWN_TAG1_LEN 18
821#define UNKNOWN_TAG2_TEXT "***</b>"
822#define UNKNOWN_TAG2_LEN 7
823 len = LWIP_MIN(sizeof(ssi->tag_name), LWIP_MIN(strlen(ssi->tag_name),
824 LWIP_HTTPD_MAX_TAG_INSERT_LEN - (UNKNOWN_TAG1_LEN + UNKNOWN_TAG2_LEN)));
825 MEMCPY(ssi->tag_insert, UNKNOWN_TAG1_TEXT, UNKNOWN_TAG1_LEN);
826 MEMCPY(&ssi->tag_insert[UNKNOWN_TAG1_LEN], ssi->tag_name, len);
827 MEMCPY(&ssi->tag_insert[UNKNOWN_TAG1_LEN + len], UNKNOWN_TAG2_TEXT, UNKNOWN_TAG2_LEN);
828 ssi->tag_insert[UNKNOWN_TAG1_LEN + len + UNKNOWN_TAG2_LEN] = 0;
829
830 len = strlen(ssi->tag_insert);
831 LWIP_ASSERT("len <= 0xffff", len <= 0xffff);
832 ssi->tag_insert_len = (u16_t)len;
833}
834#endif /* LWIP_HTTPD_SSI */
835
836#if LWIP_HTTPD_DYNAMIC_HEADERS
841static void
842get_http_headers(struct http_state *hs, const char *uri)
843{
844 size_t content_type;
845 char *tmp;
846 char *ext;
847 char *vars;
848
849 /* In all cases, the second header we send is the server identification
850 so set it here. */
851 hs->hdrs[HDR_STRINGS_IDX_SERVER_NAME] = g_psHTTPHeaderStrings[HTTP_HDR_SERVER];
852 hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEEPALIVE] = NULL;
853 hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_NR] = NULL;
854
855 /* Is this a normal file or the special case we use to send back the
856 default "404: Page not found" response? */
857 if (uri == NULL) {
858 hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND];
859#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
860 if (hs->keepalive) {
861 hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = g_psHTTPHeaderStrings[DEFAULT_404_HTML_PERSISTENT];
862 } else
863#endif
864 {
865 hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = g_psHTTPHeaderStrings[DEFAULT_404_HTML];
866 }
867
868 /* Set up to send the first header string. */
869 hs->hdr_index = 0;
870 hs->hdr_pos = 0;
871 return;
872 }
873 /* We are dealing with a particular filename. Look for one other
874 special case. We assume that any filename with "404" in it must be
875 indicative of a 404 server error whereas all other files require
876 the 200 OK header. */
877 if (memcmp(uri, "/404.", 5) == 0) {
878 hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND];
879 } else if (memcmp(uri, "/400.", 5) == 0) {
880 hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_BAD_REQUEST];
881 } else if (memcmp(uri, "/501.", 5) == 0) {
882 hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_IMPL];
883 } else {
884 hs->hdrs[HDR_STRINGS_IDX_HTTP_STATUS] = g_psHTTPHeaderStrings[HTTP_HDR_OK];
885 }
886
887 /* Determine if the URI has any variables and, if so, temporarily remove
888 them. */
889 vars = strchr(uri, '?');
890 if (vars) {
891 *vars = '\0';
892 }
893
894 /* Get a pointer to the file extension. We find this by looking for the
895 last occurrence of "." in the filename passed. */
896 ext = NULL;
897 tmp = strchr(uri, '.');
898 while (tmp) {
899 ext = tmp + 1;
900 tmp = strchr(ext, '.');
901 }
902 if (ext != NULL) {
903 /* Now determine the content type and add the relevant header for that. */
904 for (content_type = 0; content_type < NUM_HTTP_HEADERS; content_type++) {
905 /* Have we found a matching extension? */
906 if (!lwip_stricmp(g_psHTTPHeaders[content_type].extension, ext)) {
907 break;
908 }
909 }
910 } else {
911 content_type = NUM_HTTP_HEADERS;
912 }
913
914 /* Reinstate the parameter marker if there was one in the original URI. */
915 if (vars) {
916 *vars = '?';
917 }
918
919#if LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI
920 /* Does the URL passed have any file extension? If not, we assume it
921 is a special-case URL used for control state notification and we do
922 not send any HTTP headers with the response. */
923 if (!ext) {
924 /* Force the header index to a value indicating that all headers
925 have already been sent. */
926 hs->hdr_index = NUM_FILE_HDR_STRINGS;
927 return;
928 }
929#endif /* LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI */
930 /* Did we find a matching extension? */
931 if (content_type < NUM_HTTP_HEADERS) {
932 /* yes, store it */
933 hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = g_psHTTPHeaders[content_type].content_type;
934 } else if (!ext) {
935 /* no, no extension found -> use binary transfer to prevent the browser adding '.txt' on save */
936 hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = HTTP_HDR_APP;
937 } else {
938 /* No - use the default, plain text file type. */
939 hs->hdrs[HDR_STRINGS_IDX_CONTENT_TYPE] = HTTP_HDR_DEFAULT_TYPE;
940 }
941 /* Set up to send the first header string. */
942 hs->hdr_index = 0;
943 hs->hdr_pos = 0;
944}
945
946/* Add content-length header? */
947static void
948get_http_content_length(struct http_state *hs)
949{
950 u8_t add_content_len = 0;
951
952 LWIP_ASSERT("already been here?", hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEEPALIVE] == NULL);
953
954 add_content_len = 0;
955#if LWIP_HTTPD_SSI
956 if (hs->ssi == NULL) /* @todo: get maximum file length from SSI */
957#endif /* LWIP_HTTPD_SSI */
958 {
959 if ((hs->handle != NULL) && (hs->handle->flags & FS_FILE_FLAGS_HEADER_PERSISTENT)) {
960 add_content_len = 1;
961 }
962 }
963 if (add_content_len) {
964 size_t len;
965 lwip_itoa(hs->hdr_content_len, (size_t)LWIP_HTTPD_MAX_CONTENT_LEN_SIZE,
966 hs->handle->len);
967 len = strlen(hs->hdr_content_len);
968 if (len <= LWIP_HTTPD_MAX_CONTENT_LEN_SIZE - LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET) {
969 SMEMCPY(&hs->hdr_content_len[len], CRLF, 3);
970 hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_NR] = hs->hdr_content_len;
971 } else {
972 add_content_len = 0;
973 }
974 }
975#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
976 if (add_content_len) {
977 hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEEPALIVE] = g_psHTTPHeaderStrings[HTTP_HDR_KEEPALIVE_LEN];
978 } else {
979 hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEEPALIVE] = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE];
980 hs->keepalive = 0;
981 }
982#else /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
983 if (add_content_len) {
984 hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEEPALIVE] = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH];
985 }
986#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
987}
988
997static u8_t
998http_send_headers(struct altcp_pcb *pcb, struct http_state *hs)
999{
1000 err_t err;
1001 u16_t len;
1002 u8_t data_to_send = HTTP_NO_DATA_TO_SEND;
1003 u16_t hdrlen, sendlen;
1004
1005 if (hs->hdrs[HDR_STRINGS_IDX_CONTENT_LEN_KEEPALIVE] == NULL) {
1006 /* set up "content-length" and "connection:" headers */
1007 get_http_content_length(hs);
1008 }
1009
1010 /* How much data can we send? */
1011 len = altcp_sndbuf(pcb);
1012 sendlen = len;
1013
1014 while (len && (hs->hdr_index < NUM_FILE_HDR_STRINGS) && sendlen) {
1015 const void *ptr;
1016 u16_t old_sendlen;
1017 u8_t apiflags;
1018 /* How much do we have to send from the current header? */
1019 hdrlen = (u16_t)strlen(hs->hdrs[hs->hdr_index]);
1020
1021 /* How much of this can we send? */
1022 sendlen = (len < (hdrlen - hs->hdr_pos)) ? len : (hdrlen - hs->hdr_pos);
1023
1024 /* Send this amount of data or as much as we can given memory
1025 * constraints. */
1026 ptr = (const void *)(hs->hdrs[hs->hdr_index] + hs->hdr_pos);
1027 old_sendlen = sendlen;
1028 apiflags = HTTP_IS_HDR_VOLATILE(hs, ptr);
1029 if (hs->hdr_index == HDR_STRINGS_IDX_CONTENT_LEN_NR) {
1030 /* content-length is always volatile */
1031 apiflags |= TCP_WRITE_FLAG_COPY;
1032 }
1033 if (hs->hdr_index < NUM_FILE_HDR_STRINGS - 1) {
1034 apiflags |= TCP_WRITE_FLAG_MORE;
1035 }
1036 err = http_write(pcb, ptr, &sendlen, apiflags);
1037 if ((err == ERR_OK) && (old_sendlen != sendlen)) {
1038 /* Remember that we added some more data to be transmitted. */
1039 data_to_send = HTTP_DATA_TO_SEND_CONTINUE;
1040 } else if (err != ERR_OK) {
1041 /* special case: http_write does not try to send 1 byte */
1042 sendlen = 0;
1043 }
1044
1045 /* Fix up the header position for the next time round. */
1046 hs->hdr_pos += sendlen;
1047 len -= sendlen;
1048
1049 /* Have we finished sending this string? */
1050 if (hs->hdr_pos == hdrlen) {
1051 /* Yes - move on to the next one */
1052 hs->hdr_index++;
1053 /* skip headers that are NULL (not all headers are required) */
1054 while ((hs->hdr_index < NUM_FILE_HDR_STRINGS) &&
1055 (hs->hdrs[hs->hdr_index] == NULL)) {
1056 hs->hdr_index++;
1057 }
1058 hs->hdr_pos = 0;
1059 }
1060 }
1061
1062 if ((hs->hdr_index >= NUM_FILE_HDR_STRINGS) && (hs->file == NULL)) {
1063 /* When we are at the end of the headers, check for data to send
1064 * instead of waiting for ACK from remote side to continue
1065 * (which would happen when sending files from async read). */
1066 if (http_check_eof(pcb, hs)) {
1067 data_to_send = HTTP_DATA_TO_SEND_BREAK;
1068 } else {
1069 /* At this point, for non-keepalive connections, hs is deallocated an
1070 pcb is closed. */
1071 return HTTP_DATA_TO_SEND_FREED;
1072 }
1073 }
1074 /* If we get here and there are still header bytes to send, we send
1075 * the header information we just wrote immediately. If there are no
1076 * more headers to send, but we do have file data to send, drop through
1077 * to try to send some file data too. */
1078 if ((hs->hdr_index < NUM_FILE_HDR_STRINGS) || !hs->file) {
1079 LWIP_DEBUGF(HTTPD_DEBUG, ("tcp_output\n"));
1080 return HTTP_DATA_TO_SEND_BREAK;
1081 }
1082 return data_to_send;
1083}
1084#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
1085
1092static u8_t
1093http_check_eof(struct altcp_pcb *pcb, struct http_state *hs)
1094{
1095 int bytes_left;
1096#if LWIP_HTTPD_DYNAMIC_FILE_READ
1097 int count;
1098#ifdef HTTPD_MAX_WRITE_LEN
1099 int max_write_len;
1100#endif /* HTTPD_MAX_WRITE_LEN */
1101#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
1102
1103 /* Do we have a valid file handle? */
1104 if (hs->handle == NULL) {
1105 /* No - close the connection. */
1106 http_eof(pcb, hs);
1107 return 0;
1108 }
1109 bytes_left = fs_bytes_left(hs->handle);
1110 if (bytes_left <= 0) {
1111 /* We reached the end of the file so this request is done. */
1112 LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
1113 http_eof(pcb, hs);
1114 return 0;
1115 }
1116#if LWIP_HTTPD_DYNAMIC_FILE_READ
1117 /* Do we already have a send buffer allocated? */
1118 if (hs->buf) {
1119 /* Yes - get the length of the buffer */
1120 count = LWIP_MIN(hs->buf_len, bytes_left);
1121 } else {
1122 /* We don't have a send buffer so allocate one now */
1123 count = altcp_sndbuf(pcb);
1124 if (bytes_left < count) {
1125 count = bytes_left;
1126 }
1127#ifdef HTTPD_MAX_WRITE_LEN
1128 /* Additional limitation: e.g. don't enqueue more than 2*mss at once */
1129 max_write_len = HTTPD_MAX_WRITE_LEN(pcb);
1130 if (count > max_write_len) {
1131 count = max_write_len;
1132 }
1133#endif /* HTTPD_MAX_WRITE_LEN */
1134 do {
1135 hs->buf = (char *)mem_malloc((mem_size_t)count);
1136 if (hs->buf != NULL) {
1137 hs->buf_len = count;
1138 break;
1139 }
1140 count = count / 2;
1141 } while (count > 100);
1142
1143 /* Did we get a send buffer? If not, return immediately. */
1144 if (hs->buf == NULL) {
1145 LWIP_DEBUGF(HTTPD_DEBUG, ("No buff\n"));
1146 return 0;
1147 }
1148 }
1149
1150 /* Read a block of data from the file. */
1151 LWIP_DEBUGF(HTTPD_DEBUG, ("Trying to read %d bytes.\n", count));
1152
1153#if LWIP_HTTPD_FS_ASYNC_READ
1154 count = fs_read_async(hs->handle, hs->buf, count, http_continue, hs);
1155#else /* LWIP_HTTPD_FS_ASYNC_READ */
1156 count = fs_read(hs->handle, hs->buf, count);
1157#endif /* LWIP_HTTPD_FS_ASYNC_READ */
1158 if (count < 0) {
1159 if (count == FS_READ_DELAYED) {
1160 /* Delayed read, wait for FS to unblock us */
1161 return 0;
1162 }
1163 /* We reached the end of the file so this request is done.
1164 * @todo: close here for HTTP/1.1 when reading file fails */
1165 LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
1166 http_eof(pcb, hs);
1167 return 0;
1168 }
1169
1170 /* Set up to send the block of data we just read */
1171 LWIP_DEBUGF(HTTPD_DEBUG, ("Read %d bytes.\n", count));
1172 hs->left = count;
1173 hs->file = hs->buf;
1174#if LWIP_HTTPD_SSI
1175 if (hs->ssi) {
1176 hs->ssi->parse_left = count;
1177 hs->ssi->parsed = hs->buf;
1178 }
1179#endif /* LWIP_HTTPD_SSI */
1180#else /* LWIP_HTTPD_DYNAMIC_FILE_READ */
1181 LWIP_ASSERT("SSI and DYNAMIC_HEADERS turned off but eof not reached", 0);
1182#endif /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */
1183 return 1;
1184}
1185
1191static u8_t
1192http_send_data_nonssi(struct altcp_pcb *pcb, struct http_state *hs)
1193{
1194 err_t err;
1195 u16_t len;
1196 u8_t data_to_send = 0;
1197
1198 /* We are not processing an SHTML file so no tag checking is necessary.
1199 * Just send the data as we received it from the file. */
1200 len = (u16_t)LWIP_MIN(hs->left, 0xffff);
1201
1202 err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1203 if (err == ERR_OK) {
1204 data_to_send = 1;
1205 hs->file += len;
1206 hs->left -= len;
1207 }
1208
1209 return data_to_send;
1210}
1211
1212#if LWIP_HTTPD_SSI
1218static u8_t
1219http_send_data_ssi(struct altcp_pcb *pcb, struct http_state *hs)
1220{
1221 err_t err = ERR_OK;
1222 u16_t len;
1223 u8_t data_to_send = 0;
1224 u8_t tag_type;
1225
1226 struct http_ssi_state *ssi = hs->ssi;
1227 LWIP_ASSERT("ssi != NULL", ssi != NULL);
1228 /* We are processing an SHTML file so need to scan for tags and replace
1229 * them with insert strings. We need to be careful here since a tag may
1230 * straddle the boundary of two blocks read from the file and we may also
1231 * have to split the insert string between two tcp_write operations. */
1232
1233 /* How much data could we send? */
1234 len = altcp_sndbuf(pcb);
1235
1236 /* Do we have remaining data to send before parsing more? */
1237 if (ssi->parsed > hs->file) {
1238 len = (u16_t)LWIP_MIN(ssi->parsed - hs->file, 0xffff);
1239
1240 err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1241 if (err == ERR_OK) {
1242 data_to_send = 1;
1243 hs->file += len;
1244 hs->left -= len;
1245 }
1246
1247 /* If the send buffer is full, return now. */
1248 if (altcp_sndbuf(pcb) == 0) {
1249 return data_to_send;
1250 }
1251 }
1252
1253 LWIP_DEBUGF(HTTPD_DEBUG, ("State %d, %d left\n", ssi->tag_state, (int)ssi->parse_left));
1254
1255 /* We have sent all the data that was already parsed so continue parsing
1256 * the buffer contents looking for SSI tags. */
1257 while (((ssi->tag_state == TAG_SENDING) || ssi->parse_left) && (err == ERR_OK)) {
1258 if (len == 0) {
1259 return data_to_send;
1260 }
1261 switch (ssi->tag_state) {
1262 case TAG_NONE:
1263 /* We are not currently processing an SSI tag so scan for the
1264 * start of the lead-in marker. */
1265 for (tag_type = 0; tag_type < LWIP_ARRAYSIZE(http_ssi_tag_desc); tag_type++) {
1266 if (*ssi->parsed == http_ssi_tag_desc[tag_type].lead_in[0]) {
1267 /* We found what could be the lead-in for a new tag so change
1268 * state appropriately. */
1269 ssi->tag_type = tag_type;
1270 ssi->tag_state = TAG_LEADIN;
1271 ssi->tag_index = 1;
1272 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
1273 ssi->tag_started = ssi->parsed;
1274 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */
1275 break;
1276 }
1277 }
1278
1279 /* Move on to the next character in the buffer */
1280 ssi->parse_left--;
1281 ssi->parsed++;
1282 break;
1283
1284 case TAG_LEADIN:
1285 /* We are processing the lead-in marker, looking for the start of
1286 * the tag name. */
1287
1288 /* Have we reached the end of the leadin? */
1289 if (http_ssi_tag_desc[ssi->tag_type].lead_in[ssi->tag_index] == 0) {
1290 ssi->tag_index = 0;
1291 ssi->tag_state = TAG_FOUND;
1292 } else {
1293 /* Have we found the next character we expect for the tag leadin? */
1294 if (*ssi->parsed == http_ssi_tag_desc[ssi->tag_type].lead_in[ssi->tag_index]) {
1295 /* Yes - move to the next one unless we have found the complete
1296 * leadin, in which case we start looking for the tag itself */
1297 ssi->tag_index++;
1298 } else {
1299 /* We found an unexpected character so this is not a tag. Move
1300 * back to idle state. */
1301 ssi->tag_state = TAG_NONE;
1302 }
1303
1304#if LWIP_HTTPD_DYNAMIC_FILE_READ && !LWIP_HTTPD_SSI_INCLUDE_TAG
1305 if ((ssi->tag_state == TAG_NONE) &&
1306 (ssi->parsed - hs->file < ssi->tag_index)) {
1307 for(u16_t i = 0;i < ssi->tag_index;i++) {
1308 ssi->tag_insert[i] = http_ssi_tag_desc[ssi->tag_type].lead_in[i];
1309 }
1310 ssi->tag_insert_len = ssi->tag_index;
1311 hs->file += ssi->parsed - hs->file;
1312 hs->left -= ssi->parsed - hs->file;
1313 ssi->tag_end = hs->file;
1314 ssi->tag_index = 0;
1315 ssi->tag_state = TAG_SENDING;
1316 break;
1317 }
1318#endif
1319
1320 /* Move on to the next character in the buffer */
1321 ssi->parse_left--;
1322 ssi->parsed++;
1323 }
1324 break;
1325
1326 case TAG_FOUND:
1327 /* We are reading the tag name, looking for the start of the
1328 * lead-out marker and removing any whitespace found. */
1329
1330 /* Remove leading whitespace between the tag leading and the first
1331 * tag name character. */
1332 if ((ssi->tag_index == 0) && ((*ssi->parsed == ' ') ||
1333 (*ssi->parsed == '\t') || (*ssi->parsed == '\n') ||
1334 (*ssi->parsed == '\r'))) {
1335 /* Move on to the next character in the buffer */
1336 ssi->parse_left--;
1337 ssi->parsed++;
1338 break;
1339 }
1340
1341 /* Have we found the end of the tag name? This is signalled by
1342 * us finding the first leadout character or whitespace */
1343 if ((*ssi->parsed == http_ssi_tag_desc[ssi->tag_type].lead_out[0]) ||
1344 (*ssi->parsed == ' ') || (*ssi->parsed == '\t') ||
1345 (*ssi->parsed == '\n') || (*ssi->parsed == '\r')) {
1346
1347 if (ssi->tag_index == 0) {
1348 /* We read a zero length tag so ignore it. */
1349 ssi->tag_state = TAG_NONE;
1350 } else {
1351 /* We read a non-empty tag so go ahead and look for the
1352 * leadout string. */
1353 ssi->tag_state = TAG_LEADOUT;
1354 LWIP_ASSERT("ssi->tag_index <= 0xff", ssi->tag_index <= 0xff);
1355 ssi->tag_name_len = (u8_t)ssi->tag_index;
1356 ssi->tag_name[ssi->tag_index] = '\0';
1357 if (*ssi->parsed == http_ssi_tag_desc[ssi->tag_type].lead_out[0]) {
1358 ssi->tag_index = 1;
1359 } else {
1360 ssi->tag_index = 0;
1361 }
1362 }
1363 } else {
1364 /* This character is part of the tag name so save it */
1365 if (ssi->tag_index < LWIP_HTTPD_MAX_TAG_NAME_LEN) {
1366 ssi->tag_name[ssi->tag_index++] = *ssi->parsed;
1367 } else {
1368 /* The tag was too long so ignore it. */
1369 ssi->tag_state = TAG_NONE;
1370 }
1371 }
1372
1373 /* Move on to the next character in the buffer */
1374 ssi->parse_left--;
1375 ssi->parsed++;
1376
1377 break;
1378
1379 /* We are looking for the end of the lead-out marker. */
1380 case TAG_LEADOUT:
1381 /* Remove leading whitespace between the tag leading and the first
1382 * tag leadout character. */
1383 if ((ssi->tag_index == 0) && ((*ssi->parsed == ' ') ||
1384 (*ssi->parsed == '\t') || (*ssi->parsed == '\n') ||
1385 (*ssi->parsed == '\r'))) {
1386 /* Move on to the next character in the buffer */
1387 ssi->parse_left--;
1388 ssi->parsed++;
1389 break;
1390 }
1391
1392 /* Have we found the next character we expect for the tag leadout? */
1393 if (*ssi->parsed == http_ssi_tag_desc[ssi->tag_type].lead_out[ssi->tag_index]) {
1394 /* Yes - move to the next one unless we have found the complete
1395 * leadout, in which case we need to call the client to process
1396 * the tag. */
1397
1398 /* Move on to the next character in the buffer */
1399 ssi->parse_left--;
1400 ssi->parsed++;
1401 ssi->tag_index++;
1402
1403 if (http_ssi_tag_desc[ssi->tag_type].lead_out[ssi->tag_index] == 0) {
1404 /* Call the client to ask for the insert string for the
1405 * tag we just found. */
1406#if LWIP_HTTPD_SSI_MULTIPART
1407 ssi->tag_part = 0; /* start with tag part 0 */
1408#endif /* LWIP_HTTPD_SSI_MULTIPART */
1409 get_tag_insert(hs);
1410
1411 /* Next time through, we are going to be sending data
1412 * immediately, either the end of the block we start
1413 * sending here or the insert string. */
1414 ssi->tag_index = 0;
1415 ssi->tag_state = TAG_SENDING;
1416 ssi->tag_end = ssi->parsed;
1417#if !LWIP_HTTPD_SSI_INCLUDE_TAG
1418 ssi->parsed = ssi->tag_started;
1419#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
1420
1421 /* If there is any unsent data in the buffer prior to the
1422 * tag, we need to send it now. */
1423 if (ssi->tag_end > hs->file) {
1424 /* How much of the data can we send? */
1425#if LWIP_HTTPD_SSI_INCLUDE_TAG
1426 len = (u16_t)LWIP_MIN(ssi->tag_end - hs->file, 0xffff);
1427#else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
1428 /* we would include the tag in sending */
1429 len = (u16_t)LWIP_MIN(ssi->tag_started - hs->file, 0xffff);
1430#endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
1431
1432 err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1433 if (err == ERR_OK) {
1434 data_to_send = 1;
1435#if !LWIP_HTTPD_SSI_INCLUDE_TAG
1436 if (ssi->tag_started <= hs->file) {
1437 /* pretend to have sent the tag, too */
1438 len += (u16_t)(ssi->tag_end - ssi->tag_started);
1439 }
1440#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
1441 hs->file += len;
1442 hs->left -= len;
1443 }
1444 }
1445 }
1446 } else {
1447 /* We found an unexpected character so this is not a tag. Move
1448 * back to idle state. */
1449 ssi->parse_left--;
1450 ssi->parsed++;
1451 ssi->tag_state = TAG_NONE;
1452 }
1453 break;
1454
1455 /*
1456 * We have found a valid tag and are in the process of sending
1457 * data as a result of that discovery. We send either remaining data
1458 * from the file prior to the insert point or the insert string itself.
1459 */
1460 case TAG_SENDING:
1461 /* Do we have any remaining file data to send from the buffer prior
1462 * to the tag? */
1463 if (ssi->tag_end > hs->file) {
1464 /* How much of the data can we send? */
1465#if LWIP_HTTPD_SSI_INCLUDE_TAG
1466 len = (u16_t)LWIP_MIN(ssi->tag_end - hs->file, 0xffff);
1467#else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
1468 LWIP_ASSERT("hs->started >= hs->file", ssi->tag_started >= hs->file);
1469 /* we would include the tag in sending */
1470 len = (u16_t)LWIP_MIN(ssi->tag_started - hs->file, 0xffff);
1471#endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
1472 if (len != 0) {
1473 err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1474 } else {
1475 err = ERR_OK;
1476 }
1477 if (err == ERR_OK) {
1478 data_to_send = 1;
1479#if !LWIP_HTTPD_SSI_INCLUDE_TAG
1480 if (ssi->tag_started <= hs->file) {
1481 /* pretend to have sent the tag, too */
1482 len += (u16_t)(ssi->tag_end - ssi->tag_started);
1483 }
1484#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
1485 hs->file += len;
1486 hs->left -= len;
1487 }
1488 } else {
1489#if LWIP_HTTPD_SSI_MULTIPART
1490 if (ssi->tag_index >= ssi->tag_insert_len) {
1491 /* Did the last SSIHandler have more to send? */
1492 if (ssi->tag_part != HTTPD_LAST_TAG_PART) {
1493 /* If so, call it again */
1494 ssi->tag_index = 0;
1495 get_tag_insert(hs);
1496 }
1497 }
1498#endif /* LWIP_HTTPD_SSI_MULTIPART */
1499
1500 /* Do we still have insert data left to send? */
1501 if (ssi->tag_index < ssi->tag_insert_len) {
1502 /* We are sending the insert string itself. How much of the
1503 * insert can we send? */
1504 len = (ssi->tag_insert_len - ssi->tag_index);
1505
1506 /* Note that we set the copy flag here since we only have a
1507 * single tag insert buffer per connection. If we don't do
1508 * this, insert corruption can occur if more than one insert
1509 * is processed before we call tcp_output. */
1510 err = http_write(pcb, &(ssi->tag_insert[ssi->tag_index]), &len,
1512 if (err == ERR_OK) {
1513 data_to_send = 1;
1514 ssi->tag_index += len;
1515 /* Don't return here: keep on sending data */
1516 }
1517 } else {
1518#if LWIP_HTTPD_SSI_MULTIPART
1519 if (ssi->tag_part == HTTPD_LAST_TAG_PART)
1520#endif /* LWIP_HTTPD_SSI_MULTIPART */
1521 {
1522 /* We have sent all the insert data so go back to looking for
1523 * a new tag. */
1524 LWIP_DEBUGF(HTTPD_DEBUG, ("Everything sent.\n"));
1525 ssi->tag_index = 0;
1526 ssi->tag_state = TAG_NONE;
1527#if !LWIP_HTTPD_SSI_INCLUDE_TAG
1528 ssi->parsed = ssi->tag_end;
1529#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
1530 }
1531 }
1532 break;
1533 default:
1534 break;
1535 }
1536 }
1537 }
1538
1539 /* If we drop out of the end of the for loop, this implies we must have
1540 * file data to send so send it now. In TAG_SENDING state, we've already
1541 * handled this so skip the send if that's the case. */
1542 if ((ssi->tag_state != TAG_SENDING) && (ssi->parsed > hs->file)) {
1543#if LWIP_HTTPD_DYNAMIC_FILE_READ && !LWIP_HTTPD_SSI_INCLUDE_TAG
1544 if ((ssi->tag_state != TAG_NONE) && (ssi->tag_started > ssi->tag_end)) {
1545 /* If we found tag on the edge of the read buffer: just throw away the first part
1546 (we have copied/saved everything required for parsing on later). */
1547 len = (u16_t)(ssi->tag_started - hs->file);
1548 hs->left -= (ssi->parsed - ssi->tag_started);
1549 ssi->parsed = ssi->tag_started;
1550 ssi->tag_started = hs->buf;
1551 } else
1552#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ && !LWIP_HTTPD_SSI_INCLUDE_TAG */
1553 {
1554 len = (u16_t)LWIP_MIN(ssi->parsed - hs->file, 0xffff);
1555 }
1556
1557 err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1558 if (err == ERR_OK) {
1559 data_to_send = 1;
1560 hs->file += len;
1561 hs->left -= len;
1562 }
1563 }
1564 return data_to_send;
1565}
1566#endif /* LWIP_HTTPD_SSI */
1567
1574static u8_t
1575http_send(struct altcp_pcb *pcb, struct http_state *hs)
1576{
1577 u8_t data_to_send = HTTP_NO_DATA_TO_SEND;
1578
1579 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_send: pcb=%p hs=%p left=%d\n", (void *)pcb,
1580 (void *)hs, hs != NULL ? (int)hs->left : 0));
1581
1582#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
1583 if (hs->unrecved_bytes != 0) {
1584 return 0;
1585 }
1586#endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
1587
1588 /* If we were passed a NULL state structure pointer, ignore the call. */
1589 if (hs == NULL) {
1590 return 0;
1591 }
1592
1593#if LWIP_HTTPD_FS_ASYNC_READ
1594 /* Check if we are allowed to read from this file.
1595 (e.g. SSI might want to delay sending until data is available) */
1596 if (!fs_is_file_ready(hs->handle, http_continue, hs)) {
1597 return 0;
1598 }
1599#endif /* LWIP_HTTPD_FS_ASYNC_READ */
1600
1601#if LWIP_HTTPD_DYNAMIC_HEADERS
1602 /* Do we have any more header data to send for this file? */
1603 if (hs->hdr_index < NUM_FILE_HDR_STRINGS) {
1604 data_to_send = http_send_headers(pcb, hs);
1605 if ((data_to_send == HTTP_DATA_TO_SEND_FREED) ||
1606 ((data_to_send != HTTP_DATA_TO_SEND_CONTINUE) &&
1607 (hs->hdr_index < NUM_FILE_HDR_STRINGS))) {
1608 return data_to_send;
1609 }
1610 }
1611#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
1612
1613#if LWIP_HTTPD_SSI
1614 if (hs->ssi && (hs->ssi->tag_state == TAG_SENDING)) {
1615 /* do not check the condition below */
1616 } else
1617#endif
1618 /* Have we run out of file data to send? If so, we need to read the next
1619 * block from the file. */
1620 if (hs->left == 0) {
1621 if (!http_check_eof(pcb, hs)) {
1622 return 0;
1623 }
1624 }
1625
1626#if LWIP_HTTPD_SSI
1627 if (hs->ssi) {
1628 data_to_send = http_send_data_ssi(pcb, hs);
1629 if (hs->ssi->tag_state == TAG_SENDING) {
1630 return data_to_send;
1631 }
1632 } else
1633#endif /* LWIP_HTTPD_SSI */
1634 {
1635 data_to_send = http_send_data_nonssi(pcb, hs);
1636 }
1637
1638 if ((hs->left == 0) && (fs_bytes_left(hs->handle) <= 0)) {
1639 /* We reached the end of the file so this request is done.
1640 * This adds the FIN flag right into the last data segment. */
1641 LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
1642 http_eof(pcb, hs);
1643 return 0;
1644 }
1645 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("send_data end.\n"));
1646 return data_to_send;
1647}
1648
1649#if LWIP_HTTPD_SUPPORT_EXTSTATUS
1657static err_t
1658http_find_error_file(struct http_state *hs, u16_t error_nr)
1659{
1660 const char *uri, *uri1, *uri2, *uri3;
1661
1662 if (error_nr == 501) {
1663 uri1 = "/501.html";
1664 uri2 = "/501.htm";
1665 uri3 = "/501.shtml";
1666 } else {
1667 /* 400 (bad request is the default) */
1668 uri1 = "/400.html";
1669 uri2 = "/400.htm";
1670 uri3 = "/400.shtml";
1671 }
1672 if (fs_open(&hs->file_handle, uri1) == ERR_OK) {
1673 uri = uri1;
1674 } else if (fs_open(&hs->file_handle, uri2) == ERR_OK) {
1675 uri = uri2;
1676 } else if (fs_open(&hs->file_handle, uri3) == ERR_OK) {
1677 uri = uri3;
1678 } else {
1679 LWIP_DEBUGF(HTTPD_DEBUG, ("Error page for error %"U16_F" not found\n",
1680 error_nr));
1681 return ERR_ARG;
1682 }
1683 return http_init_file(hs, &hs->file_handle, 0, uri, 0, NULL);
1684}
1685#else /* LWIP_HTTPD_SUPPORT_EXTSTATUS */
1686#define http_find_error_file(hs, error_nr) ERR_ARG
1687#endif /* LWIP_HTTPD_SUPPORT_EXTSTATUS */
1688
1696static struct fs_file *
1697http_get_404_file(struct http_state *hs, const char **uri)
1698{
1699 err_t err;
1700
1701 *uri = "/404.html";
1702 err = fs_open(&hs->file_handle, *uri);
1703 if (err != ERR_OK) {
1704 /* 404.html doesn't exist. Try 404.htm instead. */
1705 *uri = "/404.htm";
1706 err = fs_open(&hs->file_handle, *uri);
1707 if (err != ERR_OK) {
1708 /* 404.htm doesn't exist either. Try 404.shtml instead. */
1709 *uri = "/404.shtml";
1710 err = fs_open(&hs->file_handle, *uri);
1711 if (err != ERR_OK) {
1712 /* 404.htm doesn't exist either. Indicate to the caller that it should
1713 * send back a default 404 page.
1714 */
1715 *uri = NULL;
1716 return NULL;
1717 }
1718 }
1719 }
1720
1721 return &hs->file_handle;
1722}
1723
1724#if LWIP_HTTPD_SUPPORT_POST
1725static err_t
1726http_handle_post_finished(struct http_state *hs)
1727{
1728#if LWIP_HTTPD_POST_MANUAL_WND
1729 /* Prevent multiple calls to httpd_post_finished, since it might have already
1730 been called before from httpd_post_data_recved(). */
1731 if (hs->post_finished) {
1732 return ERR_OK;
1733 }
1734 hs->post_finished = 1;
1735#endif /* LWIP_HTTPD_POST_MANUAL_WND */
1736 /* application error or POST finished */
1737 /* NULL-terminate the buffer */
1738 http_uri_buf[0] = 0;
1739 httpd_post_finished(hs, http_uri_buf, LWIP_HTTPD_URI_BUF_LEN);
1740 return http_find_file(hs, http_uri_buf, 0);
1741}
1742
1752static err_t
1753http_post_rxpbuf(struct http_state *hs, struct pbuf *p)
1754{
1755 err_t err;
1756
1757 if (p != NULL) {
1758 /* adjust remaining Content-Length */
1759 if (hs->post_content_len_left < p->tot_len) {
1760 hs->post_content_len_left = 0;
1761 } else {
1762 hs->post_content_len_left -= p->tot_len;
1763 }
1764 }
1765#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
1766 /* prevent connection being closed if httpd_post_data_recved() is called nested */
1767 hs->unrecved_bytes++;
1768#endif
1769 if (p != NULL) {
1770 err = httpd_post_receive_data(hs, p);
1771 } else {
1772 err = ERR_OK;
1773 }
1774#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
1775 hs->unrecved_bytes--;
1776#endif
1777 if (err != ERR_OK) {
1778 /* Ignore remaining content in case of application error */
1779 hs->post_content_len_left = 0;
1780 }
1781 if (hs->post_content_len_left == 0) {
1782#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
1783 if (hs->unrecved_bytes != 0) {
1784 return ERR_OK;
1785 }
1786#endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
1787 /* application error or POST finished */
1788 return http_handle_post_finished(hs);
1789 }
1790
1791 return ERR_OK;
1792}
1793
1808static err_t
1809http_post_request(struct pbuf *inp, struct http_state *hs,
1810 char *data, u16_t data_len, char *uri, char *uri_end)
1811{
1812 err_t err;
1813 /* search for end-of-header (first double-CRLF) */
1814 char *crlfcrlf = lwip_strnstr(uri_end + 1, CRLF CRLF, data_len - (uri_end + 1 - data));
1815
1816 if (crlfcrlf != NULL) {
1817 /* search for "Content-Length: " */
1818#define HTTP_HDR_CONTENT_LEN "Content-Length: "
1819#define HTTP_HDR_CONTENT_LEN_LEN 16
1820#define HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN 10
1821 char *scontent_len = lwip_strnstr(uri_end + 1, HTTP_HDR_CONTENT_LEN, crlfcrlf - (uri_end + 1));
1822 if (scontent_len != NULL) {
1823 char *scontent_len_end = lwip_strnstr(scontent_len + HTTP_HDR_CONTENT_LEN_LEN, CRLF, HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN);
1824 if (scontent_len_end != NULL) {
1825 int content_len;
1826 char *content_len_num = scontent_len + HTTP_HDR_CONTENT_LEN_LEN;
1827 content_len = atoi(content_len_num);
1828 if (content_len == 0) {
1829 /* if atoi returns 0 on error, fix this */
1830 if ((content_len_num[0] != '0') || (content_len_num[1] != '\r')) {
1831 content_len = -1;
1832 }
1833 }
1834 if (content_len >= 0) {
1835 /* adjust length of HTTP header passed to application */
1836 const char *hdr_start_after_uri = uri_end + 1;
1837 u16_t hdr_len = (u16_t)LWIP_MIN(data_len, crlfcrlf + 4 - data);
1838 u16_t hdr_data_len = (u16_t)LWIP_MIN(data_len, crlfcrlf + 4 - hdr_start_after_uri);
1839 u8_t post_auto_wnd = 1;
1840 http_uri_buf[0] = 0;
1841 /* trim http header */
1842 *crlfcrlf = 0;
1843 err = httpd_post_begin(hs, uri, hdr_start_after_uri, hdr_data_len, content_len,
1844 http_uri_buf, LWIP_HTTPD_URI_BUF_LEN, &post_auto_wnd);
1845 if (err == ERR_OK) {
1846 /* try to pass in data of the first pbuf(s) */
1847 struct pbuf *q = inp;
1848 u16_t start_offset = hdr_len;
1849#if LWIP_HTTPD_POST_MANUAL_WND
1850 hs->no_auto_wnd = !post_auto_wnd;
1851#endif /* LWIP_HTTPD_POST_MANUAL_WND */
1852 /* set the Content-Length to be received for this POST */
1853 hs->post_content_len_left = (u32_t)content_len;
1854
1855 /* get to the pbuf where the body starts */
1856 while ((q != NULL) && (q->len <= start_offset)) {
1857 start_offset -= q->len;
1858 q = q->next;
1859 }
1860 if (q != NULL) {
1861 /* hide the remaining HTTP header */
1862 pbuf_remove_header(q, start_offset);
1863#if LWIP_HTTPD_POST_MANUAL_WND
1864 if (!post_auto_wnd) {
1865 /* already tcp_recved() this data... */
1866 hs->unrecved_bytes = q->tot_len;
1867 }
1868#endif /* LWIP_HTTPD_POST_MANUAL_WND */
1869 pbuf_ref(q);
1870 return http_post_rxpbuf(hs, q);
1871 } else if (hs->post_content_len_left == 0) {
1873 return http_post_rxpbuf(hs, q);
1874 } else {
1875 return ERR_OK;
1876 }
1877 } else {
1878 /* return file passed from application */
1879 return http_find_file(hs, http_uri_buf, 0);
1880 }
1881 } else {
1882 LWIP_DEBUGF(HTTPD_DEBUG, ("POST received invalid Content-Length: %s\n",
1883 content_len_num));
1884 return ERR_ARG;
1885 }
1886 }
1887 }
1888 /* If we come here, headers are fully received (double-crlf), but Content-Length
1889 was not included. Since this is currently the only supported method, we have
1890 to fail in this case! */
1891 LWIP_DEBUGF(HTTPD_DEBUG, ("Error when parsing Content-Length\n"));
1892 return ERR_ARG;
1893 }
1894 /* if we come here, the POST is incomplete */
1895#if LWIP_HTTPD_SUPPORT_REQUESTLIST
1896 return ERR_INPROGRESS;
1897#else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1898 return ERR_ARG;
1899#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1900}
1901
1902#if LWIP_HTTPD_POST_MANUAL_WND
1913void httpd_post_data_recved(void *connection, u16_t recved_len)
1914{
1915 struct http_state *hs = (struct http_state *)connection;
1916 if (hs != NULL) {
1917 if (hs->no_auto_wnd) {
1918 u16_t len = recved_len;
1919 if (hs->unrecved_bytes >= recved_len) {
1920 hs->unrecved_bytes -= recved_len;
1921 } else {
1922 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_LEVEL_WARNING, ("httpd_post_data_recved: recved_len too big\n"));
1923 len = (u16_t)hs->unrecved_bytes;
1924 hs->unrecved_bytes = 0;
1925 }
1926 if (hs->pcb != NULL) {
1927 if (len != 0) {
1928 altcp_recved(hs->pcb, len);
1929 }
1930 if ((hs->post_content_len_left == 0) && (hs->unrecved_bytes == 0)) {
1931 /* finished handling POST */
1932 http_handle_post_finished(hs);
1933 http_send(hs->pcb, hs);
1934 }
1935 }
1936 }
1937 }
1938}
1939#endif /* LWIP_HTTPD_POST_MANUAL_WND */
1940
1941#endif /* LWIP_HTTPD_SUPPORT_POST */
1942
1943#if LWIP_HTTPD_FS_ASYNC_READ
1947static void
1948http_continue(void *connection)
1949{
1950 struct http_state *hs = (struct http_state *)connection;
1952 if (hs && (hs->pcb) && (hs->handle)) {
1953 LWIP_ASSERT("hs->pcb != NULL", hs->pcb != NULL);
1954 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("httpd_continue: try to send more data\n"));
1955 if (http_send(hs->pcb, hs)) {
1956 /* If we wrote anything to be sent, go ahead and send it now. */
1957 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("tcp_output\n"));
1958 altcp_output(hs->pcb);
1959 }
1960 }
1961}
1962#endif /* LWIP_HTTPD_FS_ASYNC_READ */
1963
1975static err_t
1976http_parse_request(struct pbuf *inp, struct http_state *hs, struct altcp_pcb *pcb)
1977{
1978 char *data;
1979 char *crlf;
1980 u16_t data_len;
1981 struct pbuf *p = inp;
1982#if LWIP_HTTPD_SUPPORT_REQUESTLIST
1983 u16_t clen;
1984#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1985#if LWIP_HTTPD_SUPPORT_POST
1986 err_t err;
1987#endif /* LWIP_HTTPD_SUPPORT_POST */
1988
1989 LWIP_UNUSED_ARG(pcb); /* only used for post */
1990 LWIP_ASSERT("p != NULL", p != NULL);
1991 LWIP_ASSERT("hs != NULL", hs != NULL);
1992
1993 if ((hs->handle != NULL) || (hs->file != NULL)) {
1994 LWIP_DEBUGF(HTTPD_DEBUG, ("Received data while sending a file\n"));
1995 /* already sending a file */
1996 /* @todo: abort? */
1997 return ERR_USE;
1998 }
1999
2000#if LWIP_HTTPD_SUPPORT_REQUESTLIST
2001
2002 LWIP_DEBUGF(HTTPD_DEBUG, ("Received %"U16_F" bytes\n", p->tot_len));
2003
2004 /* first check allowed characters in this pbuf? */
2005
2006 /* enqueue the pbuf */
2007 if (hs->req == NULL) {
2008 LWIP_DEBUGF(HTTPD_DEBUG, ("First pbuf\n"));
2009 hs->req = p;
2010 } else {
2011 LWIP_DEBUGF(HTTPD_DEBUG, ("pbuf enqueued\n"));
2012 pbuf_cat(hs->req, p);
2013 }
2014 /* increase pbuf ref counter as it is freed when we return but we want to
2015 keep it on the req list */
2016 pbuf_ref(p);
2017
2018 if (hs->req->next != NULL) {
2019 data_len = LWIP_MIN(hs->req->tot_len, LWIP_HTTPD_MAX_REQ_LENGTH);
2020 pbuf_copy_partial(hs->req, httpd_req_buf, data_len, 0);
2021 data = httpd_req_buf;
2022 } else
2023#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
2024 {
2025 data = (char *)p->payload;
2026 data_len = p->len;
2027 if (p->len != p->tot_len) {
2028 LWIP_DEBUGF(HTTPD_DEBUG, ("Warning: incomplete header due to chained pbufs\n"));
2029 }
2030 }
2031
2032 /* received enough data for minimal request? */
2033 if (data_len >= MIN_REQ_LEN) {
2034 /* wait for CRLF before parsing anything */
2035 crlf = lwip_strnstr(data, CRLF, data_len);
2036 if (crlf != NULL) {
2037#if LWIP_HTTPD_SUPPORT_POST
2038 int is_post = 0;
2039#endif /* LWIP_HTTPD_SUPPORT_POST */
2040 int is_09 = 0;
2041 char *sp1, *sp2;
2042 u16_t left_len, uri_len;
2043 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("CRLF received, parsing request\n"));
2044 /* parse method */
2045 if (!strncmp(data, "GET ", 4)) {
2046 sp1 = data + 3;
2047 /* received GET request */
2048 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received GET request\"\n"));
2049#if LWIP_HTTPD_SUPPORT_POST
2050 } else if (!strncmp(data, "POST ", 5)) {
2051 /* store request type */
2052 is_post = 1;
2053 sp1 = data + 4;
2054 /* received GET request */
2055 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received POST request\n"));
2056#endif /* LWIP_HTTPD_SUPPORT_POST */
2057 } else {
2058 /* null-terminate the METHOD (pbuf is freed anyway wen returning) */
2059 data[4] = 0;
2060 /* unsupported method! */
2061 LWIP_DEBUGF(HTTPD_DEBUG, ("Unsupported request method (not implemented): \"%s\"\n",
2062 data));
2063 return http_find_error_file(hs, 501);
2064 }
2065 /* if we come here, method is OK, parse URI */
2066 left_len = (u16_t)(data_len - ((sp1 + 1) - data));
2067 sp2 = lwip_strnstr(sp1 + 1, " ", left_len);
2068#if LWIP_HTTPD_SUPPORT_V09
2069 if (sp2 == NULL) {
2070 /* HTTP 0.9: respond with correct protocol version */
2071 sp2 = lwip_strnstr(sp1 + 1, CRLF, left_len);
2072 is_09 = 1;
2073#if LWIP_HTTPD_SUPPORT_POST
2074 if (is_post) {
2075 /* HTTP/0.9 does not support POST */
2076 goto badrequest;
2077 }
2078#endif /* LWIP_HTTPD_SUPPORT_POST */
2079 }
2080#endif /* LWIP_HTTPD_SUPPORT_V09 */
2081 uri_len = (u16_t)(sp2 - (sp1 + 1));
2082 if ((sp2 != NULL) && (sp2 > sp1)) {
2083 /* wait for CRLFCRLF (indicating end of HTTP headers) before parsing anything */
2084 if (lwip_strnstr(data, CRLF CRLF, data_len) != NULL) {
2085 char *uri = sp1 + 1;
2086#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
2087 /* This is HTTP/1.0 compatible: for strict 1.1, a connection
2088 would always be persistent unless "close" was specified. */
2089 if (!is_09 && (lwip_strnstr(data, HTTP11_CONNECTIONKEEPALIVE, data_len) ||
2090 lwip_strnstr(data, HTTP11_CONNECTIONKEEPALIVE2, data_len))) {
2091 hs->keepalive = 1;
2092 } else {
2093 hs->keepalive = 0;
2094 }
2095#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
2096 /* null-terminate the METHOD (pbuf is freed anyway wen returning) */
2097 *sp1 = 0;
2098 uri[uri_len] = 0;
2099 LWIP_DEBUGF(HTTPD_DEBUG, ("Received \"%s\" request for URI: \"%s\"\n",
2100 data, uri));
2101#if LWIP_HTTPD_SUPPORT_POST
2102 if (is_post) {
2103#if LWIP_HTTPD_SUPPORT_REQUESTLIST
2104 struct pbuf *q = hs->req;
2105#else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
2106 struct pbuf *q = inp;
2107#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
2108 err = http_post_request(q, hs, data, data_len, uri, sp2);
2109 if (err != ERR_OK) {
2110 /* restore header for next try */
2111 *sp1 = ' ';
2112 *sp2 = ' ';
2113 uri[uri_len] = ' ';
2114 }
2115 if (err == ERR_ARG) {
2116 goto badrequest;
2117 }
2118 return err;
2119 } else
2120#endif /* LWIP_HTTPD_SUPPORT_POST */
2121 {
2122 return http_find_file(hs, uri, is_09);
2123 }
2124 }
2125 } else {
2126 LWIP_DEBUGF(HTTPD_DEBUG, ("invalid URI\n"));
2127 }
2128 }
2129 }
2130
2131#if LWIP_HTTPD_SUPPORT_REQUESTLIST
2132 clen = pbuf_clen(hs->req);
2133 if ((hs->req->tot_len <= LWIP_HTTPD_REQ_BUFSIZE) &&
2134 (clen <= LWIP_HTTPD_REQ_QUEUELEN)) {
2135 /* request not fully received (too short or CRLF is missing) */
2136 return ERR_INPROGRESS;
2137 } else
2138#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
2139 {
2140#if LWIP_HTTPD_SUPPORT_POST
2141badrequest:
2142#endif /* LWIP_HTTPD_SUPPORT_POST */
2143 LWIP_DEBUGF(HTTPD_DEBUG, ("bad request\n"));
2144 /* could not parse request */
2145 return http_find_error_file(hs, 400);
2146 }
2147}
2148
2149#if LWIP_HTTPD_SSI && (LWIP_HTTPD_SSI_BY_FILE_EXTENSION == 1)
2150/* Check if SSI should be parsed for this file/URL
2151 * (With LWIP_HTTPD_SSI_BY_FILE_EXTENSION == 2, this function can be
2152 * overridden by an external implementation.)
2153 *
2154 * @return 1 for SSI, 0 for standard files
2155 */
2156static u8_t
2157http_uri_is_ssi(struct fs_file *file, const char *uri)
2158{
2159 size_t loop;
2160 u8_t tag_check = 0;
2161 if (file != NULL) {
2162 /* See if we have been asked for an shtml file and, if so,
2163 enable tag checking. */
2164 const char *ext = NULL, *sub;
2165 char *param = (char *)strstr(uri, "?");
2166 if (param != NULL) {
2167 /* separate uri from parameters for now, set back later */
2168 *param = 0;
2169 }
2170 sub = uri;
2171 ext = uri;
2172 for (sub = strstr(sub, "."); sub != NULL; sub = strstr(sub, ".")) {
2173 ext = sub;
2174 sub++;
2175 }
2176 for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) {
2177 if (!lwip_stricmp(ext, g_pcSSIExtensions[loop])) {
2178 tag_check = 1;
2179 break;
2180 }
2181 }
2182 if (param != NULL) {
2183 *param = '?';
2184 }
2185 }
2186 return tag_check;
2187}
2188#endif /* LWIP_HTTPD_SSI */
2189
2199static err_t
2200http_find_file(struct http_state *hs, const char *uri, int is_09)
2201{
2202 size_t loop;
2203 struct fs_file *file = NULL;
2204 char *params = NULL;
2205 err_t err;
2206#if LWIP_HTTPD_CGI
2207 int i;
2208#endif /* LWIP_HTTPD_CGI */
2209#if !LWIP_HTTPD_SSI
2210 const
2211#endif /* !LWIP_HTTPD_SSI */
2212 /* By default, assume we will not be processing server-side-includes tags */
2213 u8_t tag_check = 0;
2214
2215 /* Have we been asked for the default file (in root or a directory) ? */
2216#if LWIP_HTTPD_MAX_REQUEST_URI_LEN
2217 size_t uri_len = strlen(uri);
2218 if ((uri_len > 0) && (uri[uri_len - 1] == '/') &&
2219 ((uri != http_uri_buf) || (uri_len == 1))) {
2220 size_t copy_len = LWIP_MIN(sizeof(http_uri_buf) - 1, uri_len - 1);
2221 if (copy_len > 0) {
2222 MEMCPY(http_uri_buf, uri, copy_len);
2223 http_uri_buf[copy_len] = 0;
2224 }
2225#else /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */
2226 if ((uri[0] == '/') && (uri[1] == 0)) {
2227#endif /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */
2228 /* Try each of the configured default filenames until we find one
2229 that exists. */
2230 for (loop = 0; loop < NUM_DEFAULT_FILENAMES; loop++) {
2231 const char *file_name;
2232#if LWIP_HTTPD_MAX_REQUEST_URI_LEN
2233 if (copy_len > 0) {
2234 size_t len_left = sizeof(http_uri_buf) - copy_len - 1;
2235 if (len_left > 0) {
2236 size_t name_len = strlen(httpd_default_filenames[loop].name);
2237 size_t name_copy_len = LWIP_MIN(len_left, name_len);
2238 MEMCPY(&http_uri_buf[copy_len], httpd_default_filenames[loop].name, name_copy_len);
2239 http_uri_buf[copy_len + name_copy_len] = 0;
2240 }
2241 file_name = http_uri_buf;
2242 } else
2243#endif /* LWIP_HTTPD_MAX_REQUEST_URI_LEN */
2244 {
2245 file_name = httpd_default_filenames[loop].name;
2246 }
2247 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Looking for %s...\n", file_name));
2248 err = fs_open(&hs->file_handle, file_name);
2249 if (err == ERR_OK) {
2250 uri = file_name;
2251 file = &hs->file_handle;
2252 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opened.\n"));
2253#if LWIP_HTTPD_SSI
2254 tag_check = httpd_default_filenames[loop].shtml;
2255#endif /* LWIP_HTTPD_SSI */
2256 break;
2257 }
2258 }
2259 }
2260 if (file == NULL) {
2261 /* No - we've been asked for a specific file. */
2262 /* First, isolate the base URI (without any parameters) */
2263 params = (char *)strchr(uri, '?');
2264 if (params != NULL) {
2265 /* URI contains parameters. NULL-terminate the base URI */
2266 *params = '\0';
2267 params++;
2268 }
2269
2270#if LWIP_HTTPD_CGI
2271 http_cgi_paramcount = -1;
2272 /* Does the base URI we have isolated correspond to a CGI handler? */
2273 if (httpd_num_cgis && httpd_cgis) {
2274 for (i = 0; i < httpd_num_cgis; i++) {
2275 if (strcmp(uri, httpd_cgis[i].pcCGIName) == 0) {
2276 /*
2277 * We found a CGI that handles this URI so extract the
2278 * parameters and call the handler.
2279 */
2280 http_cgi_paramcount = extract_uri_parameters(hs, params);
2281 uri = httpd_cgis[i].pfnCGIHandler(i, http_cgi_paramcount, hs->params,
2282 hs->param_vals);
2283 break;
2284 }
2285 }
2286 }
2287#endif /* LWIP_HTTPD_CGI */
2288
2289 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opening %s\n", uri));
2290
2291 err = fs_open(&hs->file_handle, uri);
2292 if (err == ERR_OK) {
2293 file = &hs->file_handle;
2294 } else {
2295 file = http_get_404_file(hs, &uri);
2296 }
2297#if LWIP_HTTPD_SSI
2298 if (file != NULL) {
2299 if (file->flags & FS_FILE_FLAGS_SSI) {
2300 tag_check = 1;
2301 } else {
2302#if LWIP_HTTPD_SSI_BY_FILE_EXTENSION
2303 tag_check = http_uri_is_ssi(file, uri);
2304#endif /* LWIP_HTTPD_SSI_BY_FILE_EXTENSION */
2305 }
2306 }
2307#endif /* LWIP_HTTPD_SSI */
2308 }
2309 if (file == NULL) {
2310 /* None of the default filenames exist so send back a 404 page */
2311 file = http_get_404_file(hs, &uri);
2312 }
2313 return http_init_file(hs, file, is_09, uri, tag_check, params);
2314}
2315
2328static err_t
2329http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri,
2330 u8_t tag_check, char *params)
2331{
2332#if !LWIP_HTTPD_SUPPORT_V09
2333 LWIP_UNUSED_ARG(is_09);
2334#endif
2335 if (file != NULL) {
2336 /* file opened, initialise struct http_state */
2337#if !LWIP_HTTPD_DYNAMIC_FILE_READ
2338 /* If dynamic read is disabled, file data must be in one piece and available now */
2339 LWIP_ASSERT("file->data != NULL", file->data != NULL);
2340#endif
2341
2342#if LWIP_HTTPD_SSI
2343 if (tag_check) {
2344 struct http_ssi_state *ssi = http_ssi_state_alloc();
2345 if (ssi != NULL) {
2346 ssi->tag_index = 0;
2347 ssi->tag_state = TAG_NONE;
2348 ssi->parsed = file->data;
2349 ssi->parse_left = file->len;
2350 ssi->tag_end = file->data;
2351 hs->ssi = ssi;
2352 }
2353 }
2354#else /* LWIP_HTTPD_SSI */
2355 LWIP_UNUSED_ARG(tag_check);
2356#endif /* LWIP_HTTPD_SSI */
2357 hs->handle = file;
2358#if LWIP_HTTPD_CGI_SSI
2359 if (params != NULL) {
2360 /* URI contains parameters, call generic CGI handler */
2361 int count;
2362#if LWIP_HTTPD_CGI
2363 if (http_cgi_paramcount >= 0) {
2364 count = http_cgi_paramcount;
2365 } else
2366#endif
2367 {
2368 count = extract_uri_parameters(hs, params);
2369 }
2370 httpd_cgi_handler(file, uri, count, http_cgi_params, http_cgi_param_vals
2372 , file->state
2373#endif /* LWIP_HTTPD_FILE_STATE */
2374 );
2375 }
2376#else /* LWIP_HTTPD_CGI_SSI */
2378#endif /* LWIP_HTTPD_CGI_SSI */
2379 hs->file = file->data;
2380 LWIP_ASSERT("File length must be positive!", (file->len >= 0));
2381#if LWIP_HTTPD_CUSTOM_FILES
2382 if (((file->flags & FS_FILE_FLAGS_CUSTOM) != 0) && (file->data == NULL)) {
2383 /* custom file, need to read data first (via fs_read_custom) */
2384 hs->left = 0;
2385 } else
2386#endif /* LWIP_HTTPD_CUSTOM_FILES */
2387 {
2388 hs->left = (u32_t)file->len;
2389 }
2390 hs->retries = 0;
2391#if LWIP_HTTPD_TIMING
2392 hs->time_started = sys_now();
2393#endif /* LWIP_HTTPD_TIMING */
2394#if !LWIP_HTTPD_DYNAMIC_HEADERS
2395 LWIP_ASSERT("HTTP headers not included in file system",
2396 (hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) != 0);
2397#endif /* !LWIP_HTTPD_DYNAMIC_HEADERS */
2398#if LWIP_HTTPD_SUPPORT_V09
2399 if (is_09 && ((hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) != 0)) {
2400 /* HTTP/0.9 responses are sent without HTTP header,
2401 search for the end of the header. */
2402 char *file_start = lwip_strnstr(hs->file, CRLF CRLF, hs->left);
2403 if (file_start != NULL) {
2404 int diff = file_start + 4 - hs->file;
2405 hs->file += diff;
2406 hs->left -= (u32_t)diff;
2407 }
2408 }
2409#endif /* LWIP_HTTPD_SUPPORT_V09*/
2410 } else {
2411 hs->handle = NULL;
2412 hs->file = NULL;
2413 hs->left = 0;
2414 hs->retries = 0;
2415 }
2416#if LWIP_HTTPD_DYNAMIC_HEADERS
2417 /* Determine the HTTP headers to send based on the file extension of
2418 * the requested URI. */
2419 if ((hs->handle == NULL) || ((hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) == 0)) {
2420 get_http_headers(hs, uri);
2421 }
2422#else /* LWIP_HTTPD_DYNAMIC_HEADERS */
2424#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
2425#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
2426 if (hs->keepalive) {
2427#if LWIP_HTTPD_SSI
2428 if (hs->ssi != NULL) {
2429 hs->keepalive = 0;
2430 } else
2431#endif /* LWIP_HTTPD_SSI */
2432 {
2433 if ((hs->handle != NULL) &&
2435 hs->keepalive = 0;
2436 }
2437 }
2438 }
2439#endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */
2440 return ERR_OK;
2441}
2442
2447static void
2448http_err(void *arg, err_t err)
2449{
2450 struct http_state *hs = (struct http_state *)arg;
2452
2453 LWIP_DEBUGF(HTTPD_DEBUG, ("http_err: %s\n", lwip_strerr(err)));
2454
2455 if (hs != NULL) {
2456 http_state_free(hs);
2457 }
2458}
2459
2464static err_t
2465http_sent(void *arg, struct altcp_pcb *pcb, u16_t len)
2466{
2467 struct http_state *hs = (struct http_state *)arg;
2468
2469 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_sent %p\n", (void *)pcb));
2470
2472
2473 if (hs == NULL) {
2474 return ERR_OK;
2475 }
2476
2477 hs->retries = 0;
2478
2479 http_send(pcb, hs);
2480
2481 return ERR_OK;
2482}
2483
2491static err_t
2492http_poll(void *arg, struct altcp_pcb *pcb)
2493{
2494 struct http_state *hs = (struct http_state *)arg;
2495 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_poll: pcb=%p hs=%p pcb_state=%s\n",
2496 (void *)pcb, (void *)hs, tcp_debug_state_str(altcp_dbg_get_tcp_state(pcb))));
2497
2498 if (hs == NULL) {
2499 err_t closed;
2500 /* arg is null, close. */
2501 LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: arg is NULL, close\n"));
2502 closed = http_close_conn(pcb, NULL);
2503 LWIP_UNUSED_ARG(closed);
2504#if LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR
2505 if (closed == ERR_MEM) {
2506 altcp_abort(pcb);
2507 return ERR_ABRT;
2508 }
2509#endif /* LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR */
2510 return ERR_OK;
2511 } else {
2512 hs->retries++;
2513 if (hs->retries == HTTPD_MAX_RETRIES) {
2514 LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: too many retries, close\n"));
2515 http_close_conn(pcb, hs);
2516 return ERR_OK;
2517 }
2518
2519 /* If this connection has a file open, try to send some more data. If
2520 * it has not yet received a GET request, don't do this since it will
2521 * cause the connection to close immediately. */
2522 if (hs->handle) {
2523 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_poll: try to send more data\n"));
2524 if (http_send(pcb, hs)) {
2525 /* If we wrote anything to be sent, go ahead and send it now. */
2526 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("tcp_output\n"));
2527 altcp_output(pcb);
2528 }
2529 }
2530 }
2531
2532 return ERR_OK;
2533}
2534
2539static err_t
2540http_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err)
2541{
2542 struct http_state *hs = (struct http_state *)arg;
2543 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_recv: pcb=%p pbuf=%p err=%s\n", (void *)pcb,
2544 (void *)p, lwip_strerr(err)));
2545
2546 if ((err != ERR_OK) || (p == NULL) || (hs == NULL)) {
2547 /* error or closed by other side? */
2548 if (p != NULL) {
2549 /* Inform TCP that we have taken the data. */
2550 altcp_recved(pcb, p->tot_len);
2551 pbuf_free(p);
2552 }
2553 if (hs == NULL) {
2554 /* this should not happen, only to be robust */
2555 LWIP_DEBUGF(HTTPD_DEBUG, ("Error, http_recv: hs is NULL, close\n"));
2556 }
2557 http_close_conn(pcb, hs);
2558 return ERR_OK;
2559 }
2560
2561#if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
2562 if (hs->no_auto_wnd) {
2563 hs->unrecved_bytes += p->tot_len;
2564 } else
2565#endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
2566 {
2567 /* Inform TCP that we have taken the data. */
2568 altcp_recved(pcb, p->tot_len);
2569 }
2570
2571#if LWIP_HTTPD_SUPPORT_POST
2572 if (hs->post_content_len_left > 0) {
2573 /* reset idle counter when POST data is received */
2574 hs->retries = 0;
2575 /* this is data for a POST, pass the complete pbuf to the application */
2576 http_post_rxpbuf(hs, p);
2577 /* pbuf is passed to the application, don't free it! */
2578 if (hs->post_content_len_left == 0) {
2579 /* all data received, send response or close connection */
2580 http_send(pcb, hs);
2581 }
2582 return ERR_OK;
2583 } else
2584#endif /* LWIP_HTTPD_SUPPORT_POST */
2585 {
2586 if (hs->handle == NULL) {
2587 err_t parsed = http_parse_request(p, hs, pcb);
2588 LWIP_ASSERT("http_parse_request: unexpected return value", parsed == ERR_OK
2589 || parsed == ERR_INPROGRESS || parsed == ERR_ARG || parsed == ERR_USE);
2590#if LWIP_HTTPD_SUPPORT_REQUESTLIST
2591 if (parsed != ERR_INPROGRESS) {
2592 /* request fully parsed or error */
2593 if (hs->req != NULL) {
2594 pbuf_free(hs->req);
2595 hs->req = NULL;
2596 }
2597 }
2598#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
2599 pbuf_free(p);
2600 if (parsed == ERR_OK) {
2601#if LWIP_HTTPD_SUPPORT_POST
2602 if (hs->post_content_len_left == 0)
2603#endif /* LWIP_HTTPD_SUPPORT_POST */
2604 {
2605 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_recv: data %p len %"S32_F"\n", (const void *)hs->file, hs->left));
2606 http_send(pcb, hs);
2607 }
2608 } else if (parsed == ERR_ARG) {
2609 /* @todo: close on ERR_USE? */
2610 http_close_conn(pcb, hs);
2611 }
2612 } else {
2613 LWIP_DEBUGF(HTTPD_DEBUG, ("http_recv: already sending data\n"));
2614 /* already sending but still receiving data, we might want to RST here? */
2615 pbuf_free(p);
2616 }
2617 }
2618 return ERR_OK;
2619}
2620
2624static err_t
2625http_accept(void *arg, struct altcp_pcb *pcb, err_t err)
2626{
2627 struct http_state *hs;
2630 LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept %p / %p\n", (void *)pcb, arg));
2631
2632 if ((err != ERR_OK) || (pcb == NULL)) {
2633 return ERR_VAL;
2634 }
2635
2636 /* Set priority */
2638
2639 /* Allocate memory for the structure that holds the state of the
2640 connection - initialized by that function. */
2641 hs = http_state_alloc();
2642 if (hs == NULL) {
2643 LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept: Out of memory, RST\n"));
2644 return ERR_MEM;
2645 }
2646 hs->pcb = pcb;
2647
2648 /* Tell TCP that this is the structure we wish to be passed for our
2649 callbacks. */
2650 altcp_arg(pcb, hs);
2651
2652 /* Set up the various callback functions */
2653 altcp_recv(pcb, http_recv);
2654 altcp_err(pcb, http_err);
2655 altcp_poll(pcb, http_poll, HTTPD_POLL_INTERVAL);
2656 altcp_sent(pcb, http_sent);
2657
2658 return ERR_OK;
2659}
2660
2661static void
2662httpd_init_pcb(struct altcp_pcb *pcb, u16_t port)
2663{
2664 err_t err;
2665
2666 if (pcb) {
2668 /* set SOF_REUSEADDR here to explicitly bind httpd to multiple interfaces */
2669 err = altcp_bind(pcb, IP_ANY_TYPE, port);
2670 LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
2671 LWIP_ASSERT("httpd_init: tcp_bind failed", err == ERR_OK);
2672 pcb = altcp_listen(pcb);
2673 LWIP_ASSERT("httpd_init: tcp_listen failed", pcb != NULL);
2674 altcp_accept(pcb, http_accept);
2675 }
2676}
2677
2682void
2683httpd_init(void)
2684{
2685 struct altcp_pcb *pcb;
2686
2687#if HTTPD_USE_MEM_POOL
2688 LWIP_MEMPOOL_INIT(HTTPD_STATE);
2689#if LWIP_HTTPD_SSI
2690 LWIP_MEMPOOL_INIT(HTTPD_SSI_STATE);
2691#endif
2692#endif
2693 LWIP_DEBUGF(HTTPD_DEBUG, ("httpd_init\n"));
2694
2695 /* LWIP_ASSERT_CORE_LOCKED(); is checked by tcp_new() */
2696
2698 LWIP_ASSERT("httpd_init: tcp_new failed", pcb != NULL);
2699 httpd_init_pcb(pcb, HTTPD_SERVER_PORT);
2700}
2701
2702#if HTTPD_ENABLE_HTTPS
2708void
2709httpd_inits(struct altcp_tls_config *conf)
2710{
2711#if LWIP_ALTCP_TLS
2712 struct altcp_pcb *pcb_tls = altcp_tls_new(conf, IPADDR_TYPE_ANY);
2713 LWIP_ASSERT("httpd_init: altcp_tls_new failed", pcb_tls != NULL);
2714 httpd_init_pcb(pcb_tls, HTTPD_SERVER_PORT_HTTPS);
2715#else /* LWIP_ALTCP_TLS */
2716 LWIP_UNUSED_ARG(conf);
2717#endif /* LWIP_ALTCP_TLS */
2718}
2719#endif /* HTTPD_ENABLE_HTTPS */
2720
2721#if LWIP_HTTPD_SSI
2730void
2731http_set_ssi_handler(tSSIHandler ssi_handler, const char **tags, int num_tags)
2732{
2733 LWIP_DEBUGF(HTTPD_DEBUG, ("http_set_ssi_handler\n"));
2734
2735 LWIP_ASSERT("no ssi_handler given", ssi_handler != NULL);
2736 httpd_ssi_handler = ssi_handler;
2737
2738#if LWIP_HTTPD_SSI_RAW
2740 LWIP_UNUSED_ARG(num_tags);
2741#else /* LWIP_HTTPD_SSI_RAW */
2742 LWIP_ASSERT("no tags given", tags != NULL);
2743 LWIP_ASSERT("invalid number of tags", num_tags > 0);
2744
2745 httpd_tags = tags;
2746 httpd_num_tags = num_tags;
2747#endif /* !LWIP_HTTPD_SSI_RAW */
2748}
2749#endif /* LWIP_HTTPD_SSI */
2750
2751#if LWIP_HTTPD_CGI
2759void
2760http_set_cgi_handlers(const tCGI *cgis, int num_handlers)
2761{
2762 LWIP_ASSERT("no cgis given", cgis != NULL);
2763 LWIP_ASSERT("invalid number of handlers", num_handlers > 0);
2764
2765 httpd_cgis = cgis;
2766 httpd_num_cgis = num_handlers;
2767}
2768#endif /* LWIP_HTTPD_CGI */
2769
2770#endif /* LWIP_TCP && LWIP_CALLBACK_API */
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
char * strchr(const char *String, int ch)
Definition: utclib.c:501
#define altcp_accept
Definition: altcp.h:169
#define altcp_write
Definition: altcp.h:187
#define altcp_output
Definition: altcp.h:188
#define altcp_sndqueuelen
Definition: altcp.h:192
#define altcp_arg
Definition: altcp.h:168
#define altcp_sndbuf
Definition: altcp.h:191
#define altcp_poll
Definition: altcp.h:172
#define altcp_sent
Definition: altcp.h:171
#define altcp_nagle_enable
Definition: altcp.h:194
#define altcp_listen
Definition: altcp.h:181
#define altcp_setprio
Definition: altcp.h:196
#define altcp_nagle_disable
Definition: altcp.h:193
#define altcp_err
Definition: altcp.h:173
#define altcp_recv
Definition: altcp.h:170
#define altcp_pcb
Definition: altcp.h:159
#define altcp_close
Definition: altcp.h:184
#define altcp_abort
Definition: altcp.h:183
#define altcp_recved
Definition: altcp.h:175
#define altcp_tcp_new_ip_type
Definition: altcp.h:160
#define altcp_bind
Definition: altcp.h:176
#define LWIP_MAX(x, y)
Definition: def.h:65
#define LWIP_ARRAYSIZE(x)
Definition: def.h:69
#define LWIP_MIN(x, y)
Definition: def.h:66
#define mem_free(ptr, bsize)
Definition: types.h:124
#define NULL
Definition: types.h:112
static unsigned int num_handlers(const APPLYSTATEFUNC *funcs)
Definition: state.c:5990
static const WCHAR crlf[]
Definition: object.c:1018
static const WCHAR *const ext[]
Definition: module.c:53
USHORT port
Definition: uri.c:228
#define S32_F
Definition: cc.h:23
#define U16_F
Definition: cc.h:19
#define U32_F
Definition: cc.h:22
int fs_bytes_left(struct fs_file *file)
Definition: fs.c:158
err_t fs_open(struct fs_file *file, const char *name)
Definition: fs.c:43
void fs_close(struct fs_file *file)
Definition: fs.c:83
void * mem_malloc(mem_size_t size_in)
Definition: mem.c:831
#define FS_FILE_FLAGS_CUSTOM
Definition: fs.h:57
#define FS_READ_DELAYED
Definition: fs.h:43
#define FS_FILE_FLAGS_SSI
Definition: fs.h:56
void httpd_init(void)
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:158
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
#define lwip_strerr(x)
Definition: err.h:106
u16_t mem_size_t
Definition: mem.h:67
#define ERR_MEM
Definition: fontsub.h:52
#define FS_FILE_FLAGS_HEADER_INCLUDED
Definition: fsdata.c:9
#define FS_FILE_FLAGS_HEADER_PERSISTENT
Definition: fsdata.c:12
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLenum const GLfloat * params
Definition: glext.h:5645
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLint left
Definition: glext.h:7726
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLfloat GLfloat p
Definition: glext.h:8902
GLfloat param
Definition: glext.h:5796
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
uint32_t u32_t
Definition: arch.h:129
uint8_t u8_t
Definition: arch.h:125
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:373
uint16_t u16_t
Definition: arch.h:127
#define LWIP_DBG_LEVEL_WARNING
Definition: debug.h:55
#define LWIP_DBG_TRACE
Definition: debug.h:83
#define HTTPD_SERVER_PORT
Definition: httpd_opts.h:200
#define LWIP_HTTPD_MAX_REQ_LENGTH
Definition: httpd_opts.h:283
#define LWIP_HTTPD_SSI_MULTIPART
Definition: httpd_opts.h:149
#define HTTPD_DEBUG
Definition: httpd_opts.h:185
#define LWIP_HTTPD_SSI_RAW
Definition: httpd_opts.h:109
#define HTTPD_DEBUG_TIMING
Definition: httpd_opts.h:239
#define HTTP_IS_TAG_VOLATILE(ptr)
Definition: httpd_opts.h:332
#define LWIP_HTTPD_POST_MANUAL_WND
Definition: httpd_opts.h:167
#define LWIP_HTTPD_MAX_CGI_PARAMETERS
Definition: httpd_opts.h:141
#define LWIP_HTTPD_REQ_BUFSIZE
Definition: httpd_opts.h:276
#define LWIP_HTTPD_MAX_TAG_INSERT_LEN
Definition: httpd_opts.h:163
#define HTTPD_MAX_WRITE_LEN(pcb)
Definition: httpd_opts.h:346
#define HTTPD_TCP_PRIO
Definition: httpd_opts.h:230
#define LWIP_HTTPD_MAX_TAG_NAME_LEN
Definition: httpd_opts.h:156
#define HTTPD_POLL_INTERVAL
Definition: httpd_opts.h:223
#define HTTPD_MAX_RETRIES
Definition: httpd_opts.h:218
#define LWIP_HTTPD_FILE_STATE
Definition: httpd_opts.h:375
#define LWIP_HTTPD_REQ_QUEUELEN
Definition: httpd_opts.h:270
#define HTTPD_SERVER_PORT_HTTPS
Definition: httpd_opts.h:205
s8_t err_t
Definition: err.h:96
@ ERR_INPROGRESS
Definition: err.h:65
@ ERR_USE
Definition: err.h:71
@ ERR_OK
Definition: err.h:55
@ ERR_VAL
Definition: err.h:67
@ ERR_ARG
Definition: err.h:88
@ ERR_ABRT
Definition: err.h:82
#define IP_ANY_TYPE
Definition: ip_addr.h:461
@ IPADDR_TYPE_ANY
Definition: ip_addr.h:60
#define LWIP_ASSERT_CORE_LOCKED()
Definition: opt.h:227
#define SMEMCPY(dst, src, len)
Definition: opt.h:145
#define TCP_SND_QUEUELEN
Definition: opt.h:1373
#define LWIP_MEMPOOL_DECLARE(name, num, size, desc)
Definition: memp.h:95
#define LWIP_MEMPOOL_INIT(name)
Definition: memp.h:117
void pbuf_ref(struct pbuf *p)
Definition: pbuf.c:831
void pbuf_cat(struct pbuf *h, struct pbuf *t)
Definition: pbuf.c:855
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:224
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:727
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:1058
@ PBUF_REF
Definition: pbuf.h:160
@ PBUF_RAW
Definition: pbuf.h:111
int lwip_stricmp(const char *str1, const char *str2)
Definition: def.c:151
char * lwip_strnstr(const char *buffer, const char *token, size_t n)
Definition: def.c:105
void lwip_itoa(char *result, size_t bufsize, int number)
Definition: def.c:222
u32_t sys_now(void)
Definition: sys_arch.c:23
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
if(dx< 0)
Definition: linetemp.h:194
#define MEMCPY(DST, SRC, BYTES)
Definition: macros.h:231
const char * tags[7 *8]
Definition: apphelp.c:216
static PVOID ptr
Definition: dispmode.c:27
static UINT UINT last
Definition: font.c:45
static BSTR content_type
static LPCWSTR file_name
Definition: protocol.c:147
const char * uri
Definition: sec_mgr.c:1588
u16_t pbuf_clen(const struct pbuf *p)
Definition: pbuf.c:811
u8_t pbuf_remove_header(struct pbuf *p, size_t header_size_decrement)
Definition: pbuf.c:585
static unsigned __int64 next
Definition: rand_nt.c:6
#define err(...)
static FILE * file_handle
Definition: regtests2xml.c:45
void fs_read(off_t pos, int size, void *data)
Definition: io.c:282
#define memset(x, y, z)
Definition: compat.h:39
Definition: fci.c:127
Definition: fs.h:66
Definition: name.c:39
Definition: _pair.h:47
Definition: pbuf.h:186
u16_t len
Definition: pbuf.h:203
Definition: ecma_167.h:138
#define TAG_NONE
Definition: tag.h:109
int ret