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