mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-10-05 22:29:49 +00:00
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:
parent
7d77a52ea5
commit
025d5591eb
@ -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) {
|
||||||
|
@ -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
@ -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))
|
||||||
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
|
@ -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 */
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user