| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
httpd.c
Go to the documentation of this file.
1 /*
2 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25 * OF SUCH DAMAGE.
26 *
27 * This file is part of the lwIP TCP/IP stack.
28 *
29 * Author: Adam Dunkels <adam@sics.se>
30 *
31 */
32
33 /* This httpd supports for a
34 * rudimentary server-side-include facility which will replace tags of the form
35 * <!--#tag--> in any file whose extension is .shtml, .shtm or .ssi with
36 * strings provided by an include handler whose pointer is provided to the
37 * module via function http_set_ssi_handler().
38 * Additionally, a simple common
39 * gateway interface (CGI) handling mechanism has been added to allow clients
40 * to hook functions to particular request URIs.
41 *
42 * To enable SSI support, define label LWIP_HTTPD_SSI in lwipopts.h.
43 * To enable CGI support, define label LWIP_HTTPD_CGI in lwipopts.h.
44 *
45 * By default, the server assumes that HTTP headers are already present in
46 * each file stored in the file system. By defining LWIP_HTTPD_DYNAMIC_HEADERS in
47 * lwipopts.h, this behavior can be changed such that the server inserts the
48 * headers automatically based on the extension of the file being served. If
49 * this mode is used, be careful to ensure that the file system image used
50 * does not already contain the header information.
51 *
52 * File system images without headers can be created using the makefsfile
53 * tool with the -h command line option.
54 *
55 *
56 * Notes about valid SSI tags
57 * --------------------------
58 *
59 * The following assumptions are made about tags used in SSI markers:
60 *
61 * 1. No tag may contain '-' or whitespace characters within the tag name.
62 * 2. Whitespace is allowed between the tag leadin "<!--#" and the start of
63 * the tag name and between the tag name and the leadout string "-->".
64 * 3. The maximum tag name length is LWIP_HTTPD_MAX_TAG_NAME_LEN, currently 8 characters.
65 *
66 * Notes on CGI usage
67 * ------------------
68 *
69 * The simple CGI support offered here works with GET method requests only
70 * and can handle up to 16 parameters encoded into the URI. The handler
71 * function may not write directly to the HTTP output but must return a
72 * filename that the HTTP server will send to the browser as a response to
73 * the incoming CGI request.
74 *
75 * @todo:
76 * - don't use mem_malloc() (for SSI/dynamic headers)
77 * - split too long functions into multiple smaller functions?
78 * - support more file types?
79 */
80 #include "lwip/debug.h"
81 #include "lwip/stats.h"
82 #include "httpd.h"
83 #include "httpd_structs.h"
84 #include "lwip/tcp.h"
85 #include "lwip_fs.h"
86
87 #include <string.h>
88 #include <stdlib.h>
89
90 #if LWIP_TCP
91
92 #ifndef HTTPD_DEBUG
93 #define HTTPD_DEBUG LWIP_DBG_OFF
94 #endif
95
101 #ifndef HTTPD_USE_MEM_POOL
102 #define HTTPD_USE_MEM_POOL 0
103 #endif
104
106 #ifndef HTTPD_SERVER_PORT
107 #define HTTPD_SERVER_PORT 80
108 #endif
109
114 #ifndef HTTPD_MAX_RETRIES
115 #define HTTPD_MAX_RETRIES 4
116 #endif
117
119 #ifndef HTTPD_POLL_INTERVAL
120 #define HTTPD_POLL_INTERVAL 4
121 #endif
122
126 #ifndef HTTPD_TCP_PRIO
127 #define HTTPD_TCP_PRIO TCP_PRIO_MIN
128 #endif
129
131 #ifndef LWIP_HTTPD_TIMING
132 #define LWIP_HTTPD_TIMING 0
133 #endif
134 #ifndef HTTPD_DEBUG_TIMING
135 #define HTTPD_DEBUG_TIMING LWIP_DBG_OFF
136 #endif
137
139 #ifndef LWIP_HTTPD_STRNSTR_PRIVATE
140 #define LWIP_HTTPD_STRNSTR_PRIVATE 1
141 #endif
142
145 #ifndef LWIP_HTTPD_SUPPORT_EXTSTATUS
146 #define LWIP_HTTPD_SUPPORT_EXTSTATUS 0
147 #endif
148
150 #ifndef LWIP_HTTPD_SUPPORT_V09
151 #define LWIP_HTTPD_SUPPORT_V09 1
152 #endif
153
155 #ifndef LWIP_HTTPD_SUPPORT_REQUESTLIST
156 #define LWIP_HTTPD_SUPPORT_REQUESTLIST 0
157 #endif
158
159 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
160
162 #ifndef LWIP_HTTPD_REQ_QUEUELEN
163 #define LWIP_HTTPD_REQ_QUEUELEN 10
164 #endif
165
168 #ifndef LWIP_HTTPD_REQ_BUFSIZE
169 #define LWIP_HTTPD_REQ_BUFSIZE LWIP_HTTPD_MAX_REQ_LENGTH
170 #endif
171
175 #ifndef LWIP_HTTPD_MAX_REQ_LENGTH
176 #define LWIP_HTTPD_MAX_REQ_LENGTH 1023
177 #endif
178 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
179
183 #ifndef LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN
184 #define LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN 63
185 #endif
186
189 #ifndef LWIP_HTTPD_SSI_INCLUDE_TAG
190 #define LWIP_HTTPD_SSI_INCLUDE_TAG 1
191 #endif
192
196 #ifndef LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR
197 #define LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR 0
198 #endif
199
200 #ifndef true
201 #define true ((u8_t)1)
202 #endif
203
204 #ifndef false
205 #define false ((u8_t)0)
206 #endif
207
209 #define MIN_REQ_LEN 7
210
211 #define CRLF "\r\n"
212
217 #ifndef HTTP_IS_DATA_VOLATILE
218 #if LWIP_HTTPD_SSI
219 /* Copy for SSI files, no copy for non-SSI files */
220 #define HTTP_IS_DATA_VOLATILE(hs) ((hs)->tag_check ? TCP_WRITE_FLAG_COPY : 0)
221 #else /* LWIP_HTTPD_SSI */
222
223 #define HTTP_IS_DATA_VOLATILE(hs) (((hs->file != NULL) && (hs->handle != NULL) && (hs->file == \
224 (char*)hs->handle->data + hs->handle->len - hs->left)) \
225 ? 0 : TCP_WRITE_FLAG_COPY)
226 #endif /* LWIP_HTTPD_SSI */
227 #endif
228
230 #ifndef HTTP_IS_HDR_VOLATILE
231 #define HTTP_IS_HDR_VOLATILE(hs, ptr) 0
232 #endif
233
234 #if LWIP_HTTPD_SSI
235
236 #ifndef HTTP_IS_TAG_VOLATILE
237 #define HTTP_IS_TAG_VOLATILE(ptr) TCP_WRITE_FLAG_COPY
238 #endif
239 #endif /* LWIP_HTTPD_SSI */
240
241 typedef struct
242 {
243 const char *name;
244 u8_t shtml;
245 } default_filename;
246
247 const default_filename g_psDefaultFilenames[] = {
248 {"/index.shtml", true },
249 {"/index.ssi", true },
250 {"/index.shtm", true },
251 {"/index.html", false },
252 {"/index.htm", false }
253 };
254
255 #define NUM_DEFAULT_FILENAMES (sizeof(g_psDefaultFilenames) / \
256 sizeof(default_filename))
257
258 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
259
260 static char httpd_req_buf[LWIP_HTTPD_MAX_REQ_LENGTH+1];
261 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
262
263 #if LWIP_HTTPD_SUPPORT_POST
264
265 static char http_post_response_filename[LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN+1];
266 #endif /* LWIP_HTTPD_SUPPORT_POST */
267
268 #if LWIP_HTTPD_DYNAMIC_HEADERS
269 /* The number of individual strings that comprise the headers sent before each
270 * requested file.
271 */
272 #define NUM_FILE_HDR_STRINGS 3
273 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
274
275 #if LWIP_HTTPD_SSI
276
277 #define HTTPD_LAST_TAG_PART 0xFFFF
278
279 const char * const g_pcSSIExtensions[] = {
280 ".shtml", ".shtm", ".ssi", ".xml"
281 };
282
283 #define NUM_SHTML_EXTENSIONS (sizeof(g_pcSSIExtensions) / sizeof(const char *))
284
285 enum tag_check_state {
286 TAG_NONE, /* Not processing an SSI tag */
287 TAG_LEADIN, /* Tag lead in "<!--#" being processed */
288 TAG_FOUND, /* Tag name being read, looking for lead-out start */
289 TAG_LEADOUT, /* Tag lead out "-->" being processed */
290 TAG_SENDING /* Sending tag replacement string */
291 };
292 #endif /* LWIP_HTTPD_SSI */
293
294 struct http_state {
295 struct fs_file *handle;
296 char *file; /* Pointer to first unsent byte in buf. */
297
298 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
299 struct pbuf *req;
300 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
301
302 #if LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS
303 char *buf; /* File read buffer. */
304 int buf_len; /* Size of file read buffer, buf. */
305 #endif /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */
306 u32_t left; /* Number of unsent bytes in buf. */
307 u8_t retries;
308 #if LWIP_HTTPD_SSI
309 const char *parsed; /* Pointer to the first unparsed byte in buf. */
310 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
311 const char *tag_started;/* Poitner to the first opening '<' of the tag. */
312 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */
313 const char *tag_end; /* Pointer to char after the closing '>' of the tag. */
314 u32_t parse_left; /* Number of unparsed bytes in buf. */
315 u16_t tag_index; /* Counter used by tag parsing state machine */
316 u16_t tag_insert_len; /* Length of insert in string tag_insert */
317 #if LWIP_HTTPD_SSI_MULTIPART
318 u16_t tag_part; /* Counter passed to and changed by tag insertion function to insert multiple times */
319 #endif /* LWIP_HTTPD_SSI_MULTIPART */
320 u8_t tag_check; /* true if we are processing a .shtml file else false */
321 u8_t tag_name_len; /* Length of the tag name in string tag_name */
322 char tag_name[LWIP_HTTPD_MAX_TAG_NAME_LEN + 1]; /* Last tag name extracted */
323 char tag_insert[LWIP_HTTPD_MAX_TAG_INSERT_LEN + 1]; /* Insert string for tag_name */
324 enum tag_check_state tag_state; /* State of the tag processor */
325 #endif /* LWIP_HTTPD_SSI */
326 #if LWIP_HTTPD_CGI
327 char *params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */
328 char *param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */
329 #endif /* LWIP_HTTPD_CGI */
330 #if LWIP_HTTPD_DYNAMIC_HEADERS
331 const char *hdrs[NUM_FILE_HDR_STRINGS]; /* HTTP headers to be sent. */
332 u16_t hdr_pos; /* The position of the first unsent header byte in the
333 current string */
334 u16_t hdr_index; /* The index of the hdr string currently being sent. */
335 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
336 #if LWIP_HTTPD_TIMING
337 u32_t time_started;
338 #endif /* LWIP_HTTPD_TIMING */
339 #if LWIP_HTTPD_SUPPORT_POST
340 u32_t post_content_len_left;
341 #if LWIP_HTTPD_POST_MANUAL_WND
342 u32_t unrecved_bytes;
343 struct tcp_pcb *pcb;
344 u8_t no_auto_wnd;
345 #endif /* LWIP_HTTPD_POST_MANUAL_WND */
346 #endif /* LWIP_HTTPD_SUPPORT_POST*/
347 };
348
349 static err_t http_find_file(struct http_state *hs, const char *uri, int is_09);
350 static err_t http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri);
351 static err_t http_poll(void *arg, struct tcp_pcb *pcb);
352
353 #if LWIP_HTTPD_SSI
354 /* SSI insert handler function pointer. */
355 tSSIHandler g_pfnSSIHandler = NULL;
356 int g_iNumTags = 0;
357 const char **g_ppcTags = NULL;
358
359 #define LEN_TAG_LEAD_IN 5
360 const char * const g_pcTagLeadIn = "<!--#";
361
362 #define LEN_TAG_LEAD_OUT 3
363 const char * const g_pcTagLeadOut = "-->";
364 #endif /* LWIP_HTTPD_SSI */
365
366 #if LWIP_HTTPD_CGI
367 /* CGI handler information */
368 const tCGI *g_pCGIs;
369 int g_iNumCGIs;
370 #endif /* LWIP_HTTPD_CGI */
371
372 #if LWIP_HTTPD_STRNSTR_PRIVATE
373
374 static char*
375 strnstr(const char* buffer, const char* token, size_t n)
376 {
377 const char* p;
378 int tokenlen = (int)strlen(token);
379 if (tokenlen == 0) {
380 return (char *)buffer;
381 }
382 for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) {
383 if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) {
384 return (char *)p;
385 }
386 }
387 return NULL;
388 }
389 #endif /* LWIP_HTTPD_STRNSTR_PRIVATE */
390
392 static struct http_state*
393 http_state_alloc(void)
394 {
395 struct http_state *ret;
396 #if HTTPD_USE_MEM_POOL
397 ret = (struct http_state *)memp_malloc(MEMP_HTTPD_STATE);
398 #else /* HTTPD_USE_MEM_POOL */
399 ret = (struct http_state *)mem_malloc(sizeof(struct http_state));
400 #endif /* HTTPD_USE_MEM_POOL */
401 if (ret != NULL) {
402 /* Initialize the structure. */
403 memset(ret, 0, sizeof(struct http_state));
404 #if LWIP_HTTPD_DYNAMIC_HEADERS
405 /* Indicate that the headers are not yet valid */
406 ret->hdr_index = NUM_FILE_HDR_STRINGS;
407 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
408 }
409 return ret;
410 }
411
415 static void
416 http_state_free(struct http_state *hs)
417 {
418 if (hs != NULL) {
419 if(hs->handle) {
420 #if LWIP_HTTPD_TIMING
421 u32_t ms_needed = sys_now() - hs->time_started;
422 u32_t needed = LWIP_MAX(1, (ms_needed/100));
423 LWIP_DEBUGF(HTTPD_DEBUG_TIMING, ("httpd: needed %"U32_F" ms to send file of %d bytes -> %"U32_F" bytes/sec\n",
424 ms_needed, hs->handle->len, ((((u32_t)hs->handle->len) * 10) / needed)));
425 #endif /* LWIP_HTTPD_TIMING */
426 fs_close(hs->handle);
427 hs->handle = NULL;
428 }
429 #if LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS
430 if (hs->buf != NULL) {
431 mem_free(hs->buf);
432 hs->buf = NULL;
433 }
434 #endif /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */
435 #if HTTPD_USE_MEM_POOL
436 memp_free(MEMP_HTTPD_STATE, hs);
437 #else /* HTTPD_USE_MEM_POOL */
438 mem_free(hs);
439 #endif /* HTTPD_USE_MEM_POOL */
440 }
441 }
442
452 static err_t
453 http_write(struct tcp_pcb *pcb, const void* ptr, u16_t *length, u8_t apiflags)
454 {
455 u16_t len;
456 err_t err;
457 LWIP_ASSERT("length != NULL", length != NULL);
458 len = *length;
459 do {
460 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Trying go send %d bytes\n", len));
461 err = tcp_write(pcb, ptr, len, apiflags);
462 if (err == ERR_MEM) {
463 if ((tcp_sndbuf(pcb) == 0) ||
464 (tcp_sndqueuelen(pcb) >= TCP_SND_QUEUELEN)) {
465 /* no need to try smaller sizes */
466 len = 1;
467 } else {
468 len /= 2;
469 }
470 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE,
471 ("Send failed, trying less (%d bytes)\n", len));
472 }
473 } while ((err == ERR_MEM) && (len > 1));
474
475 if (err == ERR_OK) {
476 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Sent %d bytes\n", len));
477 } else {
478 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Send failed with err %d (\"%s\")\n", err, lwip_strerr(err)));
479 }
480
481 *length = len;
482 return err;
483 }
484
492 static err_t
493 http_close_conn(struct tcp_pcb *pcb, struct http_state *hs)
494 {
495 err_t err;
496 LWIP_DEBUGF(HTTPD_DEBUG, ("Closing connection %p\n", (void*)pcb));
497
498 #if LWIP_HTTPD_SUPPORT_POST
499 if (hs != NULL) {
500 if ((hs->post_content_len_left != 0)
501 #if LWIP_HTTPD_POST_MANUAL_WND
502 || ((hs->no_auto_wnd != 0) && (hs->unrecved_bytes != 0))
503 #endif /* LWIP_HTTPD_POST_MANUAL_WND */
504 ) {
505 /* make sure the post code knows that the connection is closed */
506 http_post_response_filename[0] = 0;
507 httpd_post_finished(hs, http_post_response_filename, LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN);
508 }
509 }
510 #endif /* LWIP_HTTPD_SUPPORT_POST*/
511
512
513 tcp_arg(pcb, NULL);
514 tcp_recv(pcb, NULL);
515 tcp_err(pcb, NULL);
516 tcp_poll(pcb, NULL, 0);
517 tcp_sent(pcb, NULL);
518 if(hs != NULL) {
519 http_state_free(hs);
520 }
521
522 err = tcp_close(pcb);
523 if (err != ERR_OK) {
524 LWIP_DEBUGF(HTTPD_DEBUG, ("Error %d closing %p\n", err, (void*)pcb));
525 /* error closing, try again later in poll */
526 tcp_poll(pcb, http_poll, HTTPD_POLL_INTERVAL);
527 }
528 return err;
529 }
530 #if LWIP_HTTPD_CGI
531
540 static int
541 extract_uri_parameters(struct http_state *hs, char *params)
542 {
543 char *pair;
544 char *equals;
545 int loop;
546
547 /* If we have no parameters at all, return immediately. */
548 if(!params || (params[0] == '\0')) {
549 return(0);
550 }
551
552 /* Get a pointer to our first parameter */
553 pair = params;
554
555 /* Parse up to LWIP_HTTPD_MAX_CGI_PARAMETERS from the passed string and ignore the
556 * remainder (if any) */
557 for(loop = 0; (loop < LWIP_HTTPD_MAX_CGI_PARAMETERS) && pair; loop++) {
558
559 /* Save the name of the parameter */
560 hs->params[loop] = pair;
561
562 /* Remember the start of this name=value pair */
563 equals = pair;
564
565 /* Find the start of the next name=value pair and replace the delimiter
566 * with a 0 to terminate the previous pair string. */
567 pair = strchr(pair, '&');
568 if(pair) {
569 *pair = '\0';
570 pair++;
571 } else {
572 /* We didn't find a new parameter so find the end of the URI and
573 * replace the space with a '\0' */
574 pair = strchr(equals, ' ');
575 if(pair) {
576 *pair = '\0';
577 }
578
579 /* Revert to NULL so that we exit the loop as expected. */
580 pair = NULL;
581 }
582
583 /* Now find the '=' in the previous pair, replace it with '\0' and save
584 * the parameter value string. */
585 equals = strchr(equals, '=');
586 if(equals) {
587 *equals = '\0';
588 hs->param_vals[loop] = equals + 1;
589 } else {
590 hs->param_vals[loop] = NULL;
591 }
592 }
593
594 return loop;
595 }
596 #endif /* LWIP_HTTPD_CGI */
597
598 #if LWIP_HTTPD_SSI
599
609 static void
610 get_tag_insert(struct http_state *hs)
611 {
612 int loop;
613 size_t len;
614 #if LWIP_HTTPD_SSI_MULTIPART
615 u16_t current_tag_part = hs->tag_part;
616 hs->tag_part = HTTPD_LAST_TAG_PART;
617 #endif /* LWIP_HTTPD_SSI_MULTIPART */
618
619 if(g_pfnSSIHandler && g_ppcTags && g_iNumTags) {
620
621 /* Find this tag in the list we have been provided. */
622 for(loop = 0; loop < g_iNumTags; loop++) {
623 if(strcmp(hs->tag_name, g_ppcTags[loop]) == 0) {
624 hs->tag_insert_len = g_pfnSSIHandler(loop, hs->tag_insert,
625 LWIP_HTTPD_MAX_TAG_INSERT_LEN
626 #if LWIP_HTTPD_SSI_MULTIPART
627 , current_tag_part, &hs->tag_part
628 #endif /* LWIP_HTTPD_SSI_MULTIPART */
629 #if LWIP_HTTPD_FILE_STATE
630 , hs->handle->state
631 #endif /* LWIP_HTTPD_FILE_STATE */
632 );
633 return;
634 }
635 }
636 }
637
638 /* If we drop out, we were asked to serve a page which contains tags that
639 * we don't have a handler for. Merely echo back the tags with an error
640 * marker. */
641 #define UNKNOWN_TAG1_TEXT "<b>***UNKNOWN TAG "
642 #define UNKNOWN_TAG1_LEN 18
643 #define UNKNOWN_TAG2_TEXT "***</b>"
644 #define UNKNOWN_TAG2_LEN 7
645 len = LWIP_MIN(strlen(hs->tag_name),
646 LWIP_HTTPD_MAX_TAG_INSERT_LEN - (UNKNOWN_TAG1_LEN + UNKNOWN_TAG2_LEN));
647 MEMCPY(hs->tag_insert, UNKNOWN_TAG1_TEXT, UNKNOWN_TAG1_LEN);
648 MEMCPY(&hs->tag_insert[UNKNOWN_TAG1_LEN], hs->tag_name, len);
649 MEMCPY(&hs->tag_insert[UNKNOWN_TAG1_LEN + len], UNKNOWN_TAG2_TEXT, UNKNOWN_TAG2_LEN);
650 hs->tag_insert[UNKNOWN_TAG1_LEN + len + UNKNOWN_TAG2_LEN] = 0;
651
652 len = strlen(hs->tag_insert);
653 LWIP_ASSERT("len <= 0xffff", len <= 0xffff);
654 hs->tag_insert_len = (u16_t)len;
655 }
656 #endif /* LWIP_HTTPD_SSI */
657
658 #if LWIP_HTTPD_DYNAMIC_HEADERS
659
663 static void
664 get_http_headers(struct http_state *pState, char *pszURI)
665 {
666 unsigned int iLoop;
667 char *pszWork;
668 char *pszExt;
669 char *pszVars;
670
671 /* Ensure that we initialize the loop counter. */
672 iLoop = 0;
673
674 /* In all cases, the second header we send is the server identification
675 so set it here. */
676 pState->hdrs[1] = g_psHTTPHeaderStrings[HTTP_HDR_SERVER];
677
678 /* Is this a normal file or the special case we use to send back the
679 default "404: Page not found" response? */
680 if (pszURI == NULL) {
681 pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND];
682 pState->hdrs[2] = g_psHTTPHeaderStrings[DEFAULT_404_HTML];
683
684 /* Set up to send the first header string. */
685 pState->hdr_index = 0;
686 pState->hdr_pos = 0;
687 return;
688 } else {
689 /* We are dealing with a particular filename. Look for one other
690 special case. We assume that any filename with "404" in it must be
691 indicative of a 404 server error whereas all other files require
692 the 200 OK header. */
693 if (strstr(pszURI, "404")) {
694 pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND];
695 } else if (strstr(pszURI, "400")) {
696 pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_BAD_REQUEST];
697 } else if (strstr(pszURI, "501")) {
698 pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_IMPL];
699 } else {
700 pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_OK];
701 }
702
703 /* Determine if the URI has any variables and, if so, temporarily remove
704 them. */
705 pszVars = strchr(pszURI, '?');
706 if(pszVars) {
707 *pszVars = '\0';
708 }
709
710 /* Get a pointer to the file extension. We find this by looking for the
711 last occurrence of "." in the filename passed. */
712 pszExt = NULL;
713 pszWork = strchr(pszURI, '.');
714 while(pszWork) {
715 pszExt = pszWork + 1;
716 pszWork = strchr(pszExt, '.');
717 }
718
719 /* Now determine the content type and add the relevant header for that. */
720 for(iLoop = 0; (iLoop < NUM_HTTP_HEADERS) && pszExt; iLoop++) {
721 /* Have we found a matching extension? */
722 if(!strcmp(g_psHTTPHeaders[iLoop].extension, pszExt)) {
723 pState->hdrs[2] =
724 g_psHTTPHeaderStrings[g_psHTTPHeaders[iLoop].headerIndex];
725 break;
726 }
727 }
728
729 /* Reinstate the parameter marker if there was one in the original URI. */
730 if(pszVars) {
731 *pszVars = '?';
732 }
733 }
734
735 /* Does the URL passed have any file extension? If not, we assume it
736 is a special-case URL used for control state notification and we do
737 not send any HTTP headers with the response. */
738 if(!pszExt) {
739 /* Force the header index to a value indicating that all headers
740 have already been sent. */
741 pState->hdr_index = NUM_FILE_HDR_STRINGS;
742 } else {
743 /* Did we find a matching extension? */
744 if(iLoop == NUM_HTTP_HEADERS) {
745 /* No - use the default, plain text file type. */
746 pState->hdrs[2] = g_psHTTPHeaderStrings[HTTP_HDR_DEFAULT_TYPE];
747 }
748
749 /* Set up to send the first header string. */
750 pState->hdr_index = 0;
751 pState->hdr_pos = 0;
752 }
753 }
754 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
755
762 static u8_t
763 http_send_data(struct tcp_pcb *pcb, struct http_state *hs)
764 {
765 err_t err;
766 u16_t len;
767 u16_t mss;
768 u8_t data_to_send = false;
769 #if LWIP_HTTPD_DYNAMIC_HEADERS
770 u16_t hdrlen, sendlen;
771 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
772
773 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_send_data: pcb=%p hs=%p left=%d\n", (void*)pcb,
774 (void*)hs, hs != NULL ? hs->left : 0));
775
776 #if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
777 if (hs->unrecved_bytes != 0) {
778 return 0;
779 }
780 #endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
781
782 #if LWIP_HTTPD_DYNAMIC_HEADERS
783 /* If we were passed a NULL state structure pointer, ignore the call. */
784 if (hs == NULL) {
785 return 0;
786 }
787
788 /* Assume no error until we find otherwise */
789 err = ERR_OK;
790
791 /* Do we have any more header data to send for this file? */
792 if(hs->hdr_index < NUM_FILE_HDR_STRINGS) {
793 /* How much data can we send? */
794 len = tcp_sndbuf(pcb);
795 sendlen = len;
796
797 while(len && (hs->hdr_index < NUM_FILE_HDR_STRINGS) && sendlen) {
798 const void *ptr;
799 u16_t old_sendlen;
800 /* How much do we have to send from the current header? */
801 hdrlen = (u16_t)strlen(hs->hdrs[hs->hdr_index]);
802
803 /* How much of this can we send? */
804 sendlen = (len < (hdrlen - hs->hdr_pos)) ? len : (hdrlen - hs->hdr_pos);
805
806 /* Send this amount of data or as much as we can given memory
807 * constraints. */
808 ptr = (const void *)(hs->hdrs[hs->hdr_index] + hs->hdr_pos);
809 old_sendlen = sendlen;
810 err = http_write(pcb, ptr, &sendlen, HTTP_IS_HDR_VOLATILE(hs, ptr));
811 if ((err == ERR_OK) && (old_sendlen != sendlen)) {
812 /* Remember that we added some more data to be transmitted. */
813 data_to_send = true;
814 } else if (err != ERR_OK) {
815 /* special case: http_write does not try to send 1 byte */
816 sendlen = 0;
817 }
818
819 /* Fix up the header position for the next time round. */
820 hs->hdr_pos += sendlen;
821 len -= sendlen;
822
823 /* Have we finished sending this string? */
824 if(hs->hdr_pos == hdrlen) {
825 /* Yes - move on to the next one */
826 hs->hdr_index++;
827 hs->hdr_pos = 0;
828 }
829 }
830
831 /* If we get here and there are still header bytes to send, we send
832 * the header information we just wrote immediately. If there are no
833 * more headers to send, but we do have file data to send, drop through
834 * to try to send some file data too. */
835 if((hs->hdr_index < NUM_FILE_HDR_STRINGS) || !hs->file) {
836 LWIP_DEBUGF(HTTPD_DEBUG, ("tcp_output\n"));
837 return 1;
838 }
839 }
840 #else /* LWIP_HTTPD_DYNAMIC_HEADERS */
841 /* Assume no error until we find otherwise */
842 err = ERR_OK;
843 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
844
845 /* Have we run out of file data to send? If so, we need to read the next
846 * block from the file. */
847 if (hs->left == 0) {
848 #if LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS
849 int count;
850 #endif /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */
851
852 /* Do we have a valid file handle? */
853 if (hs->handle == NULL) {
854 /* No - close the connection. */
855 http_close_conn(pcb, hs);
856 return 0;
857 }
858 if (fs_bytes_left(hs->handle) <= 0) {
859 /* We reached the end of the file so this request is done.
860 * @todo: don't close here for HTTP/1.1? */
861 LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
862 http_close_conn(pcb, hs);
863 return 0;
864 }
865 #if LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS
866 /* Do we already have a send buffer allocated? */
867 if(hs->buf) {
868 /* Yes - get the length of the buffer */
869 count = hs->buf_len;
870 } else {
871 /* We don't have a send buffer so allocate one up to 2mss bytes long. */
872 count = 2 * tcp_mss(pcb);
873 do {
874 hs->buf = (char*)mem_malloc((mem_size_t)count);
875 if (hs->buf != NULL) {
876 hs->buf_len = count;
877 break;
878 }
879 count = count / 2;
880 } while (count > 100);
881
882 /* Did we get a send buffer? If not, return immediately. */
883 if (hs->buf == NULL) {
884 LWIP_DEBUGF(HTTPD_DEBUG, ("No buff\n"));
885 return 0;
886 }
887 }
888
889 /* Read a block of data from the file. */
890 LWIP_DEBUGF(HTTPD_DEBUG, ("Trying to read %d bytes.\n", count));
891
892 count = fs_read(hs->handle, hs->buf, count);
893 if(count < 0) {
894 /* We reached the end of the file so this request is done.
895 * @todo: don't close here for HTTP/1.1? */
896 LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
897 http_close_conn(pcb, hs);
898 return 1;
899 }
900
901 /* Set up to send the block of data we just read */
902 LWIP_DEBUGF(HTTPD_DEBUG, ("Read %d bytes.\n", count));
903 hs->left = count;
904 hs->file = hs->buf;
905 #if LWIP_HTTPD_SSI
906 hs->parse_left = count;
907 hs->parsed = hs->buf;
908 #endif /* LWIP_HTTPD_SSI */
909 #else /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */
910 LWIP_ASSERT("SSI and DYNAMIC_HEADERS turned off but eof not reached", 0);
911 #endif /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */
912 }
913
914 #if LWIP_HTTPD_SSI
915 if(!hs->tag_check) {
916 #endif /* LWIP_HTTPD_SSI */
917 /* We are not processing an SHTML file so no tag checking is necessary.
918 * Just send the data as we received it from the file. */
919
920 /* We cannot send more data than space available in the send
921 buffer. */
922 if (tcp_sndbuf(pcb) < hs->left) {
923 len = tcp_sndbuf(pcb);
924 } else {
925 len = (u16_t)hs->left;
926 LWIP_ASSERT("hs->left did not fit into u16_t!", (len == hs->left));
927 }
928 mss = tcp_mss(pcb);
929 if(len > (2 * mss)) {
930 len = 2 * mss;
931 }
932
933 err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
934 if (err == ERR_OK) {
935 data_to_send = true;
936 hs->file += len;
937 hs->left -= len;
938 }
939 #if LWIP_HTTPD_SSI
940 } else {
941 /* We are processing an SHTML file so need to scan for tags and replace
942 * them with insert strings. We need to be careful here since a tag may
943 * straddle the boundary of two blocks read from the file and we may also
944 * have to split the insert string between two tcp_write operations. */
945
946 /* How much data could we send? */
947 len = tcp_sndbuf(pcb);
948
949 /* Do we have remaining data to send before parsing more? */
950 if(hs->parsed > hs->file) {
951 /* We cannot send more data than space available in the send
952 buffer. */
953 if (tcp_sndbuf(pcb) < (hs->parsed - hs->file)) {
954 len = tcp_sndbuf(pcb);
955 } else {
956 LWIP_ASSERT("Data size does not fit into u16_t!",
957 (hs->parsed - hs->file) <= 0xffff);
958 len = (u16_t)(hs->parsed - hs->file);
959 }
960 mss = tcp_mss(pcb);
961 if(len > (2 * mss)) {
962 len = 2 * mss;
963 }
964
965 err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
966 if (err == ERR_OK) {
967 data_to_send = true;
968 hs->file += len;
969 hs->left -= len;
970 }
971
972 /* If the send buffer is full, return now. */
973 if(tcp_sndbuf(pcb) == 0) {
974 return data_to_send;
975 }
976 }
977
978 LWIP_DEBUGF(HTTPD_DEBUG, ("State %d, %d left\n", hs->tag_state, hs->parse_left));
979
980 /* We have sent all the data that was already parsed so continue parsing
981 * the buffer contents looking for SSI tags. */
982 while((hs->parse_left) && (err == ERR_OK)) {
983 /* @todo: somewhere in this loop, 'len' should grow again... */
984 if (len == 0) {
985 return data_to_send;
986 }
987 switch(hs->tag_state) {
988 case TAG_NONE:
989 /* We are not currently processing an SSI tag so scan for the
990 * start of the lead-in marker. */
991 if(*hs->parsed == g_pcTagLeadIn[0]) {
992 /* We found what could be the lead-in for a new tag so change
993 * state appropriately. */
994 hs->tag_state = TAG_LEADIN;
995 hs->tag_index = 1;
996 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
997 hs->tag_started = hs->parsed;
998 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */
999 }
1000
1001 /* Move on to the next character in the buffer */
1002 hs->parse_left--;
1003 hs->parsed++;
1004 break;
1005
1006 case TAG_LEADIN:
1007 /* We are processing the lead-in marker, looking for the start of
1008 * the tag name. */
1009
1010 /* Have we reached the end of the leadin? */
1011 if(hs->tag_index == LEN_TAG_LEAD_IN) {
1012 hs->tag_index = 0;
1013 hs->tag_state = TAG_FOUND;
1014 } else {
1015 /* Have we found the next character we expect for the tag leadin? */
1016 if(*hs->parsed == g_pcTagLeadIn[hs->tag_index]) {
1017 /* Yes - move to the next one unless we have found the complete
1018 * leadin, in which case we start looking for the tag itself */
1019 hs->tag_index++;
1020 } else {
1021 /* We found an unexpected character so this is not a tag. Move
1022 * back to idle state. */
1023 hs->tag_state = TAG_NONE;
1024 }
1025
1026 /* Move on to the next character in the buffer */
1027 hs->parse_left--;
1028 hs->parsed++;
1029 }
1030 break;
1031
1032 case TAG_FOUND:
1033 /* We are reading the tag name, looking for the start of the
1034 * lead-out marker and removing any whitespace found. */
1035
1036 /* Remove leading whitespace between the tag leading and the first
1037 * tag name character. */
1038 if((hs->tag_index == 0) && ((*hs->parsed == ' ') ||
1039 (*hs->parsed == '\t') || (*hs->parsed == '\n') ||
1040 (*hs->parsed == '\r'))) {
1041 /* Move on to the next character in the buffer */
1042 hs->parse_left--;
1043 hs->parsed++;
1044 break;
1045 }
1046
1047 /* Have we found the end of the tag name? This is signalled by
1048 * us finding the first leadout character or whitespace */
1049 if((*hs->parsed == g_pcTagLeadOut[0]) ||
1050 (*hs->parsed == ' ') || (*hs->parsed == '\t') ||
1051 (*hs->parsed == '\n') || (*hs->parsed == '\r')) {
1052
1053 if(hs->tag_index == 0) {
1054 /* We read a zero length tag so ignore it. */
1055 hs->tag_state = TAG_NONE;
1056 } else {
1057 /* We read a non-empty tag so go ahead and look for the
1058 * leadout string. */
1059 hs->tag_state = TAG_LEADOUT;
1060 LWIP_ASSERT("hs->tag_index <= 0xff", hs->tag_index <= 0xff);
1061 hs->tag_name_len = (u8_t)hs->tag_index;
1062 hs->tag_name[hs->tag_index] = '\0';
1063 if(*hs->parsed == g_pcTagLeadOut[0]) {
1064 hs->tag_index = 1;
1065 } else {
1066 hs->tag_index = 0;
1067 }
1068 }
1069 } else {
1070 /* This character is part of the tag name so save it */
1071 if(hs->tag_index < LWIP_HTTPD_MAX_TAG_NAME_LEN) {
1072 hs->tag_name[hs->tag_index++] = *hs->parsed;
1073 } else {
1074 /* The tag was too long so ignore it. */
1075 hs->tag_state = TAG_NONE;
1076 }
1077 }
1078
1079 /* Move on to the next character in the buffer */
1080 hs->parse_left--;
1081 hs->parsed++;
1082
1083 break;
1084
1085 /* We are looking for the end of the lead-out marker. */
1086 case TAG_LEADOUT:
1087 /* Remove leading whitespace between the tag leading and the first
1088 * tag leadout character. */
1089 if((hs->tag_index == 0) && ((*hs->parsed == ' ') ||
1090 (*hs->parsed == '\t') || (*hs->parsed == '\n') ||
1091 (*hs->parsed == '\r'))) {
1092 /* Move on to the next character in the buffer */
1093 hs->parse_left--;
1094 hs->parsed++;
1095 break;
1096 }
1097
1098 /* Have we found the next character we expect for the tag leadout? */
1099 if(*hs->parsed == g_pcTagLeadOut[hs->tag_index]) {
1100 /* Yes - move to the next one unless we have found the complete
1101 * leadout, in which case we need to call the client to process
1102 * the tag. */
1103
1104 /* Move on to the next character in the buffer */
1105 hs->parse_left--;
1106 hs->parsed++;
1107
1108 if(hs->tag_index == (LEN_TAG_LEAD_OUT - 1)) {
1109 /* Call the client to ask for the insert string for the
1110 * tag we just found. */
1111 #if LWIP_HTTPD_SSI_MULTIPART
1112 hs->tag_part = 0; /* start with tag part 0 */
1113 #endif /* LWIP_HTTPD_SSI_MULTIPART */
1114 get_tag_insert(hs);
1115
1116 /* Next time through, we are going to be sending data
1117 * immediately, either the end of the block we start
1118 * sending here or the insert string. */
1119 hs->tag_index = 0;
1120 hs->tag_state = TAG_SENDING;
1121 hs->tag_end = hs->parsed;
1122 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
1123 hs->parsed = hs->tag_started;
1124 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
1125
1126 /* If there is any unsent data in the buffer prior to the
1127 * tag, we need to send it now. */
1128 if (hs->tag_end > hs->file) {
1129 /* How much of the data can we send? */
1130 #if LWIP_HTTPD_SSI_INCLUDE_TAG
1131 if(len > hs->tag_end - hs->file) {
1132 len = (u16_t)(hs->tag_end - hs->file);
1133 }
1134 #else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
1135 if(len > hs->tag_started - hs->file) {
1136 /* we would include the tag in sending */
1137 len = (u16_t)(hs->tag_started - hs->file);
1138 }
1139 #endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
1140
1141 err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1142 if (err == ERR_OK) {
1143 data_to_send = true;
1144 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
1145 if(hs->tag_started <= hs->file) {
1146 /* pretend to have sent the tag, too */
1147 len += hs->tag_end - hs->tag_started;
1148 }
1149 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
1150 hs->file += len;
1151 hs->left -= len;
1152 }
1153 }
1154 } else {
1155 hs->tag_index++;
1156 }
1157 } else {
1158 /* We found an unexpected character so this is not a tag. Move
1159 * back to idle state. */
1160 hs->parse_left--;
1161 hs->parsed++;
1162 hs->tag_state = TAG_NONE;
1163 }
1164 break;
1165
1166 /*
1167 * We have found a valid tag and are in the process of sending
1168 * data as a result of that discovery. We send either remaining data
1169 * from the file prior to the insert point or the insert string itself.
1170 */
1171 case TAG_SENDING:
1172 /* Do we have any remaining file data to send from the buffer prior
1173 * to the tag? */
1174 if(hs->tag_end > hs->file) {
1175 /* How much of the data can we send? */
1176 #if LWIP_HTTPD_SSI_INCLUDE_TAG
1177 if(len > hs->tag_end - hs->file) {
1178 len = (u16_t)(hs->tag_end - hs->file);
1179 }
1180 #else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
1181 LWIP_ASSERT("hs->started >= hs->file", hs->tag_started >= hs->file);
1182 if (len > hs->tag_started - hs->file) {
1183 /* we would include the tag in sending */
1184 len = (u16_t)(hs->tag_started - hs->file);
1185 }
1186 #endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/
1187 if (len != 0) {
1188 err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1189 } else {
1190 err = ERR_OK;
1191 }
1192 if (err == ERR_OK) {
1193 data_to_send = true;
1194 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
1195 if(hs->tag_started <= hs->file) {
1196 /* pretend to have sent the tag, too */
1197 len += hs->tag_end - hs->tag_started;
1198 }
1199 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
1200 hs->file += len;
1201 hs->left -= len;
1202 }
1203 } else {
1204 #if LWIP_HTTPD_SSI_MULTIPART
1205 if(hs->tag_index >= hs->tag_insert_len) {
1206 /* Did the last SSIHandler have more to send? */
1207 if (hs->tag_part != HTTPD_LAST_TAG_PART) {
1208 /* If so, call it again */
1209 hs->tag_index = 0;
1210 get_tag_insert(hs);
1211 }
1212 }
1213 #endif /* LWIP_HTTPD_SSI_MULTIPART */
1214
1215 /* Do we still have insert data left to send? */
1216 if(hs->tag_index < hs->tag_insert_len) {
1217 /* We are sending the insert string itself. How much of the
1218 * insert can we send? */
1219 if(len > (hs->tag_insert_len - hs->tag_index)) {
1220 len = (hs->tag_insert_len - hs->tag_index);
1221 }
1222
1223 /* Note that we set the copy flag here since we only have a
1224 * single tag insert buffer per connection. If we don't do
1225 * this, insert corruption can occur if more than one insert
1226 * is processed before we call tcp_output. */
1227 err = http_write(pcb, &(hs->tag_insert[hs->tag_index]), &len,
1228 HTTP_IS_TAG_VOLATILE(hs));
1229 if (err == ERR_OK) {
1230 data_to_send = true;
1231 hs->tag_index += len;
1232 /* Don't return here: keep on sending data */
1233 }
1234 } else {
1235 /* We have sent all the insert data so go back to looking for
1236 * a new tag. */
1237 LWIP_DEBUGF(HTTPD_DEBUG, ("Everything sent.\n"));
1238 hs->tag_index = 0;
1239 hs->tag_state = TAG_NONE;
1240 #if !LWIP_HTTPD_SSI_INCLUDE_TAG
1241 hs->parsed = hs->tag_end;
1242 #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/
1243 }
1244 break;
1245 }
1246 }
1247 }
1248
1249 /* If we drop out of the end of the for loop, this implies we must have
1250 * file data to send so send it now. In TAG_SENDING state, we've already
1251 * handled this so skip the send if that's the case. */
1252 if((hs->tag_state != TAG_SENDING) && (hs->parsed > hs->file)) {
1253 /* We cannot send more data than space available in the send
1254 buffer. */
1255 if (tcp_sndbuf(pcb) < (hs->parsed - hs->file)) {
1256 len = tcp_sndbuf(pcb);
1257 } else {
1258 LWIP_ASSERT("Data size does not fit into u16_t!",
1259 (hs->parsed - hs->file) <= 0xffff);
1260 len = (u16_t)(hs->parsed - hs->file);
1261 }
1262 if(len > (2 * tcp_mss(pcb))) {
1263 len = 2 * tcp_mss(pcb);
1264 }
1265
1266 err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs));
1267 if (err == ERR_OK) {
1268 data_to_send = true;
1269 hs->file += len;
1270 hs->left -= len;
1271 }
1272 }
1273 }
1274 #endif /* LWIP_HTTPD_SSI */
1275
1276 if((hs->left == 0) && (fs_bytes_left(hs->handle) <= 0)) {
1277 /* We reached the end of the file so this request is done.
1278 * This adds the FIN flag right into the last data segment.
1279 * @todo: don't close here for HTTP/1.1? */
1280 LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n"));
1281 http_close_conn(pcb, hs);
1282 return 0;
1283 }
1284 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("send_data end.\n"));
1285 return data_to_send;
1286 }
1287
1288 #if LWIP_HTTPD_SUPPORT_EXTSTATUS
1289
1296 static err_t
1297 http_find_error_file(struct http_state *hs, u16_t error_nr)
1298 {
1299 const char *uri1, *uri2, *uri3;
1300 struct fs_file *file;
1301
1302 if (error_nr == 501) {
1303 uri1 = "/501.html";
1304 uri2 = "/501.htm";
1305 uri3 = "/501.shtml";
1306 } else {
1307 /* 400 (bad request is the default) */
1308 uri1 = "/400.html";
1309 uri2 = "/400.htm";
1310 uri3 = "/400.shtml";
1311 }
1312 file = fs_open(uri1);
1313 if (file == NULL) {
1314 file = fs_open(uri2);
1315 if (file == NULL) {
1316 file = fs_open(uri3);
1317 if (file == NULL) {
1318 LWIP_DEBUGF(HTTPD_DEBUG, ("Error page for error %"U16_F" not found\n",
1319 error_nr));
1320 return ERR_ARG;
1321 }
1322 }
1323 }
1324 return http_init_file(hs, file, 0, NULL);
1325 }
1326 #else /* LWIP_HTTPD_SUPPORT_EXTSTATUS */
1327 #define http_find_error_file(hs, error_nr) ERR_ARG
1328 #endif /* LWIP_HTTPD_SUPPORT_EXTSTATUS */
1329
1337 static struct fs_file *
1338 http_get_404_file(const char **uri)
1339 {
1340 struct fs_file *file;
1341
1342 *uri = "/404.html";
1343 file = fs_open(*uri);
1344 if(file == NULL) {
1345 /* 404.html doesn't exist. Try 404.htm instead. */
1346 *uri = "/404.htm";
1347 file = fs_open(*uri);
1348 if(file == NULL) {
1349 /* 404.htm doesn't exist either. Try 404.shtml instead. */
1350 *uri = "/404.shtml";
1351 file = fs_open(*uri);
1352 if(file == NULL) {
1353 /* 404.htm doesn't exist either. Indicate to the caller that it should
1354 * send back a default 404 page.
1355 */
1356 *uri = NULL;
1357 }
1358 }
1359 }
1360
1361 return file;
1362 }
1363
1364 #if LWIP_HTTPD_SUPPORT_POST
1365 static err_t
1366 http_handle_post_finished(struct http_state *hs)
1367 {
1368 /* application error or POST finished */
1369 /* NULL-terminate the buffer */
1370 http_post_response_filename[0] = 0;
1371 httpd_post_finished(hs, http_post_response_filename, LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN);
1372 return http_find_file(hs, http_post_response_filename, 0);
1373 }
1374
1384 static err_t
1385 http_post_rxpbuf(struct http_state *hs, struct pbuf *p)
1386 {
1387 err_t err;
1388
1389 /* adjust remaining Content-Length */
1390 if (hs->post_content_len_left < p->tot_len) {
1391 hs->post_content_len_left = 0;
1392 } else {
1393 hs->post_content_len_left -= p->tot_len;
1394 }
1395 err = httpd_post_receive_data(hs, p);
1396 if ((err != ERR_OK) || (hs->post_content_len_left == 0)) {
1397 #if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
1398 if (hs->unrecved_bytes != 0) {
1399 return ERR_OK;
1400 }
1401 #endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
1402 /* application error or POST finished */
1403 return http_handle_post_finished(hs);
1404 }
1405
1406 return ERR_OK;
1407 }
1408
1424 static err_t
1425 http_post_request(struct tcp_pcb *pcb, struct pbuf **inp, struct http_state *hs,
1426 char *data, u16_t data_len, char *uri, char *uri_end)
1427 {
1428 err_t err;
1429 /* search for end-of-header (first double-CRLF) */
1430 char* crlfcrlf = strnstr(uri_end + 1, CRLF CRLF, data_len - (uri_end + 1 - data));
1431
1432 #if LWIP_HTTPD_POST_MANUAL_WND
1433 hs->pcb = pcb;
1434 #else /* LWIP_HTTPD_POST_MANUAL_WND */
1435 LWIP_UNUSED_ARG(pcb); /* only used for LWIP_HTTPD_POST_MANUAL_WND */
1436 #endif /* LWIP_HTTPD_POST_MANUAL_WND */
1437
1438 if (crlfcrlf != NULL) {
1439 /* search for "Content-Length: " */
1440 #define HTTP_HDR_CONTENT_LEN "Content-Length: "
1441 #define HTTP_HDR_CONTENT_LEN_LEN 16
1442 #define HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN 10
1443 char *scontent_len = strnstr(uri_end + 1, HTTP_HDR_CONTENT_LEN, crlfcrlf - (uri_end + 1));
1444 if (scontent_len != NULL) {
1445 char *scontent_len_end = strnstr(scontent_len + HTTP_HDR_CONTENT_LEN_LEN, CRLF, HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN);
1446 if (scontent_len_end != NULL) {
1447 int content_len;
1448 char *conten_len_num = scontent_len + HTTP_HDR_CONTENT_LEN_LEN;
1449 *scontent_len_end = 0;
1450 content_len = atoi(conten_len_num);
1451 if (content_len > 0) {
1452 /* adjust length of HTTP header passed to application */
1453 const char *hdr_start_after_uri = uri_end + 1;
1454 u16_t hdr_len = LWIP_MIN(data_len, crlfcrlf + 4 - data);
1455 u16_t hdr_data_len = LWIP_MIN(data_len, crlfcrlf + 4 - hdr_start_after_uri);
1456 u8_t post_auto_wnd = 1;
1457 http_post_response_filename[0] = 0;
1458 err = httpd_post_begin(hs, uri, hdr_start_after_uri, hdr_data_len, content_len,
1459 http_post_response_filename, LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN, &post_auto_wnd);
1460 if (err == ERR_OK) {
1461 /* try to pass in data of the first pbuf(s) */
1462 struct pbuf *q = *inp;
1463 u16_t start_offset = hdr_len;
1464 #if LWIP_HTTPD_POST_MANUAL_WND
1465 hs->no_auto_wnd = !post_auto_wnd;
1466 #endif /* LWIP_HTTPD_POST_MANUAL_WND */
1467 /* set the Content-Length to be received for this POST */
1468 hs->post_content_len_left = (u32_t)content_len;
1469
1470 /* get to the pbuf where the body starts */
1471 while((q != NULL) && (q->len <= start_offset)) {
1472 struct pbuf *head = q;
1473 start_offset -= q->len;
1474 q = q->next;
1475 /* free the head pbuf */
1476 head->next = NULL;
1477 pbuf_free(head);
1478 }
1479 *inp = NULL;
1480 if (q != NULL) {
1481 /* hide the remaining HTTP header */
1482 pbuf_header(q, -(s16_t)start_offset);
1483 #if LWIP_HTTPD_POST_MANUAL_WND
1484 if (!post_auto_wnd) {
1485 /* already tcp_recved() this data... */
1486 hs->unrecved_bytes = q->tot_len;
1487 }
1488 #endif /* LWIP_HTTPD_POST_MANUAL_WND */
1489 return http_post_rxpbuf(hs, q);
1490 } else {
1491 return ERR_OK;
1492 }
1493 } else {
1494 /* return file passed from application */
1495 return http_find_file(hs, http_post_response_filename, 0);
1496 }
1497 } else {
1498 LWIP_DEBUGF(HTTPD_DEBUG, ("POST received invalid Content-Length: %s\n",
1499 conten_len_num));
1500 return ERR_ARG;
1501 }
1502 }
1503 }
1504 }
1505 /* if we come here, the POST is incomplete */
1506 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
1507 return ERR_INPROGRESS;
1508 #else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1509 return ERR_ARG;
1510 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1511 }
1512
1513 #if LWIP_HTTPD_POST_MANUAL_WND
1514
1522 void httpd_post_data_recved(void *connection, u16_t recved_len)
1523 {
1524 struct http_state *hs = (struct http_state*)connection;
1525 if (hs != NULL) {
1526 if (hs->no_auto_wnd) {
1527 u16_t len = recved_len;
1528 if (hs->unrecved_bytes >= recved_len) {
1529 hs->unrecved_bytes -= recved_len;
1530 } else {
1531 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_LEVEL_WARNING, ("httpd_post_data_recved: recved_len too big\n"));
1532 len = (u16_t)hs->unrecved_bytes;
1533 hs->unrecved_bytes = 0;
1534 }
1535 if (hs->pcb != NULL) {
1536 if (len != 0) {
1537 tcp_recved(hs->pcb, len);
1538 }
1539 if ((hs->post_content_len_left == 0) && (hs->unrecved_bytes == 0)) {
1540 /* finished handling POST */
1541 http_handle_post_finished(hs);
1542 http_send_data(hs->pcb, hs);
1543 }
1544 }
1545 }
1546 }
1547 }
1548 #endif /* LWIP_HTTPD_POST_MANUAL_WND */
1549
1550 #endif /* LWIP_HTTPD_SUPPORT_POST */
1551
1563 static err_t
1564 http_parse_request(struct pbuf **inp, struct http_state *hs, struct tcp_pcb *pcb)
1565 {
1566 char *data;
1567 char *crlf;
1568 u16_t data_len;
1569 struct pbuf *p = *inp;
1570 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
1571 u16_t clen;
1572 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1573 #if LWIP_HTTPD_SUPPORT_POST
1574 err_t err;
1575 #endif /* LWIP_HTTPD_SUPPORT_POST */
1576
1577 LWIP_UNUSED_ARG(pcb); /* only used for post */
1578 LWIP_ASSERT("p != NULL", p != NULL);
1579 LWIP_ASSERT("hs != NULL", hs != NULL);
1580
1581 if ((hs->handle != NULL) || (hs->file != NULL)) {
1582 LWIP_DEBUGF(HTTPD_DEBUG, ("Received data while sending a file\n"));
1583 /* already sending a file */
1584 /* @todo: abort? */
1585 return ERR_USE;
1586 }
1587
1588 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
1589
1590 LWIP_DEBUGF(HTTPD_DEBUG, ("Received %"U16_F" bytes\n", p->tot_len));
1591
1592 /* first check allowed characters in this pbuf? */
1593
1594 /* enqueue the pbuf */
1595 if (hs->req == NULL) {
1596 LWIP_DEBUGF(HTTPD_DEBUG, ("First pbuf\n"));
1597 hs->req = p;
1598 } else {
1599 LWIP_DEBUGF(HTTPD_DEBUG, ("pbuf enqueued\n"));
1600 pbuf_cat(hs->req, p);
1601 }
1602
1603 if (hs->req->next != NULL) {
1604 data_len = LWIP_MIN(hs->req->tot_len, LWIP_HTTPD_MAX_REQ_LENGTH);
1605 pbuf_copy_partial(hs->req, httpd_req_buf, data_len, 0);
1606 data = httpd_req_buf;
1607 } else
1608 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1609 {
1610 data = (char *)p->payload;
1611 data_len = p->len;
1612 if (p->len != p->tot_len) {
1613 LWIP_DEBUGF(HTTPD_DEBUG, ("Warning: incomplete header due to chained pbufs\n"));
1614 }
1615 }
1616
1617 /* received enough data for minimal request? */
1618 if (data_len >= MIN_REQ_LEN) {
1619 /* wait for CRLF before parsing anything */
1620 crlf = strnstr(data, CRLF, data_len);
1621 if (crlf != NULL) {
1622 #if LWIP_HTTPD_SUPPORT_POST
1623 int is_post = 0;
1624 #endif /* LWIP_HTTPD_SUPPORT_POST */
1625 int is_09 = 0;
1626 char *sp1, *sp2;
1627 u16_t left_len, uri_len;
1628 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("CRLF received, parsing request\n"));
1629 /* parse method */
1630 if (!strncmp(data, "GET ", 4)) {
1631 sp1 = data + 3;
1632 /* received GET request */
1633 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received GET request\"\n"));
1634 #if LWIP_HTTPD_SUPPORT_POST
1635 } else if (!strncmp(data, "POST ", 5)) {
1636 /* store request type */
1637 is_post = 1;
1638 sp1 = data + 4;
1639 /* received GET request */
1640 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received POST request\n"));
1641 #endif /* LWIP_HTTPD_SUPPORT_POST */
1642 } else {
1643 /* null-terminate the METHOD (pbuf is freed anyway wen returning) */
1644 data[4] = 0;
1645 /* unsupported method! */
1646 LWIP_DEBUGF(HTTPD_DEBUG, ("Unsupported request method (not implemented): \"%s\"\n",
1647 data));
1648 return http_find_error_file(hs, 501);
1649 }
1650 /* if we come here, method is OK, parse URI */
1651 left_len = data_len - ((sp1 +1) - data);
1652 sp2 = strnstr(sp1 + 1, " ", left_len);
1653 #if LWIP_HTTPD_SUPPORT_V09
1654 if (sp2 == NULL) {
1655 /* HTTP 0.9: respond with correct protocol version */
1656 sp2 = strnstr(sp1 + 1, CRLF, left_len);
1657 is_09 = 1;
1658 #if LWIP_HTTPD_SUPPORT_POST
1659 if (is_post) {
1660 /* HTTP/0.9 does not support POST */
1661 goto badrequest;
1662 }
1663 #endif /* LWIP_HTTPD_SUPPORT_POST */
1664 }
1665 #endif /* LWIP_HTTPD_SUPPORT_V09 */
1666 uri_len = sp2 - (sp1 + 1);
1667 if ((sp2 != 0) && (sp2 > sp1)) {
1668 char *uri = sp1 + 1;
1669 /* null-terminate the METHOD (pbuf is freed anyway wen returning) */
1670 *sp1 = 0;
1671 uri[uri_len] = 0;
1672 LWIP_DEBUGF(HTTPD_DEBUG, ("Received \"%s\" request for URI: \"%s\"\n",
1673 data, uri));
1674 #if LWIP_HTTPD_SUPPORT_POST
1675 if (is_post) {
1676 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
1677 struct pbuf **q = &hs->req;
1678 #else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1679 struct pbuf **q = inp;
1680 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1681 err = http_post_request(pcb, q, hs, data, data_len, uri, sp2);
1682 if (err != ERR_OK) {
1683 /* restore header for next try */
1684 *sp1 = ' ';
1685 *sp2 = ' ';
1686 uri[uri_len] = ' ';
1687 }
1688 if (err == ERR_ARG) {
1689 goto badrequest;
1690 }
1691 return err;
1692 } else
1693 #endif /* LWIP_HTTPD_SUPPORT_POST */
1694 {
1695 return http_find_file(hs, uri, is_09);
1696 }
1697 } else {
1698 LWIP_DEBUGF(HTTPD_DEBUG, ("invalid URI\n"));
1699 }
1700 }
1701 }
1702
1703 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
1704 clen = pbuf_clen(hs->req);
1705 if ((hs->req->tot_len <= LWIP_HTTPD_REQ_BUFSIZE) &&
1706 (clen <= LWIP_HTTPD_REQ_QUEUELEN)) {
1707 /* request not fully received (too short or CRLF is missing) */
1708 return ERR_INPROGRESS;
1709 } else
1710 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
1711 {
1712 #if LWIP_HTTPD_SUPPORT_POST
1713 badrequest:
1714 #endif /* LWIP_HTTPD_SUPPORT_POST */
1715 LWIP_DEBUGF(HTTPD_DEBUG, ("bad request\n"));
1716 /* could not parse request */
1717 return http_find_error_file(hs, 400);
1718 }
1719 }
1720
1730 static err_t
1731 http_find_file(struct http_state *hs, const char *uri, int is_09)
1732 {
1733 size_t loop;
1734 struct fs_file *file = NULL;
1735 char *params;
1736 #if LWIP_HTTPD_CGI
1737 int i;
1738 int count;
1739 #endif /* LWIP_HTTPD_CGI */
1740
1741 #if LWIP_HTTPD_SSI
1742 /*
1743 * By default, assume we will not be processing server-side-includes
1744 * tags
1745 */
1746 hs->tag_check = false;
1747 #endif /* LWIP_HTTPD_SSI */
1748
1749 /* Have we been asked for the default root file? */
1750 if((uri[0] == '/') && (uri[1] == 0)) {
1751 /* Try each of the configured default filenames until we find one
1752 that exists. */
1753 for (loop = 0; loop < NUM_DEFAULT_FILENAMES; loop++) {
1754 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Looking for %s...\n", g_psDefaultFilenames[loop].name));
1755 file = fs_open((char *)g_psDefaultFilenames[loop].name);
1756 uri = (char *)g_psDefaultFilenames[loop].name;
1757 if(file != NULL) {
1758 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opened.\n"));
1759 #if LWIP_HTTPD_SSI
1760 hs->tag_check = g_psDefaultFilenames[loop].shtml;
1761 #endif /* LWIP_HTTPD_SSI */
1762 break;
1763 }
1764 }
1765 if (file == NULL) {
1766 extern struct fs_file *fs_open_default(void);
1767 file = fs_open_default();
1768 if (file == NULL)
1769 /* None of the default filenames exist so send back a 404 page */
1770 file = http_get_404_file(&uri);
1771 #if LWIP_HTTPD_SSI
1772 hs->tag_check = false;
1773 #endif /* LWIP_HTTPD_SSI */
1774 }
1775 } else {
1776 /* No - we've been asked for a specific file. */
1777 /* First, isolate the base URI (without any parameters) */
1778 params = (char *)strchr(uri, '?');
1779 if (params != NULL) {
1780 /* URI contains parameters. NULL-terminate the base URI */
1781 *params = '\0';
1782 params++;
1783 }
1784
1785 #if LWIP_HTTPD_CGI
1786 /* Does the base URI we have isolated correspond to a CGI handler? */
1787 if (g_iNumCGIs && g_pCGIs) {
1788 for (i = 0; i < g_iNumCGIs; i++) {
1789 if (strcmp(uri, g_pCGIs[i].pcCGIName) == 0) {
1790 /*
1791 * We found a CGI that handles this URI so extract the
1792 * parameters and call the handler.
1793 */
1794 count = extract_uri_parameters(hs, params);
1795 uri = g_pCGIs[i].pfnCGIHandler(i, count, hs->params,
1796 hs->param_vals);
1797 break;
1798 }
1799 }
1800 }
1801 #endif /* LWIP_HTTPD_CGI */
1802
1803 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opening %s\n", uri));
1804
1805 file = fs_open(uri);
1806 if (file == NULL) {
1807 file = http_get_404_file(&uri);
1808 }
1809 #if LWIP_HTTPD_SSI
1810 if (file != NULL) {
1811 /*
1812 * See if we have been asked for an shtml file and, if so,
1813 * enable tag checking.
1814 */
1815 hs->tag_check = false;
1816 for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) {
1817 if (strstr(uri, g_pcSSIExtensions[loop])) {
1818 hs->tag_check = true;
1819 break;
1820 }
1821 }
1822 }
1823 #endif /* LWIP_HTTPD_SSI */
1824 }
1825 return http_init_file(hs, file, is_09, uri);
1826 }
1827
1838 static err_t
1839 http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri)
1840 {
1841 if (file != NULL) {
1842 /* file opened, initialise struct http_state */
1843 #if LWIP_HTTPD_SSI
1844 hs->tag_index = 0;
1845 hs->tag_state = TAG_NONE;
1846 hs->parsed = file->data;
1847 hs->parse_left = file->len;
1848 hs->tag_end = file->data;
1849 #endif /* LWIP_HTTPD_SSI */
1850 hs->handle = file;
1851 hs->file = (char*)file->data;
1852 LWIP_ASSERT("File length must be positive!", (file->len >= 0));
1853 hs->left = file->index;
1854 hs->retries = 0;
1855 #if LWIP_HTTPD_TIMING
1856 hs->time_started = sys_now();
1857 #endif /* LWIP_HTTPD_TIMING */
1858 #if !LWIP_HTTPD_DYNAMIC_HEADERS
1859 LWIP_ASSERT("HTTP headers not included in file system", hs->handle->http_header_included);
1860 #endif /* !LWIP_HTTPD_DYNAMIC_HEADERS */
1861 #if LWIP_HTTPD_SUPPORT_V09
1862 if (hs->handle->http_header_included && is_09) {
1863 /* HTTP/0.9 responses are sent without HTTP header,
1864 search for the end of the header. */
1865 char *file_start = strnstr(hs->file, CRLF CRLF, hs->left);
1866 if (file_start != NULL) {
1867 size_t diff = file_start + 4 - hs->file;
1868 hs->file += diff;
1869 hs->left -= (u32_t)diff;
1870 }
1871 }
1872 #endif /* LWIP_HTTPD_SUPPORT_V09*/
1873 } else {
1874 hs->handle = NULL;
1875 hs->file = NULL;
1876 hs->left = 0;
1877 hs->retries = 0;
1878 }
1879 #if LWIP_HTTPD_DYNAMIC_HEADERS
1880 /* Determine the HTTP headers to send based on the file extension of
1881 * the requested URI. */
1882 if ((hs->handle == NULL) || !hs->handle->http_header_included) {
1883 get_http_headers(hs, (char*)uri);
1884 }
1885 #else /* LWIP_HTTPD_DYNAMIC_HEADERS */
1886 LWIP_UNUSED_ARG(uri);
1887 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
1888 return ERR_OK;
1889 }
1890
1895 static void
1896 http_err(void *arg, err_t err)
1897 {
1898 struct http_state *hs = (struct http_state *)arg;
1899 LWIP_UNUSED_ARG(err);
1900
1901 LWIP_DEBUGF(HTTPD_DEBUG, ("http_err: %s", lwip_strerr(err)));
1902
1903 if (hs != NULL) {
1904 http_state_free(hs);
1905 }
1906 }
1907
1912 static err_t
1913 http_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
1914 {
1915 struct http_state *hs = (struct http_state *)arg;
1916
1917 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_sent %p\n", (void*)pcb));
1918
1919 LWIP_UNUSED_ARG(len);
1920
1921 if (hs == NULL) {
1922 return ERR_OK;
1923 }
1924
1925 hs->retries = 0;
1926
1927 http_send_data(pcb, hs);
1928
1929 return ERR_OK;
1930 }
1931
1939 static err_t
1940 http_poll(void *arg, struct tcp_pcb *pcb)
1941 {
1942 struct http_state *hs = (struct http_state *)arg;
1943 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_poll: pcb=%p hs=%p pcb_state=%s\n",
1944 (void*)pcb, (void*)hs, tcp_debug_state_str(pcb->state)));
1945
1946 if (hs == NULL) {
1947 err_t closed;
1948 /* arg is null, close. */
1949 LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: arg is NULL, close\n"));
1950 closed = http_close_conn(pcb, hs);
1951 LWIP_UNUSED_ARG(closed);
1952 #if LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR
1953 if (closed == ERR_MEM) {
1954 tcp_abort(pcb);
1955 return ERR_ABRT;
1956 }
1957 #endif /* LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR */
1958 return ERR_OK;
1959 } else {
1960 hs->retries++;
1961 if (hs->retries == HTTPD_MAX_RETRIES) {
1962 LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: too many retries, close\n"));
1963 http_close_conn(pcb, hs);
1964 return ERR_OK;
1965 }
1966
1967 /* If this connection has a file open, try to send some more data. If
1968 * it has not yet received a GET request, don't do this since it will
1969 * cause the connection to close immediately. */
1970 if(hs && (hs->handle)) {
1971 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_poll: try to send more data\n"));
1972 if(http_send_data(pcb, hs)) {
1973 /* If we wrote anything to be sent, go ahead and send it now. */
1974 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("tcp_output\n"));
1975 tcp_output(pcb);
1976 }
1977 }
1978 }
1979
1980 return ERR_OK;
1981 }
1982
1987 static err_t
1988 http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
1989 {
1990 err_t parsed = ERR_ABRT;
1991 struct http_state *hs = (struct http_state *)arg;
1992 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_recv: pcb=%p pbuf=%p err=%s\n", (void*)pcb,
1993 (void*)p, lwip_strerr(err)));
1994
1995 if ((err != ERR_OK) || (p == NULL) || (hs == NULL)) {
1996 /* error or closed by other side? */
1997 if (p != NULL) {
1998 /* Inform TCP that we have taken the data. */
1999 tcp_recved(pcb, p->tot_len);
2000 pbuf_free(p);
2001 }
2002 if (hs == NULL) {
2003 /* this should not happen, only to be robust */
2004 LWIP_DEBUGF(HTTPD_DEBUG, ("Error, http_recv: hs is NULL, close\n"));
2005 }
2006 http_close_conn(pcb, hs);
2007 return ERR_OK;
2008 }
2009
2010 #if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND
2011 if (hs->no_auto_wnd) {
2012 hs->unrecved_bytes += p->tot_len;
2013 } else
2014 #endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */
2015 {
2016 /* Inform TCP that we have taken the data. */
2017 tcp_recved(pcb, p->tot_len);
2018 }
2019
2020 #if LWIP_HTTPD_SUPPORT_POST
2021 if (hs->post_content_len_left > 0) {
2022 /* reset idle counter when POST data is received */
2023 hs->retries = 0;
2024 /* this is data for a POST, pass the complete pbuf to the application */
2025 http_post_rxpbuf(hs, p);
2026 /* pbuf is passed to the application, don't free it! */
2027 if (hs->post_content_len_left == 0) {
2028 /* all data received, send response or close connection */
2029 http_send_data(pcb, hs);
2030 }
2031 return ERR_OK;
2032 } else
2033 #endif /* LWIP_HTTPD_SUPPORT_POST */
2034 {
2035 if (hs->handle == NULL) {
2036 parsed = http_parse_request(&p, hs, pcb);
2037 LWIP_ASSERT("http_parse_request: unexpected return value", parsed == ERR_OK
2038 || parsed == ERR_INPROGRESS ||parsed == ERR_ARG || parsed == ERR_USE);
2039 } else {
2040 LWIP_DEBUGF(HTTPD_DEBUG, ("http_recv: already sending data\n"));
2041 }
2042 #if LWIP_HTTPD_SUPPORT_REQUESTLIST
2043 if (parsed != ERR_INPROGRESS) {
2044 /* request fully parsed or error */
2045 if (hs->req != NULL) {
2046 pbuf_free(hs->req);
2047 hs->req = NULL;
2048 }
2049 }
2050 #else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
2051 if (p != NULL) {
2052 /* pbuf not passed to application, free it now */
2053 pbuf_free(p);
2054 }
2055 #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
2056 if (parsed == ERR_OK) {
2057 #if LWIP_HTTPD_SUPPORT_POST
2058 if (hs->post_content_len_left == 0)
2059 #endif /* LWIP_HTTPD_SUPPORT_POST */
2060 {
2061 LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_recv: data %p len %"S32_F"\n", hs->file, hs->left));
2062 http_send_data(pcb, hs);
2063 }
2064 } else if (parsed == ERR_ARG) {
2065 /* @todo: close on ERR_USE? */
2066 http_close_conn(pcb, hs);
2067 }
2068 }
2069 return ERR_OK;
2070 }
2071
2072 #include "ipc_example.h"
2073
2077 static err_t
2078 http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
2079 {
2080 struct http_state *hs;
2081 struct tcp_pcb_listen *lpcb = (struct tcp_pcb_listen*)arg;
2082 extern void EVENT_lwip_http_access(uint32_t);
2083
2084 LWIP_UNUSED_ARG(err);
2085 LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept %p / %p\n", (void*)pcb, arg));
2086
2087 EVENT_lwip_http_access(pcb->remote_ip.addr);
2088
2089 /* Decrease the listen backlog counter */
2090 tcp_accepted(lpcb);
2091 /* Set priority */
2092 tcp_setprio(pcb, HTTPD_TCP_PRIO);
2093
2094 /* Allocate memory for the structure that holds the state of the
2095 connection - initialized by that function. */
2096 hs = http_state_alloc();
2097 if (hs == NULL) {
2098 LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept: Out of memory, RST\n"));
2099 return ERR_MEM;
2100 }
2101
2102 /* Tell TCP that this is the structure we wish to be passed for our
2103 callbacks. */
2104 tcp_arg(pcb, hs);
2105
2106 /* Set up the various callback functions */
2107 tcp_recv(pcb, http_recv);
2108 tcp_err(pcb, http_err);
2109 tcp_poll(pcb, http_poll, HTTPD_POLL_INTERVAL);
2110 tcp_sent(pcb, http_sent);
2111
2112 return ERR_OK;
2113 }
2114
2118 static void
2119 httpd_init_addr(ip_addr_t *local_addr)
2120 {
2121 struct tcp_pcb *pcb;
2122 err_t err;
2123
2124 pcb = tcp_new();
2125 LWIP_ASSERT("httpd_init: tcp_new failed", pcb != NULL);
2126 tcp_setprio(pcb, HTTPD_TCP_PRIO);
2127 /* set SOF_REUSEADDR here to explicitly bind httpd to multiple interfaces */
2128 err = tcp_bind(pcb, local_addr, HTTPD_SERVER_PORT);
2129 LWIP_ASSERT("httpd_init: tcp_bind failed", err == ERR_OK);
2130 pcb = tcp_listen(pcb);
2131 LWIP_ASSERT("httpd_init: tcp_listen failed", pcb != NULL);
2132 /* initialize callback arg and accept callback */
2133 tcp_arg(pcb, pcb);
2134 tcp_accept(pcb, http_accept);
2135 }
2136
2140 void
2141 httpd_init(void)
2142 {
2143 #if HTTPD_USE_MEM_POOL
2144 LWIP_ASSERT("memp_sizes[MEMP_HTTPD_STATE] >= sizeof(http_state)",
2145 memp_sizes[MEMP_HTTPD_STATE] >= sizeof(http_state));
2146 #endif
2147 LWIP_DEBUGF(HTTPD_DEBUG, ("httpd_init\n"));
2148
2149 httpd_init_addr(IP_ADDR_ANY);
2150 }
2151
2152 #if LWIP_HTTPD_SSI
2153
2160 void
2161 http_set_ssi_handler(tSSIHandler ssi_handler, const char **tags, int num_tags)
2162 {
2163 LWIP_DEBUGF(HTTPD_DEBUG, ("http_set_ssi_handler\n"));
2164
2165 LWIP_ASSERT("no ssi_handler given", ssi_handler != NULL);
2166 LWIP_ASSERT("no tags given", tags != NULL);
2167 LWIP_ASSERT("invalid number of tags", num_tags > 0);
2168
2169 g_pfnSSIHandler = ssi_handler;
2170 g_ppcTags = tags;
2171 g_iNumTags = num_tags;
2172 }
2173 #endif /* LWIP_HTTPD_SSI */
2174
2175 #if LWIP_HTTPD_CGI
2176
2182 void
2183 http_set_cgi_handlers(const tCGI *cgis, int num_handlers)
2184 {
2185 LWIP_ASSERT("no cgis given", cgis != NULL);
2186 LWIP_ASSERT("invalid number of handlers", num_handlers > 0);
2187
2188 g_pCGIs = cgis;
2189 g_iNumCGIs = num_handlers;
2190 }
2191 #endif /* LWIP_HTTPD_CGI */
2192
2193 #ifdef __IAR_SYSTEMS_ICC__
2194 WEAK_SYMBOL
2195 #else
2196 WEAK_SYMBOL void EVENT_lwip_http_access(uint32_t addr);
2197 #endif
2198
2206 void EVENT_lwip_http_access(uint32_t addr)
2207 {
2208 /* Push the remote IP address to other core */
2209 ipcex_msgPush(IPCEX_ID_LWIP, addr);
2210 }
2211 #endif /* LWIP_TCP */