Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
lwip_makefsdata.c
00001 /** 00002 * makefsdata: Converts a directory structure for use with the lwIP httpd. 00003 * 00004 * This file is part of the lwIP TCP/IP stack. 00005 * 00006 * Author: Jim Pettinato 00007 * Simon Goldschmidt 00008 * 00009 * @todo: 00010 * - take TCP_MSS, LWIP_TCP_TIMESTAMPS and 00011 * PAYLOAD_ALIGN_TYPE/PAYLOAD_ALIGNMENT as arguments 00012 */ 00013 00014 #include <stdio.h> 00015 #include <stdlib.h> 00016 #include <string.h> 00017 #include <time.h> 00018 #include <sys/stat.h> 00019 00020 #include "tinydir.h" 00021 00022 /** Makefsdata can generate *all* files deflate-compressed (where file size shrinks). 00023 * Since nearly all browsers support this, this is a good way to reduce ROM size. 00024 * To compress the files, "miniz.c" must be downloaded seperately. 00025 */ 00026 #ifndef MAKEFS_SUPPORT_DEFLATE 00027 #define MAKEFS_SUPPORT_DEFLATE 0 00028 #endif 00029 00030 #define COPY_BUFSIZE (1024*1024) /* 1 MByte */ 00031 00032 #if MAKEFS_SUPPORT_DEFLATE 00033 #include "../miniz.c" 00034 00035 typedef unsigned char uint8; 00036 typedef unsigned short uint16; 00037 typedef unsigned int uint; 00038 00039 #define my_max(a,b) (((a) > (b)) ? (a) : (b)) 00040 #define my_min(a,b) (((a) < (b)) ? (a) : (b)) 00041 00042 /* COMP_OUT_BUF_SIZE is the size of the output buffer used during compression. 00043 COMP_OUT_BUF_SIZE must be >= 1 and <= OUT_BUF_SIZE */ 00044 #define COMP_OUT_BUF_SIZE COPY_BUFSIZE 00045 00046 /* OUT_BUF_SIZE is the size of the output buffer used during decompression. 00047 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) */ 00048 #define OUT_BUF_SIZE COPY_BUFSIZE 00049 static uint8 s_outbuf[OUT_BUF_SIZE]; 00050 static uint8 s_checkbuf[OUT_BUF_SIZE]; 00051 00052 /* tdefl_compressor contains all the state needed by the low-level compressor so it's a pretty big struct (~300k). 00053 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. */ 00054 tdefl_compressor g_deflator; 00055 tinfl_decompressor g_inflator; 00056 00057 int deflate_level = 10; /* default compression level, can be changed via command line */ 00058 #define USAGE_ARG_DEFLATE " [-defl<:compr_level>]" 00059 #else /* MAKEFS_SUPPORT_DEFLATE */ 00060 #define USAGE_ARG_DEFLATE "" 00061 #endif /* MAKEFS_SUPPORT_DEFLATE */ 00062 00063 #ifdef WIN32 00064 00065 #define GETCWD(path, len) GetCurrentDirectoryA(len, path) 00066 #define CHDIR(path) SetCurrentDirectoryA(path) 00067 #define CHDIR_SUCCEEDED(ret) (ret == TRUE) 00068 00069 #elif __linux__ 00070 00071 #define GETCWD(path, len) getcwd(path, len) 00072 #define CHDIR(path) chdir(path) 00073 #define CHDIR_SUCCEEDED(ret) (ret == 0) 00074 00075 #else 00076 00077 #error makefsdata not supported on this platform 00078 00079 #endif 00080 00081 #define NEWLINE "\r\n" 00082 #define NEWLINE_LEN 2 00083 00084 /* define this to get the header variables we use to build HTTP headers */ 00085 #define LWIP_HTTPD_DYNAMIC_HEADERS 1 00086 #define LWIP_HTTPD_SSI 1 00087 #include "lwip/init.h" 00088 #include "../httpd_structs.h" 00089 #include "lwip/apps/fs.h" 00090 00091 #include "../core/inet_chksum.c" 00092 #include "../core/def.c" 00093 00094 /** (Your server name here) */ 00095 const char *serverID = "Server: "HTTPD_SERVER_AGENT"\r\n"; 00096 char serverIDBuffer[1024]; 00097 00098 /* change this to suit your MEM_ALIGNMENT */ 00099 #define PAYLOAD_ALIGNMENT 4 00100 /* set this to 0 to prevent aligning payload */ 00101 #define ALIGN_PAYLOAD 1 00102 /* define this to a type that has the required alignment */ 00103 #define PAYLOAD_ALIGN_TYPE "unsigned int" 00104 static int payload_alingment_dummy_counter = 0; 00105 00106 #define HEX_BYTES_PER_LINE 16 00107 00108 #define MAX_PATH_LEN 256 00109 00110 struct file_entry { 00111 struct file_entry *next; 00112 const char *filename_c; 00113 }; 00114 00115 int process_sub(FILE *data_file, FILE *struct_file); 00116 int process_file(FILE *data_file, FILE *struct_file, const char *filename); 00117 int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len, 00118 u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed); 00119 int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i); 00120 int s_put_ascii(char *buf, const char *ascii_string, int len, int *i); 00121 void concat_files(const char *file1, const char *file2, const char *targetfile); 00122 int check_path(char *path, size_t size); 00123 static int checkSsiByFilelist(const char* filename_listfile); 00124 static int ext_in_list(const char* filename, const char *ext_list); 00125 static int file_to_exclude(const char* filename); 00126 static int file_can_be_compressed(const char* filename); 00127 00128 /* 5 bytes per char + 3 bytes per line */ 00129 static char file_buffer_c[COPY_BUFSIZE * 5 + ((COPY_BUFSIZE / HEX_BYTES_PER_LINE) * 3)]; 00130 00131 char curSubdir[MAX_PATH_LEN]; 00132 char lastFileVar[MAX_PATH_LEN]; 00133 char hdr_buf[4096]; 00134 00135 unsigned char processSubs = 1; 00136 unsigned char includeHttpHeader = 1; 00137 unsigned char useHttp11 = 0; 00138 unsigned char supportSsi = 1; 00139 unsigned char precalcChksum = 0; 00140 unsigned char includeLastModified = 0; 00141 #if MAKEFS_SUPPORT_DEFLATE 00142 unsigned char deflateNonSsiFiles = 0; 00143 size_t deflatedBytesReduced = 0; 00144 size_t overallDataBytes = 0; 00145 #endif 00146 const char *exclude_list = NULL; 00147 const char *ncompress_list = NULL; 00148 00149 struct file_entry *first_file = NULL; 00150 struct file_entry *last_file = NULL; 00151 00152 static char *ssi_file_buffer; 00153 static char **ssi_file_lines; 00154 static size_t ssi_file_num_lines; 00155 00156 static void print_usage(void) 00157 { 00158 printf(" Usage: htmlgen [targetdir] [-s] [-e] [-11] [-nossi] [-ssi:<filename>] [-c] [-f:<filename>] [-m] [-svr:<name>] [-x:<ext_list>] [-xc:<ext_list>" USAGE_ARG_DEFLATE NEWLINE NEWLINE); 00159 printf(" targetdir: relative or absolute path to files to convert" NEWLINE); 00160 printf(" switch -s: toggle processing of subdirectories (default is on)" NEWLINE); 00161 printf(" switch -e: exclude HTTP header from file (header is created at runtime, default is off)" NEWLINE); 00162 printf(" switch -11: include HTTP 1.1 header (1.0 is default)" NEWLINE); 00163 printf(" switch -nossi: no support for SSI (cannot calculate Content-Length for SSI)" NEWLINE); 00164 printf(" switch -ssi: ssi filename (ssi support controlled by file list, not by extension)" NEWLINE); 00165 printf(" switch -c: precalculate checksums for all pages (default is off)" NEWLINE); 00166 printf(" switch -f: target filename (default is \"fsdata.c\")" NEWLINE); 00167 printf(" switch -m: include \"Last-Modified\" header based on file time" NEWLINE); 00168 printf(" switch -svr: server identifier sent in HTTP response header ('Server' field)" NEWLINE); 00169 printf(" switch -x: comma separated list of extensions of files to exclude (e.g., -x:json,txt)" NEWLINE); 00170 printf(" switch -xc: comma separated list of extensions of files to not compress (e.g., -xc:mp3,jpg)" NEWLINE); 00171 #if MAKEFS_SUPPORT_DEFLATE 00172 printf(" switch -defl: deflate-compress all non-SSI files (with opt. compr.-level, default=10)" NEWLINE); 00173 printf(" ATTENTION: browser has to support \"Content-Encoding: deflate\"!" NEWLINE); 00174 #endif 00175 printf(" if targetdir not specified, htmlgen will attempt to" NEWLINE); 00176 printf(" process files in subdirectory 'fs'" NEWLINE); 00177 } 00178 00179 int main(int argc, char *argv[]) 00180 { 00181 char path[MAX_PATH_LEN]; 00182 char appPath[MAX_PATH_LEN]; 00183 FILE *data_file; 00184 FILE *struct_file; 00185 int filesProcessed; 00186 int i; 00187 char targetfile[MAX_PATH_LEN]; 00188 strcpy(targetfile, "fsdata.c"); 00189 00190 memset(path, 0, sizeof(path)); 00191 memset(appPath, 0, sizeof(appPath)); 00192 00193 printf(NEWLINE " makefsdata - HTML to C source converter" NEWLINE); 00194 printf(" by Jim Pettinato - circa 2003 " NEWLINE); 00195 printf(" extended by Simon Goldschmidt - 2009 " NEWLINE NEWLINE); 00196 00197 LWIP_ASSERT("sizeof(hdr_buf) must fit into an u16_t", sizeof(hdr_buf) <= 0xffff); 00198 00199 strcpy(path, "fs"); 00200 for (i = 1; i < argc; i++) { 00201 if (argv[i] == NULL) { 00202 continue; 00203 } 00204 if (argv[i][0] == '-') { 00205 if (strstr(argv[i], "-svr:") == argv[i]) { 00206 snprintf(serverIDBuffer, sizeof(serverIDBuffer), "Server: %s\r\n", &argv[i][5]); 00207 serverID = serverIDBuffer; 00208 printf("Using Server-ID: \"%s\"\n", serverID); 00209 } else if (!strcmp(argv[i], "-s")) { 00210 processSubs = 0; 00211 } else if (!strcmp(argv[i], "-e")) { 00212 includeHttpHeader = 0; 00213 } else if (!strcmp(argv[i], "-11")) { 00214 useHttp11 = 1; 00215 } else if (!strcmp(argv[i], "-nossi")) { 00216 supportSsi = 0; 00217 } else if (strstr(argv[i], "-ssi:") == argv[i]) { 00218 const char* ssi_list_filename = &argv[i][5]; 00219 if (checkSsiByFilelist(ssi_list_filename)) { 00220 printf("Reading list of SSI files from \"%s\"\n", ssi_list_filename); 00221 } else { 00222 printf("Failed to load list of SSI files from \"%s\"\n", ssi_list_filename); 00223 } 00224 } else if (!strcmp(argv[i], "-c")) { 00225 precalcChksum = 1; 00226 } else if (strstr(argv[i], "-f:") == argv[i]) { 00227 strncpy(targetfile, &argv[i][3], sizeof(targetfile) - 1); 00228 targetfile[sizeof(targetfile) - 1] = 0; 00229 printf("Writing to file \"%s\"\n", targetfile); 00230 } else if (!strcmp(argv[i], "-m")) { 00231 includeLastModified = 1; 00232 } else if (!strcmp(argv[i], "-defl")) { 00233 #if MAKEFS_SUPPORT_DEFLATE 00234 char *colon = strstr(argv[i], ":"); 00235 if (colon) { 00236 if (colon[1] != 0) { 00237 int defl_level = atoi(&colon[1]); 00238 if ((defl_level >= 0) && (defl_level <= 10)) { 00239 deflate_level = defl_level; 00240 } else { 00241 printf("ERROR: deflate level must be [0..10]" NEWLINE); 00242 exit(0); 00243 } 00244 } 00245 } 00246 deflateNonSsiFiles = 1; 00247 printf("Deflating all non-SSI files with level %d (but only if size is reduced)" NEWLINE, deflate_level); 00248 #else 00249 printf("WARNING: Deflate support is disabled\n"); 00250 #endif 00251 } else if (strstr(argv[i], "-x:") == argv[i]) { 00252 exclude_list = &argv[i][3]; 00253 printf("Excluding files with extensions %s" NEWLINE, exclude_list); 00254 } else if (strstr(argv[i], "-xc:") == argv[i]) { 00255 ncompress_list = &argv[i][4]; 00256 printf("Skipping compresion for files with extensions %s" NEWLINE, ncompress_list); 00257 } else if ((strstr(argv[i], "-?")) || (strstr(argv[i], "-h"))) { 00258 print_usage(); 00259 exit(0); 00260 } 00261 } else if ((argv[i][0] == '/') && (argv[i][1] == '?') && (argv[i][2] == 0)) { 00262 print_usage(); 00263 exit(0); 00264 } else { 00265 strncpy(path, argv[i], sizeof(path) - 1); 00266 path[sizeof(path) - 1] = 0; 00267 } 00268 } 00269 00270 if (!check_path(path, sizeof(path))) { 00271 printf("Invalid path: \"%s\"." NEWLINE, path); 00272 exit(-1); 00273 } 00274 00275 GETCWD(appPath, MAX_PATH_LEN); 00276 /* if command line param or subdir named 'fs' not found spout usage verbiage */ 00277 if (!CHDIR_SUCCEEDED(CHDIR(path))) { 00278 /* if no subdir named 'fs' (or the one which was given) exists, spout usage verbiage */ 00279 printf(" Failed to open directory \"%s\"." NEWLINE NEWLINE, path); 00280 print_usage(); 00281 exit(-1); 00282 } 00283 CHDIR(appPath); 00284 00285 printf("HTTP %sheader will %s statically included." NEWLINE, 00286 (includeHttpHeader ? (useHttp11 ? "1.1 " : "1.0 ") : ""), 00287 (includeHttpHeader ? "be" : "not be")); 00288 00289 curSubdir[0] = '\0'; /* start off in web page's root directory - relative paths */ 00290 printf(" Processing all files in directory %s", path); 00291 if (processSubs) { 00292 printf(" and subdirectories..." NEWLINE NEWLINE); 00293 } else { 00294 printf("..." NEWLINE NEWLINE); 00295 } 00296 00297 data_file = fopen("fsdata.tmp", "wb"); 00298 if (data_file == NULL) { 00299 printf("Failed to create file \"fsdata.tmp\"\n"); 00300 exit(-1); 00301 } 00302 struct_file = fopen("fshdr.tmp", "wb"); 00303 if (struct_file == NULL) { 00304 printf("Failed to create file \"fshdr.tmp\"\n"); 00305 fclose(data_file); 00306 exit(-1); 00307 } 00308 00309 CHDIR(path); 00310 00311 fprintf(data_file, "#include \"lwip/apps/fs.h\"" NEWLINE); 00312 fprintf(data_file, "#include \"lwip/def.h\"" NEWLINE NEWLINE NEWLINE); 00313 00314 fprintf(data_file, "#define file_NULL (struct fsdata_file *) NULL" NEWLINE NEWLINE NEWLINE); 00315 /* define FS_FILE_FLAGS_HEADER_INCLUDED to 1 if not defined (compatibility with older httpd/fs) */ 00316 fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_INCLUDED" NEWLINE "#define FS_FILE_FLAGS_HEADER_INCLUDED 1" NEWLINE "#endif" NEWLINE); 00317 /* define FS_FILE_FLAGS_HEADER_PERSISTENT to 0 if not defined (compatibility with older httpd/fs: wasn't supported back then) */ 00318 fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_PERSISTENT" NEWLINE "#define FS_FILE_FLAGS_HEADER_PERSISTENT 0" NEWLINE "#endif" NEWLINE); 00319 00320 /* define alignment defines */ 00321 #if ALIGN_PAYLOAD 00322 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); 00323 #endif 00324 fprintf(data_file, "#ifndef FSDATA_ALIGN_PRE" NEWLINE "#define FSDATA_ALIGN_PRE" NEWLINE "#endif" NEWLINE); 00325 fprintf(data_file, "#ifndef FSDATA_ALIGN_POST" NEWLINE "#define FSDATA_ALIGN_POST" NEWLINE "#endif" NEWLINE); 00326 #if ALIGN_PAYLOAD 00327 fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==2" NEWLINE "#include \"fsdata_alignment.h\"" NEWLINE "#endif" NEWLINE); 00328 #endif 00329 00330 sprintf(lastFileVar, "NULL"); 00331 00332 filesProcessed = process_sub(data_file, struct_file); 00333 00334 /* data_file now contains all of the raw data.. now append linked list of 00335 * file header structs to allow embedded app to search for a file name */ 00336 fprintf(data_file, NEWLINE NEWLINE); 00337 fprintf(struct_file, "#define FS_ROOT file_%s" NEWLINE, lastFileVar); 00338 fprintf(struct_file, "#define FS_NUMFILES %d" NEWLINE NEWLINE, filesProcessed); 00339 00340 fclose(data_file); 00341 fclose(struct_file); 00342 00343 CHDIR(appPath); 00344 /* append struct_file to data_file */ 00345 printf(NEWLINE "Creating target file..." NEWLINE NEWLINE); 00346 concat_files("fsdata.tmp", "fshdr.tmp", targetfile); 00347 00348 /* if succeeded, delete the temporary files */ 00349 if (remove("fsdata.tmp") != 0) { 00350 printf("Warning: failed to delete fsdata.tmp\n"); 00351 } 00352 if (remove("fshdr.tmp") != 0) { 00353 printf("Warning: failed to delete fshdr.tmp\n"); 00354 } 00355 00356 printf(NEWLINE "Processed %d files - done." NEWLINE, filesProcessed); 00357 #if MAKEFS_SUPPORT_DEFLATE 00358 if (deflateNonSsiFiles) { 00359 printf("(Deflated total byte reduction: %d bytes -> %d bytes (%.02f%%)" NEWLINE, 00360 (int)overallDataBytes, (int)deflatedBytesReduced, (float)((deflatedBytesReduced * 100.0) / overallDataBytes)); 00361 } 00362 #endif 00363 printf(NEWLINE); 00364 00365 while (first_file != NULL) { 00366 struct file_entry *fe = first_file; 00367 first_file = fe->next; 00368 free(fe); 00369 } 00370 00371 if (ssi_file_buffer) { 00372 free(ssi_file_buffer); 00373 } 00374 if (ssi_file_lines) { 00375 free(ssi_file_lines); 00376 } 00377 00378 return 0; 00379 } 00380 00381 int check_path(char *path, size_t size) 00382 { 00383 size_t slen; 00384 if (path[0] == 0) { 00385 /* empty */ 00386 return 0; 00387 } 00388 slen = strlen(path); 00389 if (slen >= size) { 00390 /* not NULL-terminated */ 00391 return 0; 00392 } 00393 while ((slen > 0) && ((path[slen] == '\\') || (path[slen] == '/'))) { 00394 /* path should not end with trailing backslash */ 00395 path[slen] = 0; 00396 slen--; 00397 } 00398 if (slen == 0) { 00399 return 0; 00400 } 00401 return 1; 00402 } 00403 00404 static void copy_file(const char *filename_in, FILE *fout) 00405 { 00406 FILE *fin; 00407 size_t len; 00408 void *buf; 00409 fin = fopen(filename_in, "rb"); 00410 if (fin == NULL) { 00411 printf("Failed to open file \"%s\"\n", filename_in); 00412 exit(-1); 00413 } 00414 buf = malloc(COPY_BUFSIZE); 00415 while ((len = fread(buf, 1, COPY_BUFSIZE, fin)) > 0) { 00416 fwrite(buf, 1, len, fout); 00417 } 00418 free(buf); 00419 fclose(fin); 00420 } 00421 00422 void concat_files(const char *file1, const char *file2, const char *targetfile) 00423 { 00424 FILE *fout; 00425 fout = fopen(targetfile, "wb"); 00426 if (fout == NULL) { 00427 printf("Failed to open file \"%s\"\n", targetfile); 00428 exit(-1); 00429 } 00430 copy_file(file1, fout); 00431 copy_file(file2, fout); 00432 fclose(fout); 00433 } 00434 00435 int process_sub(FILE *data_file, FILE *struct_file) 00436 { 00437 tinydir_dir dir; 00438 int filesProcessed = 0; 00439 00440 if (processSubs) { 00441 /* process subs recursively */ 00442 size_t sublen = strlen(curSubdir); 00443 size_t freelen = sizeof(curSubdir) - sublen - 1; 00444 int ret; 00445 LWIP_ASSERT("sublen < sizeof(curSubdir)", sublen < sizeof(curSubdir)); 00446 00447 ret = tinydir_open_sorted(&dir, TINYDIR_STRING(".")); 00448 00449 if (ret == 0) { 00450 unsigned int i; 00451 for (i = 0; i < dir.n_files; i++) { 00452 tinydir_file file; 00453 00454 ret = tinydir_readfile_n(&dir, &file, i); 00455 00456 if (ret == 0) { 00457 #if (defined _MSC_VER || defined __MINGW32__) && (defined _UNICODE) 00458 size_t num_char_converted; 00459 char currName[256]; 00460 wcstombs_s(&num_char_converted, currName, sizeof(currName), file.name, sizeof(currName)); 00461 #else 00462 const char *currName = file.name; 00463 #endif 00464 00465 if (currName[0] == '.') { 00466 continue; 00467 } 00468 if (!file.is_dir) { 00469 continue; 00470 } 00471 if (freelen > 0) { 00472 CHDIR(currName); 00473 strncat(curSubdir, "/", freelen); 00474 strncat(curSubdir, currName, freelen - 1); 00475 curSubdir[sizeof(curSubdir) - 1] = 0; 00476 printf("processing subdirectory %s/..." NEWLINE, curSubdir); 00477 filesProcessed += process_sub(data_file, struct_file); 00478 CHDIR(".."); 00479 curSubdir[sublen] = 0; 00480 } else { 00481 printf("WARNING: cannot process sub due to path length restrictions: \"%s/%s\"\n", curSubdir, currName); 00482 } 00483 } 00484 } 00485 } 00486 00487 ret = tinydir_open_sorted(&dir, TINYDIR_STRING(".")); 00488 if (ret == 0) { 00489 unsigned int i; 00490 for (i = 0; i < dir.n_files; i++) { 00491 tinydir_file file; 00492 00493 ret = tinydir_readfile_n(&dir, &file, i); 00494 00495 if (ret == 0) { 00496 if (!file.is_dir) { 00497 #if (defined _MSC_VER || defined __MINGW32__) && (defined _UNICODE) 00498 size_t num_char_converted; 00499 char curName[256]; 00500 wcstombs_s(&num_char_converted, curName, sizeof(curName), file.name, sizeof(curName)); 00501 #else 00502 const char *curName = file.name; 00503 #endif 00504 00505 if (strcmp(curName, "fsdata.tmp") == 0) { 00506 continue; 00507 } 00508 if (strcmp(curName, "fshdr.tmp") == 0) { 00509 continue; 00510 } 00511 if (file_to_exclude(curName)) { 00512 printf("skipping %s/%s by exclude list (-x option)..." NEWLINE, curSubdir, curName); 00513 continue; 00514 } 00515 00516 printf("processing %s/%s..." NEWLINE, curSubdir, curName); 00517 00518 if (process_file(data_file, struct_file, curName) < 0) { 00519 printf(NEWLINE "Error... aborting" NEWLINE); 00520 return -1; 00521 } 00522 filesProcessed++; 00523 } 00524 } 00525 } 00526 } 00527 } 00528 00529 return filesProcessed; 00530 } 00531 00532 static u8_t *get_file_data(const char *filename, int *file_size, int can_be_compressed, int *is_compressed) 00533 { 00534 FILE *inFile; 00535 size_t fsize = 0; 00536 u8_t *buf; 00537 size_t r; 00538 int rs; 00539 LWIP_UNUSED_ARG(r); /* for LWIP_NOASSERT */ 00540 inFile = fopen(filename, "rb"); 00541 if (inFile == NULL) { 00542 printf("Failed to open file \"%s\"\n", filename); 00543 exit(-1); 00544 } 00545 fseek(inFile, 0, SEEK_END); 00546 rs = ftell(inFile); 00547 if (rs < 0) { 00548 printf("ftell failed with %d\n", errno); 00549 exit(-1); 00550 } 00551 fsize = (size_t)rs; 00552 fseek(inFile, 0, SEEK_SET); 00553 buf = (u8_t *)malloc(fsize); 00554 LWIP_ASSERT("buf != NULL", buf != NULL); 00555 r = fread(buf, 1, fsize, inFile); 00556 LWIP_ASSERT("r == fsize", r == fsize); 00557 *file_size = fsize; 00558 *is_compressed = 0; 00559 #if MAKEFS_SUPPORT_DEFLATE 00560 overallDataBytes += fsize; 00561 if (deflateNonSsiFiles) { 00562 if (can_be_compressed) { 00563 if (fsize < OUT_BUF_SIZE) { 00564 u8_t *ret_buf; 00565 tdefl_status status; 00566 size_t in_bytes = fsize; 00567 size_t out_bytes = OUT_BUF_SIZE; 00568 const void *next_in = buf; 00569 void *next_out = s_outbuf; 00570 /* 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). */ 00571 mz_uint comp_flags = s_tdefl_num_probes[MZ_MIN(10, deflate_level)] | ((deflate_level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); 00572 if (!deflate_level) { 00573 comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; 00574 } 00575 status = tdefl_init(&g_deflator, NULL, NULL, comp_flags); 00576 if (status != TDEFL_STATUS_OKAY) { 00577 printf("tdefl_init() failed!\n"); 00578 exit(-1); 00579 } 00580 memset(s_outbuf, 0, sizeof(s_outbuf)); 00581 status = tdefl_compress(&g_deflator, next_in, &in_bytes, next_out, &out_bytes, TDEFL_FINISH); 00582 if (status != TDEFL_STATUS_DONE) { 00583 printf("deflate failed: %d\n", status); 00584 exit(-1); 00585 } 00586 LWIP_ASSERT("out_bytes <= COPY_BUFSIZE", out_bytes <= OUT_BUF_SIZE); 00587 if (out_bytes < fsize) { 00588 ret_buf = (u8_t *)malloc(out_bytes); 00589 LWIP_ASSERT("ret_buf != NULL", ret_buf != NULL); 00590 memcpy(ret_buf, s_outbuf, out_bytes); 00591 { 00592 /* sanity-check compression be inflating and comparing to the original */ 00593 tinfl_status dec_status; 00594 tinfl_decompressor inflator; 00595 size_t dec_in_bytes = out_bytes; 00596 size_t dec_out_bytes = OUT_BUF_SIZE; 00597 next_out = s_checkbuf; 00598 00599 tinfl_init(&inflator); 00600 memset(s_checkbuf, 0, sizeof(s_checkbuf)); 00601 dec_status = tinfl_decompress(&inflator, (const mz_uint8 *)ret_buf, &dec_in_bytes, s_checkbuf, (mz_uint8 *)next_out, &dec_out_bytes, 0); 00602 LWIP_ASSERT("tinfl_decompress failed", dec_status == TINFL_STATUS_DONE); 00603 LWIP_ASSERT("tinfl_decompress size mismatch", fsize == dec_out_bytes); 00604 LWIP_ASSERT("decompressed memcmp failed", !memcmp(s_checkbuf, buf, fsize)); 00605 } 00606 /* free original buffer, use compressed data + size */ 00607 free(buf); 00608 buf = ret_buf; 00609 *file_size = out_bytes; 00610 printf(" - deflate: %d bytes -> %d bytes (%.02f%%)" NEWLINE, (int)fsize, (int)out_bytes, (float)((out_bytes * 100.0) / fsize)); 00611 deflatedBytesReduced += (size_t)(fsize - out_bytes); 00612 *is_compressed = 1; 00613 } else { 00614 printf(" - uncompressed: (would be %d bytes larger using deflate)" NEWLINE, (int)(out_bytes - fsize)); 00615 } 00616 } else { 00617 printf(" - uncompressed: (file is larger than deflate bufer)" NEWLINE); 00618 } 00619 } else { 00620 printf(" - cannot be compressed" NEWLINE); 00621 } 00622 } 00623 #else 00624 LWIP_UNUSED_ARG(can_be_compressed); 00625 #endif 00626 fclose(inFile); 00627 return buf; 00628 } 00629 00630 static void process_file_data(FILE *data_file, u8_t *file_data, size_t file_size) 00631 { 00632 size_t written, i, src_off = 0; 00633 size_t off = 0; 00634 LWIP_UNUSED_ARG(written); /* for LWIP_NOASSERT */ 00635 for (i = 0; i < file_size; i++) { 00636 LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - 5); 00637 sprintf(&file_buffer_c[off], "0x%02x,", file_data[i]); 00638 off += 5; 00639 if ((++src_off % HEX_BYTES_PER_LINE) == 0) { 00640 LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - NEWLINE_LEN); 00641 memcpy(&file_buffer_c[off], NEWLINE, NEWLINE_LEN); 00642 off += NEWLINE_LEN; 00643 } 00644 if (off + 20 >= sizeof(file_buffer_c)) { 00645 written = fwrite(file_buffer_c, 1, off, data_file); 00646 LWIP_ASSERT("written == off", written == off); 00647 off = 0; 00648 } 00649 } 00650 written = fwrite(file_buffer_c, 1, off, data_file); 00651 LWIP_ASSERT("written == off", written == off); 00652 } 00653 00654 static int write_checksums(FILE *struct_file, const char *varname, 00655 u16_t hdr_len, u16_t hdr_chksum, const u8_t *file_data, size_t file_size) 00656 { 00657 int chunk_size = TCP_MSS; 00658 int offset, src_offset; 00659 size_t len; 00660 int i = 0; 00661 #if LWIP_TCP_TIMESTAMPS 00662 /* when timestamps are used, usable space is 12 bytes less per segment */ 00663 chunk_size -= 12; 00664 #endif 00665 00666 fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); 00667 fprintf(struct_file, "const struct fsdata_chksum chksums_%s[] = {" NEWLINE, varname); 00668 00669 if (hdr_len > 0) { 00670 /* add checksum for HTTP header */ 00671 fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, 0, hdr_chksum, hdr_len); 00672 i++; 00673 } 00674 src_offset = 0; 00675 for (offset = hdr_len; ; offset += len) { 00676 unsigned short chksum; 00677 const void *data = (const void *)&file_data[src_offset]; 00678 len = LWIP_MIN(chunk_size, (int)file_size - src_offset); 00679 if (len == 0) { 00680 break; 00681 } 00682 chksum = ~inet_chksum(data, (u16_t)len); 00683 /* add checksum for data */ 00684 fprintf(struct_file, "{%d, 0x%04x, %"SZT_F"}," NEWLINE, offset, chksum, len); 00685 i++; 00686 } 00687 fprintf(struct_file, "};" NEWLINE); 00688 fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); 00689 return i; 00690 } 00691 00692 static int is_valid_char_for_c_var(char x) 00693 { 00694 if (((x >= 'A') && (x <= 'Z')) || 00695 ((x >= 'a') && (x <= 'z')) || 00696 ((x >= '0') && (x <= '9')) || 00697 (x == '_')) { 00698 return 1; 00699 } 00700 return 0; 00701 } 00702 00703 static void fix_filename_for_c(char *qualifiedName, size_t max_len) 00704 { 00705 struct file_entry *f; 00706 size_t len = strlen(qualifiedName); 00707 char *new_name = (char *)malloc(len + 2); 00708 int filename_ok; 00709 int cnt = 0; 00710 size_t i; 00711 if (len + 3 == max_len) { 00712 printf("File name too long: \"%s\"\n", qualifiedName); 00713 exit(-1); 00714 } 00715 strcpy(new_name, qualifiedName); 00716 for (i = 0; i < len; i++) { 00717 if (!is_valid_char_for_c_var(new_name[i])) { 00718 new_name[i] = '_'; 00719 } 00720 } 00721 do { 00722 filename_ok = 1; 00723 for (f = first_file; f != NULL; f = f->next) { 00724 if (!strcmp(f->filename_c, new_name)) { 00725 filename_ok = 0; 00726 cnt++; 00727 /* try next unique file name */ 00728 sprintf(&new_name[len], "%d", cnt); 00729 break; 00730 } 00731 } 00732 } while (!filename_ok && (cnt < 999)); 00733 if (!filename_ok) { 00734 printf("Failed to get unique file name: \"%s\"\n", qualifiedName); 00735 exit(-1); 00736 } 00737 strcpy(qualifiedName, new_name); 00738 free(new_name); 00739 } 00740 00741 static void register_filename(const char *qualifiedName) 00742 { 00743 struct file_entry *fe = (struct file_entry *)malloc(sizeof(struct file_entry)); 00744 fe->filename_c = strdup(qualifiedName); 00745 fe->next = NULL; 00746 if (first_file == NULL) { 00747 first_file = last_file = fe; 00748 } else { 00749 last_file->next = fe; 00750 last_file = fe; 00751 } 00752 } 00753 00754 static int checkSsiByFilelist(const char* filename_listfile) 00755 { 00756 FILE *f = fopen(filename_listfile, "r"); 00757 if (f != NULL) { 00758 char *buf; 00759 long rs; 00760 size_t fsize, readcount; 00761 size_t i, l, num_lines; 00762 char **lines; 00763 int state; 00764 00765 fseek(f, 0, SEEK_END); 00766 rs = ftell(f); 00767 if (rs < 0) { 00768 printf("ftell failed with %d\n", errno); 00769 fclose(f); 00770 return 0; 00771 } 00772 fsize = (size_t)rs; 00773 fseek(f, 0, SEEK_SET); 00774 buf = (char*)malloc(fsize); 00775 if (!buf) { 00776 printf("failed to allocate ssi file buffer\n"); 00777 fclose(f); 00778 return 0; 00779 } 00780 memset(buf, 0, fsize); 00781 readcount = fread(buf, 1, fsize, f); 00782 fclose(f); 00783 if ((readcount > fsize) || !readcount) { 00784 printf("failed to read data from ssi file\n"); 00785 free(buf); 00786 return 0; 00787 } 00788 00789 /* first pass: get the number of lines (and convert newlines to '0') */ 00790 num_lines = 1; 00791 for (i = 0; i < readcount; i++) { 00792 if (buf[i] == '\n') { 00793 num_lines++; 00794 buf[i] = 0; 00795 } else if (buf[i] == '\r') { 00796 buf[i] = 0; 00797 } 00798 } 00799 /* allocate the line pointer array */ 00800 lines = (char**)malloc(sizeof(char*) * num_lines); 00801 if (!lines) { 00802 printf("failed to allocate ssi line buffer\n"); 00803 free(buf); 00804 return 0; 00805 } 00806 memset(lines, 0, sizeof(char*) * num_lines); 00807 l = 0; 00808 state = 0; 00809 for (i = 0; i < readcount; i++) { 00810 if (state) { 00811 /* waiting for null */ 00812 if (buf[i] == 0) { 00813 state = 0; 00814 } 00815 } else { 00816 /* waiting for beginning of new string */ 00817 if (buf[i] != 0) { 00818 LWIP_ASSERT("lines array overflow", l < num_lines); 00819 lines[l] = &buf[i]; 00820 state = 1; 00821 l++; 00822 } 00823 } 00824 } 00825 LWIP_ASSERT("lines array overflow", l < num_lines); 00826 00827 ssi_file_buffer = buf; 00828 ssi_file_lines = lines; 00829 ssi_file_num_lines = l; 00830 } 00831 return 0; 00832 } 00833 00834 static int is_ssi_file(const char *filename) 00835 { 00836 if (supportSsi) { 00837 if (ssi_file_buffer) { 00838 /* compare by list */ 00839 size_t i; 00840 int ret = 0; 00841 /* build up the relative path to this file */ 00842 size_t sublen = strlen(curSubdir); 00843 size_t freelen = sizeof(curSubdir) - sublen - 1; 00844 strncat(curSubdir, "/", freelen); 00845 strncat(curSubdir, filename, freelen - 1); 00846 curSubdir[sizeof(curSubdir) - 1] = 0; 00847 for (i = 0; i < ssi_file_num_lines; i++) { 00848 const char *listed_file = ssi_file_lines[i]; 00849 /* compare without the leading '/' */ 00850 if (!strcmp(&curSubdir[1], listed_file)) { 00851 ret = 1; 00852 } 00853 } 00854 curSubdir[sublen] = 0; 00855 return ret; 00856 } else { 00857 /* check file extension */ 00858 size_t loop; 00859 for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) { 00860 if (strstr(filename, g_pcSSIExtensions[loop])) { 00861 return 1; 00862 } 00863 } 00864 } 00865 } 00866 return 0; 00867 } 00868 00869 static int ext_in_list(const char* filename, const char *ext_list) 00870 { 00871 int found = 0; 00872 const char *ext = ext_list; 00873 if (ext_list == NULL) { 00874 return 0; 00875 } 00876 while(*ext != '\0') { 00877 const char *comma = strchr(ext, ','); 00878 size_t ext_size; 00879 size_t filename_size = strlen(filename); 00880 if (comma == NULL) { 00881 comma = strchr(ext, '\0'); 00882 } 00883 ext_size = comma - ext; 00884 if ((filename[filename_size - ext_size - 1] == '.') && 00885 !strncmp(&filename[filename_size - ext_size], ext, ext_size)) { 00886 found = 1; 00887 break; 00888 } 00889 ext = comma + 1; 00890 } 00891 00892 return found; 00893 } 00894 00895 static int file_to_exclude(const char *filename) 00896 { 00897 return (exclude_list != NULL) && ext_in_list(filename, exclude_list); 00898 } 00899 00900 static int file_can_be_compressed(const char *filename) 00901 { 00902 return (ncompress_list == NULL) || !ext_in_list(filename, ncompress_list); 00903 } 00904 00905 int process_file(FILE *data_file, FILE *struct_file, const char *filename) 00906 { 00907 char varname[MAX_PATH_LEN]; 00908 int i = 0; 00909 char qualifiedName[MAX_PATH_LEN]; 00910 int file_size; 00911 u16_t http_hdr_chksum = 0; 00912 u16_t http_hdr_len = 0; 00913 int chksum_count = 0; 00914 u8_t flags = 0; 00915 u8_t has_content_len; 00916 u8_t *file_data; 00917 int is_ssi; 00918 int can_be_compressed; 00919 int is_compressed = 0; 00920 int flags_printed; 00921 00922 /* create qualified name (@todo: prepend slash or not?) */ 00923 sprintf(qualifiedName, "%s/%s", curSubdir, filename); 00924 /* create C variable name */ 00925 strcpy(varname, qualifiedName); 00926 /* convert slashes & dots to underscores */ 00927 fix_filename_for_c(varname, MAX_PATH_LEN); 00928 register_filename(varname); 00929 #if ALIGN_PAYLOAD 00930 /* to force even alignment of array, type 1 */ 00931 fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==1" NEWLINE); 00932 fprintf(data_file, "static const " PAYLOAD_ALIGN_TYPE " dummy_align_%s = %d;" NEWLINE, varname, payload_alingment_dummy_counter++); 00933 fprintf(data_file, "#endif" NEWLINE); 00934 #endif /* ALIGN_PAYLOAD */ 00935 fprintf(data_file, "static const unsigned char FSDATA_ALIGN_PRE data_%s[] FSDATA_ALIGN_POST = {" NEWLINE, varname); 00936 /* encode source file name (used by file system, not returned to browser) */ 00937 fprintf(data_file, "/* %s (%"SZT_F" chars) */" NEWLINE, qualifiedName, strlen(qualifiedName) + 1); 00938 file_put_ascii(data_file, qualifiedName, strlen(qualifiedName) + 1, &i); 00939 #if ALIGN_PAYLOAD 00940 /* pad to even number of bytes to assure payload is on aligned boundary */ 00941 while (i % PAYLOAD_ALIGNMENT != 0) { 00942 fprintf(data_file, "0x%02x,", 0); 00943 i++; 00944 } 00945 #endif /* ALIGN_PAYLOAD */ 00946 fprintf(data_file, NEWLINE); 00947 00948 is_ssi = is_ssi_file(filename); 00949 if (is_ssi) { 00950 flags |= FS_FILE_FLAGS_SSI; 00951 } 00952 has_content_len = !is_ssi; 00953 can_be_compressed = includeHttpHeader && !is_ssi && file_can_be_compressed(filename); 00954 file_data = get_file_data(filename, &file_size, can_be_compressed, &is_compressed); 00955 if (includeHttpHeader) { 00956 file_write_http_header(data_file, filename, file_size, &http_hdr_len, &http_hdr_chksum, has_content_len, is_compressed); 00957 flags |= FS_FILE_FLAGS_HEADER_INCLUDED; 00958 if (has_content_len) { 00959 flags |= FS_FILE_FLAGS_HEADER_PERSISTENT; 00960 if (useHttp11) { 00961 flags |= FS_FILE_FLAGS_HEADER_HTTPVER_1_1; 00962 } 00963 } 00964 } 00965 if (precalcChksum) { 00966 chksum_count = write_checksums(struct_file, varname, http_hdr_len, http_hdr_chksum, file_data, file_size); 00967 } 00968 00969 /* build declaration of struct fsdata_file in temp file */ 00970 fprintf(struct_file, "const struct fsdata_file file_%s[] = { {" NEWLINE, varname); 00971 fprintf(struct_file, "file_%s," NEWLINE, lastFileVar); 00972 fprintf(struct_file, "data_%s," NEWLINE, varname); 00973 fprintf(struct_file, "data_%s + %d," NEWLINE, varname, i); 00974 fprintf(struct_file, "sizeof(data_%s) - %d," NEWLINE, varname, i); 00975 00976 flags_printed = 0; 00977 if (flags & FS_FILE_FLAGS_HEADER_INCLUDED) { 00978 fputs("FS_FILE_FLAGS_HEADER_INCLUDED", struct_file); 00979 flags_printed = 1; 00980 } 00981 if (flags & FS_FILE_FLAGS_HEADER_PERSISTENT) { 00982 if (flags_printed) { 00983 fputs(" | ", struct_file); 00984 } 00985 fputs("FS_FILE_FLAGS_HEADER_PERSISTENT", struct_file); 00986 flags_printed = 1; 00987 } 00988 if (flags & FS_FILE_FLAGS_HEADER_HTTPVER_1_1) { 00989 if (flags_printed) { 00990 fputs(" | ", struct_file); 00991 } 00992 fputs("FS_FILE_FLAGS_HEADER_HTTPVER_1_1", struct_file); 00993 flags_printed = 1; 00994 } 00995 if (flags & FS_FILE_FLAGS_SSI) { 00996 if (flags_printed) { 00997 fputs(" | ", struct_file); 00998 } 00999 fputs("FS_FILE_FLAGS_SSI", struct_file); 01000 flags_printed = 1; 01001 } 01002 if (!flags_printed) { 01003 fputs("0", struct_file); 01004 } 01005 fputs("," NEWLINE, struct_file); 01006 if (precalcChksum) { 01007 fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); 01008 fprintf(struct_file, "%d, chksums_%s," NEWLINE, chksum_count, varname); 01009 fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); 01010 } 01011 fprintf(struct_file, "}};" NEWLINE NEWLINE); 01012 strcpy(lastFileVar, varname); 01013 01014 /* write actual file contents */ 01015 i = 0; 01016 fprintf(data_file, NEWLINE "/* raw file data (%d bytes) */" NEWLINE, file_size); 01017 process_file_data(data_file, file_data, file_size); 01018 fprintf(data_file, "};" NEWLINE NEWLINE); 01019 free(file_data); 01020 return 0; 01021 } 01022 01023 int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len, 01024 u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed) 01025 { 01026 int i = 0; 01027 int response_type = HTTP_HDR_OK; 01028 const char *file_type; 01029 const char *cur_string; 01030 size_t cur_len; 01031 int written = 0; 01032 size_t hdr_len = 0; 01033 u16_t acc; 01034 const char *file_ext; 01035 size_t j; 01036 u8_t provide_last_modified = includeLastModified; 01037 01038 memset(hdr_buf, 0, sizeof(hdr_buf)); 01039 01040 if (useHttp11) { 01041 response_type = HTTP_HDR_OK_11; 01042 } 01043 01044 fprintf(data_file, NEWLINE "/* HTTP header */"); 01045 if (strstr(filename, "404") == filename) { 01046 response_type = HTTP_HDR_NOT_FOUND; 01047 if (useHttp11) { 01048 response_type = HTTP_HDR_NOT_FOUND_11; 01049 } 01050 } else if (strstr(filename, "400") == filename) { 01051 response_type = HTTP_HDR_BAD_REQUEST; 01052 if (useHttp11) { 01053 response_type = HTTP_HDR_BAD_REQUEST_11; 01054 } 01055 } else if (strstr(filename, "501") == filename) { 01056 response_type = HTTP_HDR_NOT_IMPL; 01057 if (useHttp11) { 01058 response_type = HTTP_HDR_NOT_IMPL_11; 01059 } 01060 } 01061 cur_string = g_psHTTPHeaderStrings[response_type]; 01062 cur_len = strlen(cur_string); 01063 fprintf(data_file, NEWLINE "/* \"%s\" (%"SZT_F" bytes) */" NEWLINE, cur_string, cur_len); 01064 written += file_put_ascii(data_file, cur_string, cur_len, &i); 01065 i = 0; 01066 if (precalcChksum) { 01067 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 01068 hdr_len += cur_len; 01069 } 01070 01071 cur_string = serverID; 01072 cur_len = strlen(cur_string); 01073 fprintf(data_file, NEWLINE "/* \"%s\" (%"SZT_F" bytes) */" NEWLINE, cur_string, cur_len); 01074 written += file_put_ascii(data_file, cur_string, cur_len, &i); 01075 i = 0; 01076 if (precalcChksum) { 01077 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 01078 hdr_len += cur_len; 01079 } 01080 01081 file_ext = filename; 01082 if (file_ext != NULL) { 01083 while (strstr(file_ext, ".") != NULL) { 01084 file_ext = strstr(file_ext, "."); 01085 file_ext++; 01086 } 01087 } 01088 if ((file_ext == NULL) || (*file_ext == 0)) { 01089 printf("failed to get extension for file \"%s\", using default.\n", filename); 01090 file_type = HTTP_HDR_DEFAULT_TYPE; 01091 } else { 01092 file_type = NULL; 01093 for (j = 0; j < NUM_HTTP_HEADERS; j++) { 01094 if (!strcmp(file_ext, g_psHTTPHeaders[j].extension)) { 01095 file_type = g_psHTTPHeaders[j].content_type; 01096 break; 01097 } 01098 } 01099 if (file_type == NULL) { 01100 printf("failed to get file type for extension \"%s\", using default.\n", file_ext); 01101 file_type = HTTP_HDR_DEFAULT_TYPE; 01102 } 01103 } 01104 01105 /* Content-Length is used for persistent connections in HTTP/1.1 but also for 01106 download progress in older versions 01107 @todo: just use a big-enough buffer and let the HTTPD send spaces? */ 01108 if (provide_content_len) { 01109 char intbuf[MAX_PATH_LEN]; 01110 int content_len = file_size; 01111 memset(intbuf, 0, sizeof(intbuf)); 01112 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH]; 01113 cur_len = strlen(cur_string); 01114 fprintf(data_file, NEWLINE "/* \"%s%d\r\n\" (%"SZT_F"+ bytes) */" NEWLINE, cur_string, content_len, cur_len + 2); 01115 written += file_put_ascii(data_file, cur_string, cur_len, &i); 01116 if (precalcChksum) { 01117 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 01118 hdr_len += cur_len; 01119 } 01120 01121 lwip_itoa(intbuf, sizeof(intbuf), content_len); 01122 strcat(intbuf, "\r\n"); 01123 cur_len = strlen(intbuf); 01124 written += file_put_ascii(data_file, intbuf, cur_len, &i); 01125 i = 0; 01126 if (precalcChksum) { 01127 memcpy(&hdr_buf[hdr_len], intbuf, cur_len); 01128 hdr_len += cur_len; 01129 } 01130 } 01131 if (provide_last_modified) { 01132 char modbuf[256]; 01133 struct stat stat_data; 01134 struct tm *t; 01135 memset(modbuf, 0, sizeof(modbuf)); 01136 memset(&stat_data, 0, sizeof(stat_data)); 01137 cur_string = modbuf; 01138 strcpy(modbuf, "Last-Modified: "); 01139 if (stat(filename, &stat_data) != 0) { 01140 printf("stat(%s) failed with error %d\n", filename, errno); 01141 exit(-1); 01142 } 01143 t = gmtime(&stat_data.st_mtime); 01144 if (t == NULL) { 01145 printf("gmtime() failed with error %d\n", errno); 01146 exit(-1); 01147 } 01148 strftime(&modbuf[15], sizeof(modbuf) - 15, "%a, %d %b %Y %H:%M:%S GMT", t); 01149 cur_len = strlen(cur_string); 01150 fprintf(data_file, NEWLINE "/* \"%s\"\r\n\" (%"SZT_F"+ bytes) */" NEWLINE, cur_string, cur_len + 2); 01151 written += file_put_ascii(data_file, cur_string, cur_len, &i); 01152 if (precalcChksum) { 01153 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 01154 hdr_len += cur_len; 01155 } 01156 01157 modbuf[0] = 0; 01158 strcat(modbuf, "\r\n"); 01159 cur_len = strlen(modbuf); 01160 written += file_put_ascii(data_file, modbuf, cur_len, &i); 01161 i = 0; 01162 if (precalcChksum) { 01163 memcpy(&hdr_buf[hdr_len], modbuf, cur_len); 01164 hdr_len += cur_len; 01165 } 01166 } 01167 01168 /* HTTP/1.1 implements persistent connections */ 01169 if (useHttp11) { 01170 if (provide_content_len) { 01171 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_KEEPALIVE]; 01172 } else { 01173 /* no Content-Length available, so a persistent connection is no possible 01174 because the client does not know the data length */ 01175 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE]; 01176 } 01177 cur_len = strlen(cur_string); 01178 fprintf(data_file, NEWLINE "/* \"%s\" (%"SZT_F" bytes) */" NEWLINE, cur_string, cur_len); 01179 written += file_put_ascii(data_file, cur_string, cur_len, &i); 01180 i = 0; 01181 if (precalcChksum) { 01182 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 01183 hdr_len += cur_len; 01184 } 01185 } 01186 01187 #if MAKEFS_SUPPORT_DEFLATE 01188 if (is_compressed) { 01189 /* tell the client about the deflate encoding */ 01190 LWIP_ASSERT("error", deflateNonSsiFiles); 01191 cur_string = "Content-Encoding: deflate\r\n"; 01192 cur_len = strlen(cur_string); 01193 fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); 01194 written += file_put_ascii(data_file, cur_string, cur_len, &i); 01195 i = 0; 01196 } 01197 #else 01198 LWIP_UNUSED_ARG(is_compressed); 01199 #endif 01200 01201 /* write content-type, ATTENTION: this includes the double-CRLF! */ 01202 cur_string = file_type; 01203 cur_len = strlen(cur_string); 01204 fprintf(data_file, NEWLINE "/* \"%s\" (%"SZT_F" bytes) */" NEWLINE, cur_string, cur_len); 01205 written += file_put_ascii(data_file, cur_string, cur_len, &i); 01206 i = 0; 01207 01208 /* ATTENTION: headers are done now (double-CRLF has been written!) */ 01209 01210 if (precalcChksum) { 01211 LWIP_ASSERT("hdr_len + cur_len <= sizeof(hdr_buf)", hdr_len + cur_len <= sizeof(hdr_buf)); 01212 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 01213 hdr_len += cur_len; 01214 01215 LWIP_ASSERT("strlen(hdr_buf) == hdr_len", strlen(hdr_buf) == hdr_len); 01216 acc = ~inet_chksum(hdr_buf, (u16_t)hdr_len); 01217 *http_hdr_len = (u16_t)hdr_len; 01218 *http_hdr_chksum = acc; 01219 } 01220 01221 return written; 01222 } 01223 01224 int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i) 01225 { 01226 int x; 01227 for (x = 0; x < len; x++) { 01228 unsigned char cur = ascii_string[x]; 01229 fprintf(file, "0x%02x,", cur); 01230 if ((++(*i) % HEX_BYTES_PER_LINE) == 0) { 01231 fprintf(file, NEWLINE); 01232 } 01233 } 01234 return len; 01235 } 01236 01237 int s_put_ascii(char *buf, const char *ascii_string, int len, int *i) 01238 { 01239 int x; 01240 int idx = 0; 01241 for (x = 0; x < len; x++) { 01242 unsigned char cur = ascii_string[x]; 01243 sprintf(&buf[idx], "0x%02x,", cur); 01244 idx += 5; 01245 if ((++(*i) % HEX_BYTES_PER_LINE) == 0) { 01246 sprintf(&buf[idx], NEWLINE); 01247 idx += NEWLINE_LEN; 01248 } 01249 } 01250 return len; 01251 }
Generated on Tue Jul 12 2022 13:54:29 by
