Coverage Report

Created: 2026-01-13 06:53

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