httpd improvements: added persistent connections, improved asynchronous read mode, compile-time deflate compression, new CGI mode, SSI handler can be called with tag string (instead of tag index)

This commit is contained in:
goldsimon 2016-04-26 13:00:27 +02:00
parent 7d77a52ea5
commit 025d5591eb
8 changed files with 923 additions and 288 deletions

View File

@ -36,6 +36,7 @@
#include "fsdata.h" #include "fsdata.h"
#include <string.h> #include <string.h>
#if HTTPD_USE_CUSTOM_FSDATA #if HTTPD_USE_CUSTOM_FSDATA
#include "fsdata_custom.c" #include "fsdata_custom.c"
#else /* HTTPD_USE_CUSTOM_FSDATA */ #else /* HTTPD_USE_CUSTOM_FSDATA */
@ -50,6 +51,9 @@ void fs_close_custom(struct fs_file *file);
#if LWIP_HTTPD_FS_ASYNC_READ #if LWIP_HTTPD_FS_ASYNC_READ
u8_t fs_canread_custom(struct fs_file *file); u8_t fs_canread_custom(struct fs_file *file);
u8_t fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg); u8_t fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg);
int fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg);
#else /* LWIP_HTTPD_FS_ASYNC_READ */
int fs_read_custom(struct fs_file *file, char *buffer, int count);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */ #endif /* LWIP_HTTPD_FS_ASYNC_READ */
#endif /* LWIP_HTTPD_CUSTOM_FILES */ #endif /* LWIP_HTTPD_CUSTOM_FILES */
@ -77,7 +81,7 @@ fs_open(struct fs_file *file, const char *name)
file->len = f->len; file->len = f->len;
file->index = f->len; file->index = f->len;
file->pextension = NULL; file->pextension = NULL;
file->http_header_included = f->http_header_included; file->flags = f->flags;
#if HTTPD_PRECALCULATED_CHECKSUM #if HTTPD_PRECALCULATED_CHECKSUM
file->chksum_count = f->chksum_count; file->chksum_count = f->chksum_count;
file->chksum = f->chksum; file->chksum = f->chksum;
@ -117,22 +121,22 @@ fs_read(struct fs_file *file, char *buffer, int count)
#endif /* LWIP_HTTPD_FS_ASYNC_READ */ #endif /* LWIP_HTTPD_FS_ASYNC_READ */
{ {
int read; int read;
if(file->index == file->len) { if(file->index == file->len) {
return FS_READ_EOF; return FS_READ_EOF;
} }
#if LWIP_HTTPD_FS_ASYNC_READ #if LWIP_HTTPD_FS_ASYNC_READ
#if LWIP_HTTPD_CUSTOM_FILES
if (!fs_canread_custom(file)) {
if (fs_wait_read_custom(file, callback_fn, callback_arg)) {
return FS_READ_DELAYED;
}
}
#else /* LWIP_HTTPD_CUSTOM_FILES */
LWIP_UNUSED_ARG(callback_fn); LWIP_UNUSED_ARG(callback_fn);
LWIP_UNUSED_ARG(callback_arg); LWIP_UNUSED_ARG(callback_arg);
#endif /* LWIP_HTTPD_CUSTOM_FILES */
#endif /* LWIP_HTTPD_FS_ASYNC_READ */ #endif /* LWIP_HTTPD_FS_ASYNC_READ */
#if LWIP_HTTPD_CUSTOM_FILES
if (file->is_custom_file) {
#if LWIP_HTTPD_FS_ASYNC_READ
return fs_read_async_custom(file, buffer, count, callback_fn, callback_arg);
#else /* LWIP_HTTPD_FS_ASYNC_READ */
return fs_read_custom(file, buffer, count);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
}
#endif /* LWIP_HTTPD_CUSTOM_FILES */
read = file->len - file->index; read = file->len - file->index;
if(read > count) { if(read > count) {

View File

@ -40,7 +40,7 @@ struct fsdata_file {
const unsigned char *name; const unsigned char *name;
const unsigned char *data; const unsigned char *data;
int len; int len;
u8_t http_header_included; u8_t flags;
#if HTTPD_PRECALCULATED_CHECKSUM #if HTTPD_PRECALCULATED_CHECKSUM
u16_t chksum_count; u16_t chksum_count;
const struct fsdata_chksum *chksum; const struct fsdata_chksum *chksum;

File diff suppressed because it is too large Load Diff

View File

@ -27,8 +27,12 @@ static const char * const g_psHTTPHeaderStrings[] =
"Content-Length: ", "Content-Length: ",
"Connection: Close\r\n", "Connection: Close\r\n",
"Connection: keep-alive\r\n", "Connection: keep-alive\r\n",
"Connection: keep-alive\r\nContent-Length: ",
"Server: "HTTPD_SERVER_AGENT"\r\n", "Server: "HTTPD_SERVER_AGENT"\r\n",
"\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n" "\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
,"Connection: keep-alive\r\nContent-Length: 77\r\n\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
#endif
}; };
/* Indexes into the g_psHTTPHeaderStrings array */ /* Indexes into the g_psHTTPHeaderStrings array */
@ -40,11 +44,15 @@ static const char * const g_psHTTPHeaderStrings[] =
#define HTTP_HDR_NOT_FOUND_11 5 /* 404 File not found */ #define HTTP_HDR_NOT_FOUND_11 5 /* 404 File not found */
#define HTTP_HDR_BAD_REQUEST_11 6 /* 400 Bad request */ #define HTTP_HDR_BAD_REQUEST_11 6 /* 400 Bad request */
#define HTTP_HDR_NOT_IMPL_11 7 /* 501 Not Implemented */ #define HTTP_HDR_NOT_IMPL_11 7 /* 501 Not Implemented */
#define HTTP_HDR_CONTENT_LENGTH 8 /* Content-Length: (HTTP 1.1)*/ #define HTTP_HDR_CONTENT_LENGTH 8 /* Content-Length: (HTTP 1.0)*/
#define HTTP_HDR_CONN_CLOSE 9 /* Connection: Close (HTTP 1.1) */ #define HTTP_HDR_CONN_CLOSE 9 /* Connection: Close (HTTP 1.1) */
#define HTTP_HDR_CONN_KEEPALIVE 10 /* Connection: keep-alive (HTTP 1.1) */ #define HTTP_HDR_CONN_KEEPALIVE 10 /* Connection: keep-alive (HTTP 1.1) */
#define HTTP_HDR_SERVER 11 /* Server: HTTPD_SERVER_AGENT */ #define HTTP_HDR_KEEPALIVE_LEN 11 /* Connection: keep-alive + Content-Length: (HTTP 1.1)*/
#define DEFAULT_404_HTML 12 /* default 404 body */ #define HTTP_HDR_SERVER 12 /* Server: HTTPD_SERVER_AGENT */
#define DEFAULT_404_HTML 13 /* default 404 body */
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
#define DEFAULT_404_HTML_PERSISTENT 14 /* default 404 body, but including Connection: keep-alive */
#endif
#define HTTP_HDR_HTML "Content-type: text/html\r\n\r\n" #define HTTP_HDR_HTML "Content-type: text/html\r\n\r\n"
@ -61,6 +69,7 @@ static const char * const g_psHTTPHeaderStrings[] =
#define HTTP_HDR_SWF "Content-type: application/x-shockwave-flash\r\n\r\n" #define HTTP_HDR_SWF "Content-type: application/x-shockwave-flash\r\n\r\n"
#define HTTP_HDR_XML "Content-type: text/xml\r\n\r\n" #define HTTP_HDR_XML "Content-type: text/xml\r\n\r\n"
#define HTTP_HDR_PDF "Content-type: application/pdf\r\n\r\n" #define HTTP_HDR_PDF "Content-type: application/pdf\r\n\r\n"
#define HTTP_HDR_JSON "Content-type: application/json\r\n\r\n"
#define HTTP_HDR_DEFAULT_TYPE "Content-type: text/plain\r\n\r\n" #define HTTP_HDR_DEFAULT_TYPE "Content-type: text/plain\r\n\r\n"
@ -87,7 +96,8 @@ static const tHTTPHeader g_psHTTPHeaders[] =
{ "swf", HTTP_HDR_SWF}, { "swf", HTTP_HDR_SWF},
{ "xml", HTTP_HDR_XML}, { "xml", HTTP_HDR_XML},
{ "xsl", HTTP_HDR_XML}, { "xsl", HTTP_HDR_XML},
{ "pdf", HTTP_HDR_PDF} { "pdf", HTTP_HDR_PDF},
{ "json", HTTP_HDR_JSON}
}; };
#define NUM_HTTP_HEADERS (sizeof(g_psHTTPHeaders) / sizeof(tHTTPHeader)) #define NUM_HTTP_HEADERS (sizeof(g_psHTTPHeaders) / sizeof(tHTTPHeader))

View File

@ -21,6 +21,49 @@
#endif #endif
#include <dos.h> #include <dos.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <sys/stat.h>
/** Makefsdata can generate *all* files deflate-compressed (where file size shrinks).
* Since nearly all browsers support this, this is a good way to reduce ROM size.
* To compress the files, "miniz.c" must be downloaded seperately.
*/
#ifndef MAKEFS_SUPPORT_DEFLATE
#define MAKEFS_SUPPORT_DEFLATE 0
#endif
#define COPY_BUFSIZE (1024*1024) /* 1 MByte */
#if MAKEFS_SUPPORT_DEFLATE
#include "../miniz.c"
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint;
#define my_max(a,b) (((a) > (b)) ? (a) : (b))
#define my_min(a,b) (((a) < (b)) ? (a) : (b))
/* COMP_OUT_BUF_SIZE is the size of the output buffer used during compression.
COMP_OUT_BUF_SIZE must be >= 1 and <= OUT_BUF_SIZE */
#define COMP_OUT_BUF_SIZE COPY_BUFSIZE
/* OUT_BUF_SIZE is the size of the output buffer used during decompression.
OUT_BUF_SIZE must be a power of 2 >= TINFL_LZ_DICT_SIZE (because the low-level decompressor not only writes, but reads from the output buffer as it decompresses) */
#define OUT_BUF_SIZE COPY_BUFSIZE
static uint8 s_outbuf[OUT_BUF_SIZE];
static uint8 s_checkbuf[OUT_BUF_SIZE];
/* tdefl_compressor contains all the state needed by the low-level compressor so it's a pretty big struct (~300k).
This example makes it a global vs. putting it on the stack, of course in real-world usage you'll probably malloc() or new it. */
tdefl_compressor g_deflator;
tinfl_decompressor g_inflator;
int deflate_level = 10; /* default compression level, can be changed via command line */
#define USAGE_ARG_DEFLATE " [-defl]"
#else /* MAKEFS_SUPPORT_DEFLATE */
#define USAGE_ARG_DEFLATE ""
#endif /* MAKEFS_SUPPORT_DEFLATE */
/* Compatibility defines Win32 vs. DOS */ /* Compatibility defines Win32 vs. DOS */
#ifdef WIN32 #ifdef WIN32
@ -66,6 +109,7 @@
#define LWIP_HTTPD_DYNAMIC_HEADERS 1 #define LWIP_HTTPD_DYNAMIC_HEADERS 1
#define LWIP_HTTPD_SSI 1 #define LWIP_HTTPD_SSI 1
#include "../httpd_structs.h" #include "../httpd_structs.h"
#include "lwip/apps/fs.h"
#include "../core/inet_chksum.c" #include "../core/inet_chksum.c"
#include "../core/def.c" #include "../core/def.c"
@ -85,8 +129,6 @@ static int payload_alingment_dummy_counter = 0;
#define MAX_PATH_LEN 256 #define MAX_PATH_LEN 256
#define COPY_BUFSIZE 10240
struct file_entry struct file_entry
{ {
struct file_entry* next; struct file_entry* next;
@ -95,14 +137,13 @@ struct file_entry
int process_sub(FILE *data_file, FILE *struct_file); int process_sub(FILE *data_file, FILE *struct_file);
int process_file(FILE *data_file, FILE *struct_file, const char *filename); int process_file(FILE *data_file, FILE *struct_file, const char *filename);
int file_write_http_header(FILE *data_file, const char *filename, int file_size, int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len,
u16_t *http_hdr_len, u16_t *http_hdr_chksum); u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed);
int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i); int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i);
int s_put_ascii(char *buf, const char *ascii_string, int len, int *i); int s_put_ascii(char *buf, const char *ascii_string, int len, int *i);
void concat_files(const char *file1, const char *file2, const char *targetfile); void concat_files(const char *file1, const char *file2, const char *targetfile);
int check_path(char* path, size_t size); int check_path(char* path, size_t size);
static unsigned char file_buffer_raw[COPY_BUFSIZE];
/* 5 bytes per char + 3 bytes per line */ /* 5 bytes per char + 3 bytes per line */
static char file_buffer_c[COPY_BUFSIZE * 5 + ((COPY_BUFSIZE / HEX_BYTES_PER_LINE) * 3)]; static char file_buffer_c[COPY_BUFSIZE * 5 + ((COPY_BUFSIZE / HEX_BYTES_PER_LINE) * 3)];
@ -115,13 +156,19 @@ unsigned char includeHttpHeader = 1;
unsigned char useHttp11 = 0; unsigned char useHttp11 = 0;
unsigned char supportSsi = 1; unsigned char supportSsi = 1;
unsigned char precalcChksum = 0; unsigned char precalcChksum = 0;
unsigned char includeLastModified = 0;
#if MAKEFS_SUPPORT_DEFLATE
unsigned char deflateNonSsiFiles = 0;
size_t deflatedBytesReduced = 0;
size_t overallDataBytes = 0;
#endif
struct file_entry* first_file = NULL; struct file_entry* first_file = NULL;
struct file_entry* last_file = NULL; struct file_entry* last_file = NULL;
static void print_usage(void) static void print_usage(void)
{ {
printf(" Usage: htmlgen [targetdir] [-s] [-i] [-f:<filename>]" NEWLINE NEWLINE); printf(" Usage: htmlgen [targetdir] [-s] [-i] [-f:<filename>] [-m]" USAGE_ARG_DEFLATE NEWLINE NEWLINE);
printf(" targetdir: relative or absolute path to files to convert" NEWLINE); printf(" targetdir: relative or absolute path to files to convert" NEWLINE);
printf(" switch -s: toggle processing of subdirectories (default is on)" NEWLINE); printf(" switch -s: toggle processing of subdirectories (default is on)" NEWLINE);
printf(" switch -e: exclude HTTP header from file (header is created at runtime, default is off)" NEWLINE); printf(" switch -e: exclude HTTP header from file (header is created at runtime, default is off)" NEWLINE);
@ -129,6 +176,11 @@ static void print_usage(void)
printf(" switch -nossi: no support for SSI (cannot calculate Content-Length for SSI)" NEWLINE); printf(" switch -nossi: no support for SSI (cannot calculate Content-Length for SSI)" NEWLINE);
printf(" switch -c: precalculate checksums for all pages (default is off)" NEWLINE); printf(" switch -c: precalculate checksums for all pages (default is off)" NEWLINE);
printf(" switch -f: target filename (default is \"fsdata.c\")" NEWLINE); printf(" switch -f: target filename (default is \"fsdata.c\")" NEWLINE);
printf(" switch -m: include \"Last-Modified\" header based on file time" NEWLINE);
#if MAKEFS_SUPPORT_DEFLATE
printf(" switch -defl: deflate-compress all non-SSI files" NEWLINE);
printf(" ATTENTION: browser has to support \"Content-Encoding: deflate\"!" NEWLINE);
#endif
printf(" if targetdir not specified, htmlgen will attempt to" NEWLINE); printf(" if targetdir not specified, htmlgen will attempt to" NEWLINE);
printf(" process files in subdirectory 'fs'" NEWLINE); printf(" process files in subdirectory 'fs'" NEWLINE);
} }
@ -171,6 +223,27 @@ int main(int argc, char *argv[])
strncpy(targetfile, &argv[i][3], sizeof(targetfile) - 1); strncpy(targetfile, &argv[i][3], sizeof(targetfile) - 1);
targetfile[sizeof(targetfile) - 1] = 0; targetfile[sizeof(targetfile) - 1] = 0;
printf("Writing to file \"%s\"\n", targetfile); printf("Writing to file \"%s\"\n", targetfile);
} else if (strstr(argv[i], "-m")) {
includeLastModified = 1;
} else if (strstr(argv[i], "-defl")) {
#if MAKEFS_SUPPORT_DEFLATE
char* colon = strstr(argv[i], ":");
if (colon) {
if (colon[1] != 0) {
int defl_level = atoi(&colon[1]);
if ((defl_level >= 0) && (defl_level <= 10)) {
deflate_level = defl_level;
} else {
printf("ERROR: deflate level must be [0..10]" NEWLINE);
exit(0);
}
}
}
deflateNonSsiFiles = 1;
printf("Deflating all non-SSI files with level %d (but only if size is reduced)" NEWLINE, deflate_level);
#else
printf("WARNING: Deflate support is disabled\n");
#endif
} else if ((strstr(argv[i], "-?")) || (strstr(argv[i], "-h"))) { } else if ((strstr(argv[i], "-?")) || (strstr(argv[i], "-h"))) {
print_usage(); print_usage();
exit(0); exit(0);
@ -230,6 +303,20 @@ int main(int argc, char *argv[])
fprintf(data_file, "#include \"fsdata.h\"" NEWLINE NEWLINE NEWLINE); fprintf(data_file, "#include \"fsdata.h\"" NEWLINE NEWLINE NEWLINE);
fprintf(data_file, "#define file_NULL (struct fsdata_file *) NULL" NEWLINE NEWLINE NEWLINE); fprintf(data_file, "#define file_NULL (struct fsdata_file *) NULL" NEWLINE NEWLINE NEWLINE);
/* define FS_FILE_FLAGS_HEADER_INCLUDED to 1 if not defined (compatibility with older httpd/fs) */
fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_INCLUDED" NEWLINE "#define FS_FILE_FLAGS_HEADER_INCLUDED 1" NEWLINE "#endif" NEWLINE);
/* define FS_FILE_FLAGS_HEADER_PERSISTENT to 0 if not defined (compatibility with older httpd/fs: wasn't supported back then) */
fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_PERSISTENT" NEWLINE "#define FS_FILE_FLAGS_HEADER_PERSISTENT 0" NEWLINE "#endif" NEWLINE);
/* define alignment defines */
#if ALIGN_PAYLOAD
fprintf(data_file, "/* FSDATA_FILE_ALIGNMENT: 0=off, 1=by variable, 2=by include */" NEWLINE "#ifndef FSDATA_FILE_ALIGNMENT" NEWLINE "#define FSDATA_FILE_ALIGNMENT 0" NEWLINE "#endif" NEWLINE);
#endif
fprintf(data_file, "#ifndef FSDATA_ALIGN_PRE" NEWLINE "#define FSDATA_ALIGN_PRE" NEWLINE "#endif" NEWLINE);
fprintf(data_file, "#ifndef FSDATA_ALIGN_POST" NEWLINE "#define FSDATA_ALIGN_POST" NEWLINE "#endif" NEWLINE);
#if ALIGN_PAYLOAD
fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==2" NEWLINE "#include \"fsdata_alignment.h\"" NEWLINE "#endif" NEWLINE);
#endif
sprintf(lastFileVar, "NULL"); sprintf(lastFileVar, "NULL");
@ -257,7 +344,14 @@ int main(int argc, char *argv[])
printf("Warning: failed to delete fshdr.tmp\n"); printf("Warning: failed to delete fshdr.tmp\n");
} }
printf(NEWLINE "Processed %d files - done." NEWLINE NEWLINE, filesProcessed); printf(NEWLINE "Processed %d files - done." NEWLINE, filesProcessed);
#if MAKEFS_SUPPORT_DEFLATE
if (deflateNonSsiFiles) {
printf("(Deflated total byte reduction: %d bytes -> %d bytes (%.02f%%)" NEWLINE,
(int)overallDataBytes, (int)deflatedBytesReduced, (float)((deflatedBytesReduced*100.0)/overallDataBytes));
}
#endif
printf(NEWLINE);
while (first_file != NULL) { while (first_file != NULL) {
struct file_entry* fe = first_file; struct file_entry* fe = first_file;
@ -295,16 +389,18 @@ static void copy_file(const char *filename_in, FILE *fout)
{ {
FILE *fin; FILE *fin;
size_t len; size_t len;
void* buf;
fin = fopen(filename_in, "rb"); fin = fopen(filename_in, "rb");
if (fin == NULL) { if (fin == NULL) {
printf("Failed to open file \"%s\"\n", filename_in); printf("Failed to open file \"%s\"\n", filename_in);
exit(-1); exit(-1);
} }
buf = malloc(COPY_BUFSIZE);
while((len = fread(file_buffer_raw, 1, COPY_BUFSIZE, fin)) > 0) while((len = fread(buf, 1, COPY_BUFSIZE, fin)) > 0)
{ {
fwrite(file_buffer_raw, 1, len, fout); fwrite(buf, 1, len, fout);
} }
free(buf);
fclose(fin); fclose(fin);
} }
@ -347,7 +443,7 @@ int process_sub(FILE *data_file, FILE *struct_file)
strncat(curSubdir, "/", freelen); strncat(curSubdir, "/", freelen);
strncat(curSubdir, curName, freelen - 1); strncat(curSubdir, curName, freelen - 1);
curSubdir[sizeof(curSubdir) - 1] = 0; curSubdir[sizeof(curSubdir) - 1] = 0;
printf(NEWLINE "processing subdirectory %s/..." NEWLINE, curSubdir); printf("processing subdirectory %s/..." NEWLINE, curSubdir);
filesProcessed += process_sub(data_file, struct_file); filesProcessed += process_sub(data_file, struct_file);
CHDIR(".."); CHDIR("..");
curSubdir[sublen] = 0; curSubdir[sublen] = 0;
@ -376,58 +472,134 @@ int process_sub(FILE *data_file, FILE *struct_file)
return filesProcessed; return filesProcessed;
} }
int get_file_size(const char* filename) u8_t* get_file_data(const char* filename, int* file_size, int can_be_compressed, int* is_compressed)
{ {
FILE *inFile; FILE *inFile;
int file_size = -1; size_t fsize = 0;
u8_t* buf;
size_t r;
int rs;
inFile = fopen(filename, "rb"); inFile = fopen(filename, "rb");
if (inFile == NULL) { if (inFile == NULL) {
printf("Failed to open file \"%s\"\n", filename); printf("Failed to open file \"%s\"\n", filename);
exit(-1); exit(-1);
} }
fseek(inFile, 0, SEEK_END); fseek(inFile, 0, SEEK_END);
file_size = ftell(inFile); rs = ftell(inFile);
fclose(inFile); if(rs < 0)
return file_size; {
} printf("ftell failed with %d\n", errno);
exit(-1);
void process_file_data(const char *filename, FILE *data_file)
{
FILE *source_file;
size_t len, written, i, src_off=0;
source_file = fopen(filename, "rb");
if (source_file == NULL) {
printf("Failed to open file \"%s\"\n", filename);
exit(-1);
} }
fsize = (size_t)rs;
do { fseek(inFile, 0, SEEK_SET);
size_t off = 0; buf = (u8_t*)malloc(fsize);
len = fread(file_buffer_raw, 1, COPY_BUFSIZE, source_file); LWIP_ASSERT("buf != NULL", buf != NULL);
if (len > 0) { r = fread(buf, 1, fsize, inFile);
for (i = 0; i < len; i++) { *file_size = fsize;
sprintf(&file_buffer_c[off], "0x%02.2x,", file_buffer_raw[i]); *is_compressed = 0;
off += 5; #if MAKEFS_SUPPORT_DEFLATE
if ((++src_off % HEX_BYTES_PER_LINE) == 0) { overallDataBytes += fsize;
memcpy(&file_buffer_c[off], NEWLINE, NEWLINE_LEN); if (deflateNonSsiFiles) {
off += NEWLINE_LEN; if (can_be_compressed) {
if (fsize < OUT_BUF_SIZE) {
u8_t* ret_buf;
tdefl_status status;
size_t in_bytes = fsize;
size_t out_bytes = OUT_BUF_SIZE;
const void *next_in = buf;
void *next_out = s_outbuf;
/* create tdefl() compatible flags (we have to compose the low-level flags ourselves, or use tdefl_create_comp_flags_from_zip_params() but that means MINIZ_NO_ZLIB_APIS can't be defined). */
mz_uint comp_flags = s_tdefl_num_probes[MZ_MIN(10, deflate_level)] | ((deflate_level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
if (!deflate_level) {
comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
} }
status = tdefl_init(&g_deflator, NULL, NULL, comp_flags);
if (status != TDEFL_STATUS_OKAY) {
printf("tdefl_init() failed!\n");
exit(-1);
}
memset(s_outbuf, 0, sizeof(s_outbuf));
status = tdefl_compress(&g_deflator, next_in, &in_bytes, next_out, &out_bytes, TDEFL_FINISH);
if (status != TDEFL_STATUS_DONE) {
printf("deflate failed: %d\n", status);
exit(-1);
}
LWIP_ASSERT("out_bytes <= COPY_BUFSIZE", out_bytes <= OUT_BUF_SIZE);
if (out_bytes < fsize) {
ret_buf = (u8_t*)malloc(out_bytes);
LWIP_ASSERT("ret_buf != NULL", ret_buf != NULL);
memcpy(ret_buf, s_outbuf, out_bytes);
{
/* sanity-check compression be inflating and comparing to the original */
tinfl_status dec_status;
tinfl_decompressor inflator;
size_t dec_in_bytes = out_bytes;
size_t dec_out_bytes = OUT_BUF_SIZE;
next_out = s_checkbuf;
tinfl_init(&inflator);
memset(s_checkbuf, 0, sizeof(s_checkbuf));
dec_status = tinfl_decompress(&inflator, (const mz_uint8 *)ret_buf, &dec_in_bytes, s_checkbuf, (mz_uint8 *)next_out, &dec_out_bytes, 0);
LWIP_ASSERT("tinfl_decompress failed", dec_status == TINFL_STATUS_DONE);
LWIP_ASSERT("tinfl_decompress size mismatch", fsize == dec_out_bytes);
LWIP_ASSERT("decompressed memcmp failed", !memcmp(s_checkbuf, buf, fsize));
}
/* free original buffer, use compressed data + size */
free(buf);
buf = ret_buf;
*file_size = out_bytes;
printf(" - deflate: %d bytes -> %d bytes (%.02f%%)" NEWLINE, (int)fsize, (int)out_bytes, (float)((out_bytes*100.0)/fsize));
deflatedBytesReduced += (size_t)(fsize - out_bytes);
*is_compressed = 1;
} else {
printf(" - uncompressed: (would be %d bytes larger using deflate)" NEWLINE, (int)(out_bytes - fsize));
}
} else {
printf(" - uncompressed: (file is larger than deflate bufer)" NEWLINE);
} }
written = fwrite(file_buffer_c, 1, off, data_file); } else {
printf(" - SSI file, cannot be compressed" NEWLINE);
} }
} while(len > 0); }
fclose(source_file); #else
LWIP_UNUSED_ARG(compress);
#endif
fclose(inFile);
return buf;
} }
int write_checksums(FILE *struct_file, const char *filename, const char *varname, void process_file_data(FILE* data_file, u8_t* file_data, size_t file_size)
u16_t hdr_len, u16_t hdr_chksum) {
size_t written, i, src_off=0;
size_t off = 0;
for (i = 0; i < file_size; i++) {
LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - 5);
sprintf(&file_buffer_c[off], "0x%02.2x,", file_data[i]);
off += 5;
if ((++src_off % HEX_BYTES_PER_LINE) == 0) {
LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - NEWLINE_LEN);
memcpy(&file_buffer_c[off], NEWLINE, NEWLINE_LEN);
off += NEWLINE_LEN;
}
if (off + 20 >= sizeof(file_buffer_c)) {
written = fwrite(file_buffer_c, 1, off, data_file);
LWIP_ASSERT("written == off", written == off);
off = 0;
}
}
written = fwrite(file_buffer_c, 1, off, data_file);
LWIP_ASSERT("written == off", written == off);
}
int write_checksums(FILE *struct_file, const char *varname,
u16_t hdr_len, u16_t hdr_chksum, const u8_t* file_data, size_t file_size)
{ {
int chunk_size = TCP_MSS; int chunk_size = TCP_MSS;
int offset; int offset, src_offset;
size_t len; size_t len;
int i = 0; int i = 0;
FILE *f;
#if LWIP_TCP_TIMESTAMPS #if LWIP_TCP_TIMESTAMPS
/* when timestamps are used, usable space is 12 bytes less per segment */ /* when timestamps are used, usable space is 12 bytes less per segment */
chunk_size -= 12; chunk_size -= 12;
@ -436,29 +608,24 @@ int write_checksums(FILE *struct_file, const char *filename, const char *varname
fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE);
fprintf(struct_file, "const struct fsdata_chksum chksums_%s[] = {" NEWLINE, varname); fprintf(struct_file, "const struct fsdata_chksum chksums_%s[] = {" NEWLINE, varname);
memset(file_buffer_raw, 0xab, sizeof(file_buffer_raw));
f = fopen(filename, "rb");
if (f == NULL) {
printf("Failed to open file \"%s\"\n", filename);
exit(-1);
}
if (hdr_len > 0) { if (hdr_len > 0) {
/* add checksum for HTTP header */ /* add checksum for HTTP header */
fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, 0, hdr_chksum, hdr_len); fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, 0, hdr_chksum, hdr_len);
i++; i++;
} }
src_offset = 0;
for (offset = hdr_len; ; offset += len) { for (offset = hdr_len; ; offset += len) {
unsigned short chksum; unsigned short chksum;
len = fread(file_buffer_raw, 1, chunk_size, f); void* data = (void*)&file_data[src_offset];
len = LWIP_MIN(chunk_size, (int)file_size - src_offset);
if (len == 0) { if (len == 0) {
break; break;
} }
chksum = ~inet_chksum(file_buffer_raw, (u16_t)len); chksum = ~inet_chksum(data, (u16_t)len);
/* add checksum for data */ /* add checksum for data */
fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, offset, chksum, len); fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, offset, chksum, len);
i++; i++;
} }
fclose(f);
fprintf(struct_file, "};" NEWLINE); fprintf(struct_file, "};" NEWLINE);
fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE);
return i; return i;
@ -480,7 +647,7 @@ static void fix_filename_for_c(char* qualifiedName, size_t max_len)
{ {
struct file_entry* f; struct file_entry* f;
size_t len = strlen(qualifiedName); size_t len = strlen(qualifiedName);
char *new_name = malloc(len + 2); char *new_name = (char*)malloc(len + 2);
int filename_ok; int filename_ok;
int cnt = 0; int cnt = 0;
size_t i; size_t i;
@ -516,7 +683,7 @@ static void fix_filename_for_c(char* qualifiedName, size_t max_len)
static void register_filename(const char* qualifiedName) static void register_filename(const char* qualifiedName)
{ {
struct file_entry* fe = malloc(sizeof(struct file_entry)); struct file_entry* fe = (struct file_entry*)malloc(sizeof(struct file_entry));
fe->filename_c = strdup(qualifiedName); fe->filename_c = strdup(qualifiedName);
fe->next = NULL; fe->next = NULL;
if (first_file == NULL) { if (first_file == NULL) {
@ -527,6 +694,17 @@ static void register_filename(const char* qualifiedName)
} }
} }
int is_ssi_file(const char* filename)
{
size_t loop;
for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) {
if (strstr(filename, g_pcSSIExtensions[loop])) {
return 1;
}
}
return 0;
}
int process_file(FILE *data_file, FILE *struct_file, const char *filename) int process_file(FILE *data_file, FILE *struct_file, const char *filename)
{ {
char varname[MAX_PATH_LEN]; char varname[MAX_PATH_LEN];
@ -536,6 +714,11 @@ int process_file(FILE *data_file, FILE *struct_file, const char *filename)
u16_t http_hdr_chksum = 0; u16_t http_hdr_chksum = 0;
u16_t http_hdr_len = 0; u16_t http_hdr_len = 0;
int chksum_count = 0; int chksum_count = 0;
u8_t flags = 0;
const char* flags_str;
u8_t has_content_len;
u8_t* file_data;
int is_compressed = 0;
/* create qualified name (TODO: prepend slash or not?) */ /* create qualified name (TODO: prepend slash or not?) */
sprintf(qualifiedName,"%s/%s", curSubdir, filename); sprintf(qualifiedName,"%s/%s", curSubdir, filename);
@ -545,10 +728,12 @@ int process_file(FILE *data_file, FILE *struct_file, const char *filename)
fix_filename_for_c(varname, MAX_PATH_LEN); fix_filename_for_c(varname, MAX_PATH_LEN);
register_filename(varname); register_filename(varname);
#if ALIGN_PAYLOAD #if ALIGN_PAYLOAD
/* to force even alignment of array */ /* to force even alignment of array, type 1 */
fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==1" NEWLINE);
fprintf(data_file, "static const " PAYLOAD_ALIGN_TYPE " dummy_align_%s = %d;" NEWLINE, varname, payload_alingment_dummy_counter++); fprintf(data_file, "static const " PAYLOAD_ALIGN_TYPE " dummy_align_%s = %d;" NEWLINE, varname, payload_alingment_dummy_counter++);
fprintf(data_file, "#endif" NEWLINE);
#endif /* ALIGN_PAYLOAD */ #endif /* ALIGN_PAYLOAD */
fprintf(data_file, "static const unsigned char data_%s[] = {" NEWLINE, varname); fprintf(data_file, "static const unsigned char FSDATA_ALIGN_PRE data_%s[] FSDATA_ALIGN_POST = {" NEWLINE, varname);
/* encode source file name (used by file system, not returned to browser) */ /* encode source file name (used by file system, not returned to browser) */
fprintf(data_file, "/* %s (%d chars) */" NEWLINE, qualifiedName, strlen(qualifiedName)+1); fprintf(data_file, "/* %s (%d chars) */" NEWLINE, qualifiedName, strlen(qualifiedName)+1);
file_put_ascii(data_file, qualifiedName, strlen(qualifiedName)+1, &i); file_put_ascii(data_file, qualifiedName, strlen(qualifiedName)+1, &i);
@ -561,12 +746,17 @@ int process_file(FILE *data_file, FILE *struct_file, const char *filename)
#endif /* ALIGN_PAYLOAD */ #endif /* ALIGN_PAYLOAD */
fprintf(data_file, NEWLINE); fprintf(data_file, NEWLINE);
file_size = get_file_size(filename); has_content_len = !is_ssi_file(filename);
file_data = get_file_data(filename, &file_size, includeHttpHeader && has_content_len, &is_compressed);
if (includeHttpHeader) { if (includeHttpHeader) {
file_write_http_header(data_file, filename, file_size, &http_hdr_len, &http_hdr_chksum); file_write_http_header(data_file, filename, file_size, &http_hdr_len, &http_hdr_chksum, has_content_len, is_compressed);
flags = FS_FILE_FLAGS_HEADER_INCLUDED;
if (has_content_len) {
flags |= FS_FILE_FLAGS_HEADER_PERSISTENT;
}
} }
if (precalcChksum) { if (precalcChksum) {
chksum_count = write_checksums(struct_file, filename, varname, http_hdr_len, http_hdr_chksum); chksum_count = write_checksums(struct_file, varname, http_hdr_len, http_hdr_chksum, file_data, file_size);
} }
/* build declaration of struct fsdata_file in temp file */ /* build declaration of struct fsdata_file in temp file */
@ -575,7 +765,22 @@ int process_file(FILE *data_file, FILE *struct_file, const char *filename)
fprintf(struct_file, "data_%s," NEWLINE, varname); fprintf(struct_file, "data_%s," NEWLINE, varname);
fprintf(struct_file, "data_%s + %d," NEWLINE, varname, i); fprintf(struct_file, "data_%s + %d," NEWLINE, varname, i);
fprintf(struct_file, "sizeof(data_%s) - %d," NEWLINE, varname, i); fprintf(struct_file, "sizeof(data_%s) - %d," NEWLINE, varname, i);
fprintf(struct_file, "%d," NEWLINE, includeHttpHeader); switch(flags)
{
case(FS_FILE_FLAGS_HEADER_INCLUDED):
flags_str = "FS_FILE_FLAGS_HEADER_INCLUDED";
break;
case(FS_FILE_FLAGS_HEADER_PERSISTENT):
flags_str = "FS_FILE_FLAGS_HEADER_PERSISTENT";
break;
case(FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT):
flags_str = "FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT";
break;
default:
flags_str = "0";
break;
}
fprintf(struct_file, "%s," NEWLINE, flags_str);
if (precalcChksum) { if (precalcChksum) {
fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE);
fprintf(struct_file, "%d, chksums_%s," NEWLINE, chksum_count, varname); fprintf(struct_file, "%d, chksums_%s," NEWLINE, chksum_count, varname);
@ -587,14 +792,14 @@ int process_file(FILE *data_file, FILE *struct_file, const char *filename)
/* write actual file contents */ /* write actual file contents */
i = 0; i = 0;
fprintf(data_file, NEWLINE "/* raw file data (%d bytes) */" NEWLINE, file_size); fprintf(data_file, NEWLINE "/* raw file data (%d bytes) */" NEWLINE, file_size);
process_file_data(filename, data_file); process_file_data(data_file, file_data, file_size);
fprintf(data_file, "};" NEWLINE NEWLINE); fprintf(data_file, "};" NEWLINE NEWLINE);
free(file_data);
return 0; return 0;
} }
int file_write_http_header(FILE *data_file, const char *filename, int file_size, int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len,
u16_t *http_hdr_len, u16_t *http_hdr_chksum) u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed)
{ {
int i = 0; int i = 0;
int response_type = HTTP_HDR_OK; int response_type = HTTP_HDR_OK;
@ -606,17 +811,7 @@ int file_write_http_header(FILE *data_file, const char *filename, int file_size,
u16_t acc; u16_t acc;
const char *file_ext; const char *file_ext;
int j; int j;
u8_t keepalive = useHttp11; u8_t provide_last_modified = includeLastModified;
if (keepalive) {
size_t loop;
for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) {
if (strstr(filename, g_pcSSIExtensions[loop])) {
/* no keepalive connection for SSI files */
keepalive = 0;
}
}
}
memset(hdr_buf, 0, sizeof(hdr_buf)); memset(hdr_buf, 0, sizeof(hdr_buf));
@ -685,38 +880,78 @@ int file_write_http_header(FILE *data_file, const char *filename, int file_size,
} }
} }
if (useHttp11) { /* Content-Length is used for persistent connections in HTTP/1.1 but also for
download progress in older versions
@todo: just use a big-enough buffer and let the HTTPD send spaces? */
if (provide_content_len) {
char intbuf[MAX_PATH_LEN]; char intbuf[MAX_PATH_LEN];
int content_len = file_size; int content_len = file_size;
memset(intbuf, 0, sizeof(intbuf)); memset(intbuf, 0, sizeof(intbuf));
cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH];
if (!keepalive) { cur_len = strlen(cur_string);
content_len *= 2; fprintf(data_file, NEWLINE "/* \"%s%d\r\n\" (%d+ bytes) */" NEWLINE, cur_string, content_len, cur_len+2);
written += file_put_ascii(data_file, cur_string, cur_len, &i);
if (precalcChksum) {
memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
hdr_len += cur_len;
} }
_itoa(content_len, intbuf, 10);
strcat(intbuf, "\r\n");
cur_len = strlen(intbuf);
written += file_put_ascii(data_file, intbuf, cur_len, &i);
i = 0;
if (precalcChksum) {
memcpy(&hdr_buf[hdr_len], intbuf, cur_len);
hdr_len += cur_len;
}
}
if (provide_last_modified) {
char modbuf[256];
struct stat stat_data;
struct tm* t;
memset(modbuf, 0, sizeof(modbuf));
memset(&stat_data, 0, sizeof(stat_data));
cur_string = modbuf;
strcpy(modbuf, "Last-Modified: ");
if(stat(filename, &stat_data) != 0)
{ {
cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH]; printf("stat(%s) failed with error %d\n", filename, errno);
cur_len = strlen(cur_string); exit(-1);
fprintf(data_file, NEWLINE "/* \"%s%d\r\n\" (%d+ bytes) */" NEWLINE, cur_string, content_len, cur_len+2); }
written += file_put_ascii(data_file, cur_string, cur_len, &i); t = gmtime(&stat_data.st_mtime);
if (precalcChksum) { if(t == NULL)
memcpy(&hdr_buf[hdr_len], cur_string, cur_len); {
hdr_len += cur_len; printf("gmtime() failed with error %d\n", errno);
} exit(-1);
}
_itoa(content_len, intbuf, 10); strftime(&modbuf[15], sizeof(modbuf)-15, "%a, %d %b %Y %H:%M:%S GMT", t);
strcat(intbuf, "\r\n"); cur_len = strlen(cur_string);
cur_len = strlen(intbuf); fprintf(data_file, NEWLINE "/* \"%s\"\r\n\" (%d+ bytes) */" NEWLINE, cur_string, cur_len+2);
written += file_put_ascii(data_file, intbuf, cur_len, &i); written += file_put_ascii(data_file, cur_string, cur_len, &i);
i = 0; if (precalcChksum) {
if (precalcChksum) { memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
memcpy(&hdr_buf[hdr_len], intbuf, cur_len); hdr_len += cur_len;
hdr_len += cur_len;
}
} }
if (keepalive) { modbuf[0] = 0;
strcat(modbuf, "\r\n");
cur_len = strlen(modbuf);
written += file_put_ascii(data_file, modbuf, cur_len, &i);
i = 0;
if (precalcChksum) {
memcpy(&hdr_buf[hdr_len], modbuf, cur_len);
hdr_len += cur_len;
}
}
/* HTTP/1.1 implements persistent connections */
if (useHttp11) {
if (provide_content_len) {
cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_KEEPALIVE]; cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_KEEPALIVE];
} else { } else {
/* no Content-Length available, so a persistent connection is no possible
because the client does not know the data length */
cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE]; cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE];
} }
cur_len = strlen(cur_string); cur_len = strlen(cur_string);
@ -729,11 +964,29 @@ int file_write_http_header(FILE *data_file, const char *filename, int file_size,
} }
} }
#if MAKEFS_SUPPORT_DEFLATE
if (is_compressed) {
/* tell the client about the deflate encoding */
LWIP_ASSERT("error", deflateNonSsiFiles);
cur_string = "Content-Encoding: deflate\r\n";
cur_len = strlen(cur_string);
fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len);
written += file_put_ascii(data_file, cur_string, cur_len, &i);
i = 0;
}
#else
LWIP_UNUSED_ARG(is_compressed);
#endif
/* write content-type, ATTENTION: this includes the double-CRLF! */
cur_string = file_type; cur_string = file_type;
cur_len = strlen(cur_string); cur_len = strlen(cur_string);
fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len);
written += file_put_ascii(data_file, cur_string, cur_len, &i); written += file_put_ascii(data_file, cur_string, cur_len, &i);
i = 0; i = 0;
/* ATTENTION: headers are done now (double-CRLF has been written!) */
if (precalcChksum) { if (precalcChksum) {
memcpy(&hdr_buf[hdr_len], cur_string, cur_len); memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
hdr_len += cur_len; hdr_len += cur_len;

View File

@ -50,6 +50,9 @@ struct fsdata_chksum {
}; };
#endif /* HTTPD_PRECALCULATED_CHECKSUM */ #endif /* HTTPD_PRECALCULATED_CHECKSUM */
#define FS_FILE_FLAGS_HEADER_INCLUDED 0x01
#define FS_FILE_FLAGS_HEADER_PERSISTENT 0x02
struct fs_file { struct fs_file {
const char *data; const char *data;
int len; int len;
@ -59,7 +62,7 @@ struct fs_file {
const struct fsdata_chksum *chksum; const struct fsdata_chksum *chksum;
u16_t chksum_count; u16_t chksum_count;
#endif /* HTTPD_PRECALCULATED_CHECKSUM */ #endif /* HTTPD_PRECALCULATED_CHECKSUM */
u8_t http_header_included; u8_t flags;
#if LWIP_HTTPD_CUSTOM_FILES #if LWIP_HTTPD_CUSTOM_FILES
u8_t is_custom_file; u8_t is_custom_file;
#endif /* LWIP_HTTPD_CUSTOM_FILES */ #endif /* LWIP_HTTPD_CUSTOM_FILES */

View File

@ -92,6 +92,27 @@ void http_set_cgi_handlers(const tCGI *pCGIs, int iNumHandlers);
#endif /* LWIP_HTTPD_CGI */ #endif /* LWIP_HTTPD_CGI */
#if LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI
/* The maximum number of parameters that the CGI handler can be sent. */
#ifndef LWIP_HTTPD_MAX_CGI_PARAMETERS
#define LWIP_HTTPD_MAX_CGI_PARAMETERS 16
#endif
#if LWIP_HTTPD_CGI_SSI
/** Define this generic CGI handler in your application.
* It is called once for every URI with parameters.
* The parameters can be stored to
*/
extern void httpd_cgi_handler(const char* uri, int iNumParams, char **pcParam, char **pcValue
#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE
, void *connection_state
#endif /* LWIP_HTTPD_FILE_STATE */
);
#endif /* LWIP_HTTPD_CGI_SSI */
#endif /* LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI */
#if LWIP_HTTPD_SSI #if LWIP_HTTPD_SSI
/* /*
@ -123,7 +144,13 @@ void http_set_cgi_handlers(const tCGI *pCGIs, int iNumHandlers);
* output JavaScript code must do so in an encapsulated way, sending the whole * output JavaScript code must do so in an encapsulated way, sending the whole
* HTML <script>...</script> section as a single include. * HTML <script>...</script> section as a single include.
*/ */
typedef u16_t (*tSSIHandler)(int iIndex, char *pcInsert, int iInsertLen typedef u16_t (*tSSIHandler)(
#if LWIP_HTTPD_SSI_RAW
const char* ssi_tag_name,
#else /* LWIP_HTTPD_SSI_RAW */
int iIndex,
#endif /* LWIP_HTTPD_SSI_RAW */
char *pcInsert, int iInsertLen
#if LWIP_HTTPD_SSI_MULTIPART #if LWIP_HTTPD_SSI_MULTIPART
, u16_t current_tag_part, u16_t *next_tag_part , u16_t current_tag_part, u16_t *next_tag_part
#endif /* LWIP_HTTPD_SSI_MULTIPART */ #endif /* LWIP_HTTPD_SSI_MULTIPART */
@ -132,9 +159,18 @@ typedef u16_t (*tSSIHandler)(int iIndex, char *pcInsert, int iInsertLen
#endif /* LWIP_HTTPD_FILE_STATE */ #endif /* LWIP_HTTPD_FILE_STATE */
); );
/** Set the SSI handler function
* (if LWIP_HTTPD_SSI_RAW==1, only the first argument is used)
*/
void http_set_ssi_handler(tSSIHandler pfnSSIHandler, void http_set_ssi_handler(tSSIHandler pfnSSIHandler,
const char **ppcTags, int iNumTags); const char **ppcTags, int iNumTags);
/** For LWIP_HTTPD_SSI_RAW==1, return this to indicat the tag is unknown.
* In this case, the webserver writes a warning into the page.
* You can also just return 0 to write nothing for unknown tags.
*/
#define HTTPD_SSI_TAG_UNKNOWN 0xFFFF
#endif /* LWIP_HTTPD_SSI */ #endif /* LWIP_HTTPD_SSI */
#if LWIP_HTTPD_SUPPORT_POST #if LWIP_HTTPD_SUPPORT_POST
@ -192,8 +228,9 @@ void httpd_post_data_recved(void *connection, u16_t recved_len);
void httpd_init(void); void httpd_init(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* LWIP_HDR_APPS_HTTPD_H */ #endif /* LWIP_HTTPD_H */

View File

@ -38,11 +38,16 @@
#include "lwip/opt.h" #include "lwip/opt.h"
/** Set this to 1 to support CGI */ /** Set this to 1 to support CGI (old style) */
#ifndef LWIP_HTTPD_CGI #ifndef LWIP_HTTPD_CGI
#define LWIP_HTTPD_CGI 0 #define LWIP_HTTPD_CGI 0
#endif #endif
/** Set this to 1 to support CGI (new style) */
#ifndef LWIP_HTTPD_CGI_SSI
#define LWIP_HTTPD_CGI_SSI 0
#endif
/** Set this to 1 to support SSI (Server-Side-Includes) */ /** Set this to 1 to support SSI (Server-Side-Includes) */
#ifndef LWIP_HTTPD_SSI #ifndef LWIP_HTTPD_SSI
#define LWIP_HTTPD_SSI 0 #define LWIP_HTTPD_SSI 0
@ -143,6 +148,28 @@
#define LWIP_HTTPD_STRNSTR_PRIVATE 1 #define LWIP_HTTPD_STRNSTR_PRIVATE 1
#endif #endif
/** Set this to 1 on platforms where stricmp is not available */
#ifndef LWIP_HTTPD_STRICMP_PRIVATE
#define LWIP_HTTPD_STRICMP_PRIVATE 0
#endif
/** Set this to 1 on platforms where stricmp is not available */
#ifndef LWIP_HTTPD_ITOA_PRIVATE
#define LWIP_HTTPD_ITOA_PRIVATE 1
#endif
/** Define this to a smaller function if you have itoa() at hand... */
#ifndef LWIP_HTTPD_ITOA
#ifndef LWIP_HTTPD_ITOA_PRIVATE
#define LWIP_HTTPD_ITOA_PRIVATE 1
#endif
#if LWIP_HTTPD_ITOA_PRIVATE
#define LWIP_HTTPD_ITOA(buffer, bufsize, number) httpd_itoa(number, buffer)
#else
#define LWIP_HTTPD_ITOA(buffer, bufsize, number) snprintf(buffer, bufsize, "%d", number)
#endif
#endif
/** Set this to one to show error pages when parsing a request fails instead /** Set this to one to show error pages when parsing a request fails instead
of simply closing the connection. */ of simply closing the connection. */
#ifndef LWIP_HTTPD_SUPPORT_EXTSTATUS #ifndef LWIP_HTTPD_SUPPORT_EXTSTATUS
@ -188,6 +215,15 @@
#endif #endif
#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */
/** This is the size of a static buffer used when URIs end with '/'.
* In this buffer, the directory requested is concatenated with all the
* configured default file names.
* Set to 0 to disable checking default filenames on non-root directories.
*/
#ifndef LWIP_HTTPD_MAX_REQUEST_URI_LEN
#define LWIP_HTTPD_MAX_REQUEST_URI_LEN 63
#endif
/** Maximum length of the filename to send as response to a POST request, /** Maximum length of the filename to send as response to a POST request,
* filled in by the application when a POST is finished. * filled in by the application when a POST is finished.
*/ */
@ -216,6 +252,12 @@
#define LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED 0 #define LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED 0
#endif #endif
/** Set this to 1 to send URIs without extension without headers
* (who uses this at all??) */
#ifndef LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI
#define LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI 0
#endif
/** Default: Tags are sent from struct http_state and are therefore volatile */ /** Default: Tags are sent from struct http_state and are therefore volatile */
#ifndef HTTP_IS_TAG_VOLATILE #ifndef HTTP_IS_TAG_VOLATILE
#define HTTP_IS_TAG_VOLATILE(ptr) TCP_WRITE_FLAG_COPY #define HTTP_IS_TAG_VOLATILE(ptr) TCP_WRITE_FLAG_COPY