1/** 2 * makefsdata: Converts a directory structure for use with the lwIP httpd. 3 * 4 * This file is part of the lwIP TCP/IP stack. 5 * 6 * Author: Jim Pettinato 7 * Simon Goldschmidt 8 * 9 * @todo: 10 * - take TCP_MSS, LWIP_TCP_TIMESTAMPS and 11 * PAYLOAD_ALIGN_TYPE/PAYLOAD_ALIGNMENT as arguments 12 */ 13 14#include <stdio.h> 15#include <stdlib.h> 16#include <string.h> 17#include <time.h> 18#include <sys/stat.h> 19 20#include "tinydir.h" 21 22/** Makefsdata can generate *all* files deflate-compressed (where file size shrinks). 23 * Since nearly all browsers support this, this is a good way to reduce ROM size. 24 * To compress the files, "miniz.c" must be downloaded seperately. 25 */ 26#ifndef MAKEFS_SUPPORT_DEFLATE 27#define MAKEFS_SUPPORT_DEFLATE 0 28#endif 29 30#define COPY_BUFSIZE (1024*1024) /* 1 MByte */ 31 32#if MAKEFS_SUPPORT_DEFLATE 33#include "../miniz.c" 34 35typedef unsigned char uint8; 36typedef unsigned short uint16; 37typedef unsigned int uint; 38 39#define my_max(a,b) (((a) > (b)) ? (a) : (b)) 40#define my_min(a,b) (((a) < (b)) ? (a) : (b)) 41 42/* COMP_OUT_BUF_SIZE is the size of the output buffer used during compression. 43 COMP_OUT_BUF_SIZE must be >= 1 and <= OUT_BUF_SIZE */ 44#define COMP_OUT_BUF_SIZE COPY_BUFSIZE 45 46/* OUT_BUF_SIZE is the size of the output buffer used during decompression. 47 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) */ 48#define OUT_BUF_SIZE COPY_BUFSIZE 49static uint8 s_outbuf[OUT_BUF_SIZE]; 50static uint8 s_checkbuf[OUT_BUF_SIZE]; 51 52/* tdefl_compressor contains all the state needed by the low-level compressor so it's a pretty big struct (~300k). 53 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. */ 54tdefl_compressor g_deflator; 55tinfl_decompressor g_inflator; 56 57int deflate_level = 10; /* default compression level, can be changed via command line */ 58#define USAGE_ARG_DEFLATE " [-defl<:compr_level>]" 59#else /* MAKEFS_SUPPORT_DEFLATE */ 60#define USAGE_ARG_DEFLATE "" 61#endif /* MAKEFS_SUPPORT_DEFLATE */ 62 63#ifdef WIN32 64 65#define GETCWD(path, len) GetCurrentDirectoryA(len, path) 66#define CHDIR(path) SetCurrentDirectoryA(path) 67#define CHDIR_SUCCEEDED(ret) (ret == TRUE) 68 69#elif __linux__ 70 71#define GETCWD(path, len) getcwd(path, len) 72#define CHDIR(path) chdir(path) 73#define CHDIR_SUCCEEDED(ret) (ret == 0) 74 75#else 76 77#error makefsdata not supported on this platform 78 79#endif 80 81#define NEWLINE "\r\n" 82#define NEWLINE_LEN 2 83 84/* define this to get the header variables we use to build HTTP headers */ 85#define LWIP_HTTPD_DYNAMIC_HEADERS 1 86#define LWIP_HTTPD_SSI 1 87#include "lwip/init.h" 88#include "../httpd_structs.h" 89#include "lwip/apps/fs.h" 90 91#include "../core/inet_chksum.c" 92#include "../core/def.c" 93 94/** (Your server name here) */ 95const char *serverID = "Server: "HTTPD_SERVER_AGENT"\r\n"; 96char serverIDBuffer[1024]; 97 98/* change this to suit your MEM_ALIGNMENT */ 99#define PAYLOAD_ALIGNMENT 4 100/* set this to 0 to prevent aligning payload */ 101#define ALIGN_PAYLOAD 1 102/* define this to a type that has the required alignment */ 103#define PAYLOAD_ALIGN_TYPE "unsigned int" 104static int payload_alingment_dummy_counter = 0; 105 106#define HEX_BYTES_PER_LINE 16 107 108#define MAX_PATH_LEN 256 109 110struct file_entry { 111 struct file_entry *next; 112 const char *filename_c; 113}; 114 115int process_sub(FILE *data_file, FILE *struct_file); 116int process_file(FILE *data_file, FILE *struct_file, const char *filename); 117int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len, 118 u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed); 119int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i); 120int s_put_ascii(char *buf, const char *ascii_string, int len, int *i); 121void concat_files(const char *file1, const char *file2, const char *targetfile); 122int check_path(char *path, size_t size); 123static int checkSsiByFilelist(const char* filename_listfile); 124static int ext_in_list(const char* filename, const char *ext_list); 125static int file_to_exclude(const char* filename); 126static int file_can_be_compressed(const char* filename); 127 128/* 5 bytes per char + 3 bytes per line */ 129static char file_buffer_c[COPY_BUFSIZE * 5 + ((COPY_BUFSIZE / HEX_BYTES_PER_LINE) * 3)]; 130 131char curSubdir[MAX_PATH_LEN]; 132char lastFileVar[MAX_PATH_LEN]; 133char hdr_buf[4096]; 134 135unsigned char processSubs = 1; 136unsigned char includeHttpHeader = 1; 137unsigned char useHttp11 = 0; 138unsigned char supportSsi = 1; 139unsigned char precalcChksum = 0; 140unsigned char includeLastModified = 0; 141#if MAKEFS_SUPPORT_DEFLATE 142unsigned char deflateNonSsiFiles = 0; 143size_t deflatedBytesReduced = 0; 144size_t overallDataBytes = 0; 145#endif 146const char *exclude_list = NULL; 147const char *ncompress_list = NULL; 148 149struct file_entry *first_file = NULL; 150struct file_entry *last_file = NULL; 151 152static char *ssi_file_buffer; 153static char **ssi_file_lines; 154static size_t ssi_file_num_lines; 155 156static void print_usage(void) 157{ 158 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); 159 printf(" targetdir: relative or absolute path to files to convert" NEWLINE); 160 printf(" switch -s: toggle processing of subdirectories (default is on)" NEWLINE); 161 printf(" switch -e: exclude HTTP header from file (header is created at runtime, default is off)" NEWLINE); 162 printf(" switch -11: include HTTP 1.1 header (1.0 is default)" NEWLINE); 163 printf(" switch -nossi: no support for SSI (cannot calculate Content-Length for SSI)" NEWLINE); 164 printf(" switch -ssi: ssi filename (ssi support controlled by file list, not by extension)" NEWLINE); 165 printf(" switch -c: precalculate checksums for all pages (default is off)" NEWLINE); 166 printf(" switch -f: target filename (default is \"fsdata.c\")" NEWLINE); 167 printf(" switch -m: include \"Last-Modified\" header based on file time" NEWLINE); 168 printf(" switch -svr: server identifier sent in HTTP response header ('Server' field)" NEWLINE); 169 printf(" switch -x: comma separated list of extensions of files to exclude (e.g., -x:json,txt)" NEWLINE); 170 printf(" switch -xc: comma separated list of extensions of files to not compress (e.g., -xc:mp3,jpg)" NEWLINE); 171#if MAKEFS_SUPPORT_DEFLATE 172 printf(" switch -defl: deflate-compress all non-SSI files (with opt. compr.-level, default=10)" NEWLINE); 173 printf(" ATTENTION: browser has to support \"Content-Encoding: deflate\"!" NEWLINE); 174#endif 175 printf(" if targetdir not specified, htmlgen will attempt to" NEWLINE); 176 printf(" process files in subdirectory 'fs'" NEWLINE); 177} 178 179int main(int argc, char *argv[]) 180{ 181 char path[MAX_PATH_LEN]; 182 char appPath[MAX_PATH_LEN]; 183 FILE *data_file; 184 FILE *struct_file; 185 int filesProcessed; 186 int i; 187 char targetfile[MAX_PATH_LEN]; 188 strcpy(targetfile, "fsdata.c"); 189 190 memset(path, 0, sizeof(path)); 191 memset(appPath, 0, sizeof(appPath)); 192 193 printf(NEWLINE " makefsdata - HTML to C source converter" NEWLINE); 194 printf(" by Jim Pettinato - circa 2003 " NEWLINE); 195 printf(" extended by Simon Goldschmidt - 2009 " NEWLINE NEWLINE); 196 197 LWIP_ASSERT("sizeof(hdr_buf) must fit into an u16_t", sizeof(hdr_buf) <= 0xffff); 198 199 strcpy(path, "fs"); 200 for (i = 1; i < argc; i++) { 201 if (argv[i] == NULL) { 202 continue; 203 } 204 if (argv[i][0] == '-') { 205 if (strstr(argv[i], "-svr:") == argv[i]) { 206 snprintf(serverIDBuffer, sizeof(serverIDBuffer), "Server: %s\r\n", &argv[i][5]); 207 serverID = serverIDBuffer; 208 printf("Using Server-ID: \"%s\"\n", serverID); 209 } else if (!strcmp(argv[i], "-s")) { 210 processSubs = 0; 211 } else if (!strcmp(argv[i], "-e")) { 212 includeHttpHeader = 0; 213 } else if (!strcmp(argv[i], "-11")) { 214 useHttp11 = 1; 215 } else if (!strcmp(argv[i], "-nossi")) { 216 supportSsi = 0; 217 } else if (strstr(argv[i], "-ssi:") == argv[i]) { 218 const char* ssi_list_filename = &argv[i][5]; 219 if (checkSsiByFilelist(ssi_list_filename)) { 220 printf("Reading list of SSI files from \"%s\"\n", ssi_list_filename); 221 } else { 222 printf("Failed to load list of SSI files from \"%s\"\n", ssi_list_filename); 223 } 224 } else if (!strcmp(argv[i], "-c")) { 225 precalcChksum = 1; 226 } else if (strstr(argv[i], "-f:") == argv[i]) { 227 strncpy(targetfile, &argv[i][3], sizeof(targetfile) - 1); 228 targetfile[sizeof(targetfile) - 1] = 0; 229 printf("Writing to file \"%s\"\n", targetfile); 230 } else if (!strcmp(argv[i], "-m")) { 231 includeLastModified = 1; 232 } else if (!strcmp(argv[i], "-defl")) { 233#if MAKEFS_SUPPORT_DEFLATE 234 char *colon = strstr(argv[i], ":"); 235 if (colon) { 236 if (colon[1] != 0) { 237 int defl_level = atoi(&colon[1]); 238 if ((defl_level >= 0) && (defl_level <= 10)) { 239 deflate_level = defl_level; 240 } else { 241 printf("ERROR: deflate level must be [0..10]" NEWLINE); 242 exit(0); 243 } 244 } 245 } 246 deflateNonSsiFiles = 1; 247 printf("Deflating all non-SSI files with level %d (but only if size is reduced)" NEWLINE, deflate_level); 248#else 249 printf("WARNING: Deflate support is disabled\n"); 250#endif 251 } else if (strstr(argv[i], "-x:") == argv[i]) { 252 exclude_list = &argv[i][3]; 253 printf("Excluding files with extensions %s" NEWLINE, exclude_list); 254 } else if (strstr(argv[i], "-xc:") == argv[i]) { 255 ncompress_list = &argv[i][4]; 256 printf("Skipping compresion for files with extensions %s" NEWLINE, ncompress_list); 257 } else if ((strstr(argv[i], "-?")) || (strstr(argv[i], "-h"))) { 258 print_usage(); 259 exit(0); 260 } 261 } else if ((argv[i][0] == '/') && (argv[i][1] == '?') && (argv[i][2] == 0)) { 262 print_usage(); 263 exit(0); 264 } else { 265 strncpy(path, argv[i], sizeof(path) - 1); 266 path[sizeof(path) - 1] = 0; 267 } 268 } 269 270 if (!check_path(path, sizeof(path))) { 271 printf("Invalid path: \"%s\"." NEWLINE, path); 272 exit(-1); 273 } 274 275 GETCWD(appPath, MAX_PATH_LEN); 276 /* if command line param or subdir named 'fs' not found spout usage verbiage */ 277 if (!CHDIR_SUCCEEDED(CHDIR(path))) { 278 /* if no subdir named 'fs' (or the one which was given) exists, spout usage verbiage */ 279 printf(" Failed to open directory \"%s\"." NEWLINE NEWLINE, path); 280 print_usage(); 281 exit(-1); 282 } 283 CHDIR(appPath); 284 285 printf("HTTP %sheader will %s statically included." NEWLINE, 286 (includeHttpHeader ? (useHttp11 ? "1.1 " : "1.0 ") : ""), 287 (includeHttpHeader ? "be" : "not be")); 288 289 curSubdir[0] = '\0'; /* start off in web page's root directory - relative paths */ 290 printf(" Processing all files in directory %s", path); 291 if (processSubs) { 292 printf(" and subdirectories..." NEWLINE NEWLINE); 293 } else { 294 printf("..." NEWLINE NEWLINE); 295 } 296 297 data_file = fopen("fsdata.tmp", "wb"); 298 if (data_file == NULL) { 299 printf("Failed to create file \"fsdata.tmp\"\n"); 300 exit(-1); 301 } 302 struct_file = fopen("fshdr.tmp", "wb"); 303 if (struct_file == NULL) { 304 printf("Failed to create file \"fshdr.tmp\"\n"); 305 fclose(data_file); 306 exit(-1); 307 } 308 309 CHDIR(path); 310 311 fprintf(data_file, "#include \"lwip/apps/fs.h\"" NEWLINE); 312 fprintf(data_file, "#include \"lwip/def.h\"" NEWLINE NEWLINE NEWLINE); 313 314 fprintf(data_file, "#define file_NULL (struct fsdata_file *) NULL" NEWLINE NEWLINE NEWLINE); 315 /* define FS_FILE_FLAGS_HEADER_INCLUDED to 1 if not defined (compatibility with older httpd/fs) */ 316 fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_INCLUDED" NEWLINE "#define FS_FILE_FLAGS_HEADER_INCLUDED 1" NEWLINE "#endif" NEWLINE); 317 /* define FS_FILE_FLAGS_HEADER_PERSISTENT to 0 if not defined (compatibility with older httpd/fs: wasn't supported back then) */ 318 fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_PERSISTENT" NEWLINE "#define FS_FILE_FLAGS_HEADER_PERSISTENT 0" NEWLINE "#endif" NEWLINE); 319 320 /* define alignment defines */ 321#if ALIGN_PAYLOAD 322 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); 323#endif 324 fprintf(data_file, "#ifndef FSDATA_ALIGN_PRE" NEWLINE "#define FSDATA_ALIGN_PRE" NEWLINE "#endif" NEWLINE); 325 fprintf(data_file, "#ifndef FSDATA_ALIGN_POST" NEWLINE "#define FSDATA_ALIGN_POST" NEWLINE "#endif" NEWLINE); 326#if ALIGN_PAYLOAD 327 fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==2" NEWLINE "#include \"fsdata_alignment.h\"" NEWLINE "#endif" NEWLINE); 328#endif 329 330 sprintf(lastFileVar, "NULL"); 331 332 filesProcessed = process_sub(data_file, struct_file); 333 334 /* data_file now contains all of the raw data.. now append linked list of 335 * file header structs to allow embedded app to search for a file name */ 336 fprintf(data_file, NEWLINE NEWLINE); 337 fprintf(struct_file, "#define FS_ROOT file_%s" NEWLINE, lastFileVar); 338 fprintf(struct_file, "#define FS_NUMFILES %d" NEWLINE NEWLINE, filesProcessed); 339 340 fclose(data_file); 341 fclose(struct_file); 342 343 CHDIR(appPath); 344 /* append struct_file to data_file */ 345 printf(NEWLINE "Creating target file..." NEWLINE NEWLINE); 346 concat_files("fsdata.tmp", "fshdr.tmp", targetfile); 347 348 /* if succeeded, delete the temporary files */ 349 if (remove("fsdata.tmp") != 0) { 350 printf("Warning: failed to delete fsdata.tmp\n"); 351 } 352 if (remove("fshdr.tmp") != 0) { 353 printf("Warning: failed to delete fshdr.tmp\n"); 354 } 355 356 printf(NEWLINE "Processed %d files - done." NEWLINE, filesProcessed); 357#if MAKEFS_SUPPORT_DEFLATE 358 if (deflateNonSsiFiles) { 359 printf("(Deflated total byte reduction: %d bytes -> %d bytes (%.02f%%)" NEWLINE, 360 (int)overallDataBytes, (int)deflatedBytesReduced, (float)((deflatedBytesReduced * 100.0) / overallDataBytes)); 361 } 362#endif 363 printf(NEWLINE); 364 365 while (first_file != NULL) { 366 struct file_entry *fe = first_file; 367 first_file = fe->next; 368 free(fe); 369 } 370 371 if (ssi_file_buffer) { 372 free(ssi_file_buffer); 373 } 374 if (ssi_file_lines) { 375 free(ssi_file_lines); 376 } 377 378 return 0; 379} 380 381int check_path(char *path, size_t size) 382{ 383 size_t slen; 384 if (path[0] == 0) { 385 /* empty */ 386 return 0; 387 } 388 slen = strlen(path); 389 if (slen >= size) { 390 /* not NULL-terminated */ 391 return 0; 392 } 393 while ((slen > 0) && ((path[slen] == '\\') || (path[slen] == '/'))) { 394 /* path should not end with trailing backslash */ 395 path[slen] = 0; 396 slen--; 397 } 398 if (slen == 0) { 399 return 0; 400 } 401 return 1; 402} 403 404static void copy_file(const char *filename_in, FILE *fout) 405{ 406 FILE *fin; 407 size_t len; 408 void *buf; 409 fin = fopen(filename_in, "rb"); 410 if (fin == NULL) { 411 printf("Failed to open file \"%s\"\n", filename_in); 412 exit(-1); 413 } 414 buf = malloc(COPY_BUFSIZE); 415 while ((len = fread(buf, 1, COPY_BUFSIZE, fin)) > 0) { 416 fwrite(buf, 1, len, fout); 417 } 418 free(buf); 419 fclose(fin); 420} 421 422void concat_files(const char *file1, const char *file2, const char *targetfile) 423{ 424 FILE *fout; 425 fout = fopen(targetfile, "wb"); 426 if (fout == NULL) { 427 printf("Failed to open file \"%s\"\n", targetfile); 428 exit(-1); 429 } 430 copy_file(file1, fout); 431 copy_file(file2, fout); 432 fclose(fout); 433} 434 435int process_sub(FILE *data_file, FILE *struct_file) 436{ 437 tinydir_dir dir; 438 int filesProcessed = 0; 439 440 if (processSubs) { 441 /* process subs recursively */ 442 size_t sublen = strlen(curSubdir); 443 size_t freelen = sizeof(curSubdir) - sublen - 1; 444 int ret; 445 LWIP_ASSERT("sublen < sizeof(curSubdir)", sublen < sizeof(curSubdir)); 446 447 ret = tinydir_open_sorted(&dir, TINYDIR_STRING(".")); 448 449 if (ret == 0) { 450 unsigned int i; 451 for (i = 0; i < dir.n_files; i++) { 452 tinydir_file file; 453 454 ret = tinydir_readfile_n(&dir, &file, i); 455 456 if (ret == 0) { 457#if (defined _MSC_VER || defined __MINGW32__) && (defined _UNICODE) 458 size_t num_char_converted; 459 char currName[256]; 460 wcstombs_s(&num_char_converted, currName, sizeof(currName), file.name, sizeof(currName)); 461#else 462 const char *currName = file.name; 463#endif 464 465 if (currName[0] == '.') { 466 continue; 467 } 468 if (!file.is_dir) { 469 continue; 470 } 471 if (freelen > 0) { 472 CHDIR(currName); 473 strncat(curSubdir, "/", freelen); 474 strncat(curSubdir, currName, freelen - 1); 475 curSubdir[sizeof(curSubdir) - 1] = 0; 476 printf("processing subdirectory %s/..." NEWLINE, curSubdir); 477 filesProcessed += process_sub(data_file, struct_file); 478 CHDIR(".."); 479 curSubdir[sublen] = 0; 480 } else { 481 printf("WARNING: cannot process sub due to path length restrictions: \"%s/%s\"\n", curSubdir, currName); 482 } 483 } 484 } 485 } 486 487 ret = tinydir_open_sorted(&dir, TINYDIR_STRING(".")); 488 if (ret == 0) { 489 unsigned int i; 490 for (i = 0; i < dir.n_files; i++) { 491 tinydir_file file; 492 493 ret = tinydir_readfile_n(&dir, &file, i); 494 495 if (ret == 0) { 496 if (!file.is_dir) { 497#if (defined _MSC_VER || defined __MINGW32__) && (defined _UNICODE) 498 size_t num_char_converted; 499 char curName[256]; 500 wcstombs_s(&num_char_converted, curName, sizeof(curName), file.name, sizeof(curName)); 501#else 502 const char *curName = file.name; 503#endif 504 505 if (strcmp(curName, "fsdata.tmp") == 0) { 506 continue; 507 } 508 if (strcmp(curName, "fshdr.tmp") == 0) { 509 continue; 510 } 511 if (file_to_exclude(curName)) { 512 printf("skipping %s/%s by exclude list (-x option)..." NEWLINE, curSubdir, curName); 513 continue; 514 } 515 516 printf("processing %s/%s..." NEWLINE, curSubdir, curName); 517 518 if (process_file(data_file, struct_file, curName) < 0) { 519 printf(NEWLINE "Error... aborting" NEWLINE); 520 return -1; 521 } 522 filesProcessed++; 523 } 524 } 525 } 526 } 527 } 528 529 return filesProcessed; 530} 531 532static u8_t *get_file_data(const char *filename, int *file_size, int can_be_compressed, int *is_compressed) 533{ 534 FILE *inFile; 535 size_t fsize = 0; 536 u8_t *buf; 537 size_t r; 538 int rs; 539 LWIP_UNUSED_ARG(r); /* for LWIP_NOASSERT */ 540 inFile = fopen(filename, "rb"); 541 if (inFile == NULL) { 542 printf("Failed to open file \"%s\"\n", filename); 543 exit(-1); 544 } 545 fseek(inFile, 0, SEEK_END); 546 rs = ftell(inFile); 547 if (rs < 0) { 548 printf("ftell failed with %d\n", errno); 549 exit(-1); 550 } 551 fsize = (size_t)rs; 552 fseek(inFile, 0, SEEK_SET); 553 buf = (u8_t *)malloc(fsize); 554 LWIP_ASSERT("buf != NULL", buf != NULL); 555 r = fread(buf, 1, fsize, inFile); 556 LWIP_ASSERT("r == fsize", r == fsize); 557 *file_size = fsize; 558 *is_compressed = 0; 559#if MAKEFS_SUPPORT_DEFLATE 560 overallDataBytes += fsize; 561 if (deflateNonSsiFiles) { 562 if (can_be_compressed) { 563 if (fsize < OUT_BUF_SIZE) { 564 u8_t *ret_buf; 565 tdefl_status status; 566 size_t in_bytes = fsize; 567 size_t out_bytes = OUT_BUF_SIZE; 568 const void *next_in = buf; 569 void *next_out = s_outbuf; 570 /* 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). */ 571 mz_uint comp_flags = s_tdefl_num_probes[MZ_MIN(10, deflate_level)] | ((deflate_level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); 572 if (!deflate_level) { 573 comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; 574 } 575 status = tdefl_init(&g_deflator, NULL, NULL, comp_flags); 576 if (status != TDEFL_STATUS_OKAY) { 577 printf("tdefl_init() failed!\n"); 578 exit(-1); 579 } 580 memset(s_outbuf, 0, sizeof(s_outbuf)); 581 status = tdefl_compress(&g_deflator, next_in, &in_bytes, next_out, &out_bytes, TDEFL_FINISH); 582 if (status != TDEFL_STATUS_DONE) { 583 printf("deflate failed: %d\n", status); 584 exit(-1); 585 } 586 LWIP_ASSERT("out_bytes <= COPY_BUFSIZE", out_bytes <= OUT_BUF_SIZE); 587 if (out_bytes < fsize) { 588 ret_buf = (u8_t *)malloc(out_bytes); 589 LWIP_ASSERT("ret_buf != NULL", ret_buf != NULL); 590 memcpy(ret_buf, s_outbuf, out_bytes); 591 { 592 /* sanity-check compression be inflating and comparing to the original */ 593 tinfl_status dec_status; 594 tinfl_decompressor inflator; 595 size_t dec_in_bytes = out_bytes; 596 size_t dec_out_bytes = OUT_BUF_SIZE; 597 next_out = s_checkbuf; 598 599 tinfl_init(&inflator); 600 memset(s_checkbuf, 0, sizeof(s_checkbuf)); 601 dec_status = tinfl_decompress(&inflator, (const mz_uint8 *)ret_buf, &dec_in_bytes, s_checkbuf, (mz_uint8 *)next_out, &dec_out_bytes, 0); 602 LWIP_ASSERT("tinfl_decompress failed", dec_status == TINFL_STATUS_DONE); 603 LWIP_ASSERT("tinfl_decompress size mismatch", fsize == dec_out_bytes); 604 LWIP_ASSERT("decompressed memcmp failed", !memcmp(s_checkbuf, buf, fsize)); 605 } 606 /* free original buffer, use compressed data + size */ 607 free(buf); 608 buf = ret_buf; 609 *file_size = out_bytes; 610 printf(" - deflate: %d bytes -> %d bytes (%.02f%%)" NEWLINE, (int)fsize, (int)out_bytes, (float)((out_bytes * 100.0) / fsize)); 611 deflatedBytesReduced += (size_t)(fsize - out_bytes); 612 *is_compressed = 1; 613 } else { 614 printf(" - uncompressed: (would be %d bytes larger using deflate)" NEWLINE, (int)(out_bytes - fsize)); 615 } 616 } else { 617 printf(" - uncompressed: (file is larger than deflate bufer)" NEWLINE); 618 } 619 } else { 620 printf(" - cannot be compressed" NEWLINE); 621 } 622 } 623#else 624 LWIP_UNUSED_ARG(can_be_compressed); 625#endif 626 fclose(inFile); 627 return buf; 628} 629 630static void process_file_data(FILE *data_file, u8_t *file_data, size_t file_size) 631{ 632 size_t written, i, src_off = 0; 633 size_t off = 0; 634 LWIP_UNUSED_ARG(written); /* for LWIP_NOASSERT */ 635 for (i = 0; i < file_size; i++) { 636 LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - 5); 637 sprintf(&file_buffer_c[off], "0x%02x,", file_data[i]); 638 off += 5; 639 if ((++src_off % HEX_BYTES_PER_LINE) == 0) { 640 LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - NEWLINE_LEN); 641 memcpy(&file_buffer_c[off], NEWLINE, NEWLINE_LEN); 642 off += NEWLINE_LEN; 643 } 644 if (off + 20 >= sizeof(file_buffer_c)) { 645 written = fwrite(file_buffer_c, 1, off, data_file); 646 LWIP_ASSERT("written == off", written == off); 647 off = 0; 648 } 649 } 650 written = fwrite(file_buffer_c, 1, off, data_file); 651 LWIP_ASSERT("written == off", written == off); 652} 653 654static int write_checksums(FILE *struct_file, const char *varname, 655 u16_t hdr_len, u16_t hdr_chksum, const u8_t *file_data, size_t file_size) 656{ 657 int chunk_size = TCP_MSS; 658 int offset, src_offset; 659 size_t len; 660 int i = 0; 661#if LWIP_TCP_TIMESTAMPS 662 /* when timestamps are used, usable space is 12 bytes less per segment */ 663 chunk_size -= 12; 664#endif 665 666 fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); 667 fprintf(struct_file, "const struct fsdata_chksum chksums_%s[] = {" NEWLINE, varname); 668 669 if (hdr_len > 0) { 670 /* add checksum for HTTP header */ 671 fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, 0, hdr_chksum, hdr_len); 672 i++; 673 } 674 src_offset = 0; 675 for (offset = hdr_len; ; offset += len) { 676 unsigned short chksum; 677 const void *data = (const void *)&file_data[src_offset]; 678 len = LWIP_MIN(chunk_size, (int)file_size - src_offset); 679 if (len == 0) { 680 break; 681 } 682 chksum = ~inet_chksum(data, (u16_t)len); 683 /* add checksum for data */ 684 fprintf(struct_file, "{%d, 0x%04x, %"SZT_F"}," NEWLINE, offset, chksum, len); 685 i++; 686 } 687 fprintf(struct_file, "};" NEWLINE); 688 fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); 689 return i; 690} 691 692static int is_valid_char_for_c_var(char x) 693{ 694 if (((x >= 'A') && (x <= 'Z')) || 695 ((x >= 'a') && (x <= 'z')) || 696 ((x >= '0') && (x <= '9')) || 697 (x == '_')) { 698 return 1; 699 } 700 return 0; 701} 702 703static void fix_filename_for_c(char *qualifiedName, size_t max_len) 704{ 705 struct file_entry *f; 706 size_t len = strlen(qualifiedName); 707 char *new_name = (char *)malloc(len + 2); 708 int filename_ok; 709 int cnt = 0; 710 size_t i; 711 if (len + 3 == max_len) { 712 printf("File name too long: \"%s\"\n", qualifiedName); 713 exit(-1); 714 } 715 strcpy(new_name, qualifiedName); 716 for (i = 0; i < len; i++) { 717 if (!is_valid_char_for_c_var(new_name[i])) { 718 new_name[i] = '_'; 719 } 720 } 721 do { 722 filename_ok = 1; 723 for (f = first_file; f != NULL; f = f->next) { 724 if (!strcmp(f->filename_c, new_name)) { 725 filename_ok = 0; 726 cnt++; 727 /* try next unique file name */ 728 sprintf(&new_name[len], "%d", cnt); 729 break; 730 } 731 } 732 } while (!filename_ok && (cnt < 999)); 733 if (!filename_ok) { 734 printf("Failed to get unique file name: \"%s\"\n", qualifiedName); 735 exit(-1); 736 } 737 strcpy(qualifiedName, new_name); 738 free(new_name); 739} 740 741static void register_filename(const char *qualifiedName) 742{ 743 struct file_entry *fe = (struct file_entry *)malloc(sizeof(struct file_entry)); 744 fe->filename_c = strdup(qualifiedName); 745 fe->next = NULL; 746 if (first_file == NULL) { 747 first_file = last_file = fe; 748 } else { 749 last_file->next = fe; 750 last_file = fe; 751 } 752} 753 754static int checkSsiByFilelist(const char* filename_listfile) 755{ 756 FILE *f = fopen(filename_listfile, "r"); 757 if (f != NULL) { 758 char *buf; 759 long rs; 760 size_t fsize, readcount; 761 size_t i, l, num_lines; 762 char **lines; 763 int state; 764 765 fseek(f, 0, SEEK_END); 766 rs = ftell(f); 767 if (rs < 0) { 768 printf("ftell failed with %d\n", errno); 769 fclose(f); 770 return 0; 771 } 772 fsize = (size_t)rs; 773 fseek(f, 0, SEEK_SET); 774 buf = (char*)malloc(fsize); 775 if (!buf) { 776 printf("failed to allocate ssi file buffer\n"); 777 fclose(f); 778 return 0; 779 } 780 memset(buf, 0, fsize); 781 readcount = fread(buf, 1, fsize, f); 782 fclose(f); 783 if ((readcount > fsize) || !readcount) { 784 printf("failed to read data from ssi file\n"); 785 free(buf); 786 return 0; 787 } 788 789 /* first pass: get the number of lines (and convert newlines to '0') */ 790 num_lines = 1; 791 for (i = 0; i < readcount; i++) { 792 if (buf[i] == '\n') { 793 num_lines++; 794 buf[i] = 0; 795 } else if (buf[i] == '\r') { 796 buf[i] = 0; 797 } 798 } 799 /* allocate the line pointer array */ 800 lines = (char**)malloc(sizeof(char*) * num_lines); 801 if (!lines) { 802 printf("failed to allocate ssi line buffer\n"); 803 free(buf); 804 return 0; 805 } 806 memset(lines, 0, sizeof(char*) * num_lines); 807 l = 0; 808 state = 0; 809 for (i = 0; i < readcount; i++) { 810 if (state) { 811 /* waiting for null */ 812 if (buf[i] == 0) { 813 state = 0; 814 } 815 } else { 816 /* waiting for beginning of new string */ 817 if (buf[i] != 0) { 818 LWIP_ASSERT("lines array overflow", l < num_lines); 819 lines[l] = &buf[i]; 820 state = 1; 821 l++; 822 } 823 } 824 } 825 LWIP_ASSERT("lines array overflow", l < num_lines); 826 827 ssi_file_buffer = buf; 828 ssi_file_lines = lines; 829 ssi_file_num_lines = l; 830 } 831 return 0; 832} 833 834static int is_ssi_file(const char *filename) 835{ 836 if (supportSsi) { 837 if (ssi_file_buffer) { 838 /* compare by list */ 839 size_t i; 840 int ret = 0; 841 /* build up the relative path to this file */ 842 size_t sublen = strlen(curSubdir); 843 size_t freelen = sizeof(curSubdir) - sublen - 1; 844 strncat(curSubdir, "/", freelen); 845 strncat(curSubdir, filename, freelen - 1); 846 curSubdir[sizeof(curSubdir) - 1] = 0; 847 for (i = 0; i < ssi_file_num_lines; i++) { 848 const char *listed_file = ssi_file_lines[i]; 849 /* compare without the leading '/' */ 850 if (!strcmp(&curSubdir[1], listed_file)) { 851 ret = 1; 852 } 853 } 854 curSubdir[sublen] = 0; 855 return ret; 856 } else { 857 /* check file extension */ 858 size_t loop; 859 for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) { 860 if (strstr(filename, g_pcSSIExtensions[loop])) { 861 return 1; 862 } 863 } 864 } 865 } 866 return 0; 867} 868 869static int ext_in_list(const char* filename, const char *ext_list) 870{ 871 int found = 0; 872 const char *ext = ext_list; 873 if (ext_list == NULL) { 874 return 0; 875 } 876 while(*ext != '\0') { 877 const char *comma = strchr(ext, ','); 878 size_t ext_size; 879 size_t filename_size = strlen(filename); 880 if (comma == NULL) { 881 comma = strchr(ext, '\0'); 882 } 883 ext_size = comma - ext; 884 if ((filename[filename_size - ext_size - 1] == '.') && 885 !strncmp(&filename[filename_size - ext_size], ext, ext_size)) { 886 found = 1; 887 break; 888 } 889 ext = comma + 1; 890 } 891 892 return found; 893} 894 895static int file_to_exclude(const char *filename) 896{ 897 return (exclude_list != NULL) && ext_in_list(filename, exclude_list); 898} 899 900static int file_can_be_compressed(const char *filename) 901{ 902 return (ncompress_list == NULL) || !ext_in_list(filename, ncompress_list); 903} 904 905int process_file(FILE *data_file, FILE *struct_file, const char *filename) 906{ 907 char varname[MAX_PATH_LEN]; 908 int i = 0; 909 char qualifiedName[MAX_PATH_LEN]; 910 int file_size; 911 u16_t http_hdr_chksum = 0; 912 u16_t http_hdr_len = 0; 913 int chksum_count = 0; 914 u8_t flags = 0; 915 u8_t has_content_len; 916 u8_t *file_data; 917 int is_ssi; 918 int can_be_compressed; 919 int is_compressed = 0; 920 int flags_printed; 921 922 /* create qualified name (@todo: prepend slash or not?) */ 923 sprintf(qualifiedName, "%s/%s", curSubdir, filename); 924 /* create C variable name */ 925 strcpy(varname, qualifiedName); 926 /* convert slashes & dots to underscores */ 927 fix_filename_for_c(varname, MAX_PATH_LEN); 928 register_filename(varname); 929#if ALIGN_PAYLOAD 930 /* to force even alignment of array, type 1 */ 931 fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==1" NEWLINE); 932 fprintf(data_file, "static const " PAYLOAD_ALIGN_TYPE " dummy_align_%s = %d;" NEWLINE, varname, payload_alingment_dummy_counter++); 933 fprintf(data_file, "#endif" NEWLINE); 934#endif /* ALIGN_PAYLOAD */ 935 fprintf(data_file, "static const unsigned char FSDATA_ALIGN_PRE data_%s[] FSDATA_ALIGN_POST = {" NEWLINE, varname); 936 /* encode source file name (used by file system, not returned to browser) */ 937 fprintf(data_file, "/* %s (%"SZT_F" chars) */" NEWLINE, qualifiedName, strlen(qualifiedName) + 1); 938 file_put_ascii(data_file, qualifiedName, strlen(qualifiedName) + 1, &i); 939#if ALIGN_PAYLOAD 940 /* pad to even number of bytes to assure payload is on aligned boundary */ 941 while (i % PAYLOAD_ALIGNMENT != 0) { 942 fprintf(data_file, "0x%02x,", 0); 943 i++; 944 } 945#endif /* ALIGN_PAYLOAD */ 946 fprintf(data_file, NEWLINE); 947 948 is_ssi = is_ssi_file(filename); 949 if (is_ssi) { 950 flags |= FS_FILE_FLAGS_SSI; 951 } 952 has_content_len = !is_ssi; 953 can_be_compressed = includeHttpHeader && !is_ssi && file_can_be_compressed(filename); 954 file_data = get_file_data(filename, &file_size, can_be_compressed, &is_compressed); 955 if (includeHttpHeader) { 956 file_write_http_header(data_file, filename, file_size, &http_hdr_len, &http_hdr_chksum, has_content_len, is_compressed); 957 flags |= FS_FILE_FLAGS_HEADER_INCLUDED; 958 if (has_content_len) { 959 flags |= FS_FILE_FLAGS_HEADER_PERSISTENT; 960 if (useHttp11) { 961 flags |= FS_FILE_FLAGS_HEADER_HTTPVER_1_1; 962 } 963 } 964 } 965 if (precalcChksum) { 966 chksum_count = write_checksums(struct_file, varname, http_hdr_len, http_hdr_chksum, file_data, file_size); 967 } 968 969 /* build declaration of struct fsdata_file in temp file */ 970 fprintf(struct_file, "const struct fsdata_file file_%s[] = { {" NEWLINE, varname); 971 fprintf(struct_file, "file_%s," NEWLINE, lastFileVar); 972 fprintf(struct_file, "data_%s," NEWLINE, varname); 973 fprintf(struct_file, "data_%s + %d," NEWLINE, varname, i); 974 fprintf(struct_file, "sizeof(data_%s) - %d," NEWLINE, varname, i); 975 976 flags_printed = 0; 977 if (flags & FS_FILE_FLAGS_HEADER_INCLUDED) { 978 fputs("FS_FILE_FLAGS_HEADER_INCLUDED", struct_file); 979 flags_printed = 1; 980 } 981 if (flags & FS_FILE_FLAGS_HEADER_PERSISTENT) { 982 if (flags_printed) { 983 fputs(" | ", struct_file); 984 } 985 fputs("FS_FILE_FLAGS_HEADER_PERSISTENT", struct_file); 986 flags_printed = 1; 987 } 988 if (flags & FS_FILE_FLAGS_HEADER_HTTPVER_1_1) { 989 if (flags_printed) { 990 fputs(" | ", struct_file); 991 } 992 fputs("FS_FILE_FLAGS_HEADER_HTTPVER_1_1", struct_file); 993 flags_printed = 1; 994 } 995 if (flags & FS_FILE_FLAGS_SSI) { 996 if (flags_printed) { 997 fputs(" | ", struct_file); 998 } 999 fputs("FS_FILE_FLAGS_SSI", struct_file); 1000 flags_printed = 1; 1001 } 1002 if (!flags_printed) { 1003 fputs("0", struct_file); 1004 } 1005 fputs("," NEWLINE, struct_file); 1006 if (precalcChksum) { 1007 fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); 1008 fprintf(struct_file, "%d, chksums_%s," NEWLINE, chksum_count, varname); 1009 fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); 1010 } 1011 fprintf(struct_file, "}};" NEWLINE NEWLINE); 1012 strcpy(lastFileVar, varname); 1013 1014 /* write actual file contents */ 1015 i = 0; 1016 fprintf(data_file, NEWLINE "/* raw file data (%d bytes) */" NEWLINE, file_size); 1017 process_file_data(data_file, file_data, file_size); 1018 fprintf(data_file, "};" NEWLINE NEWLINE); 1019 free(file_data); 1020 return 0; 1021} 1022 1023int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len, 1024 u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed) 1025{ 1026 int i = 0; 1027 int response_type = HTTP_HDR_OK; 1028 const char *file_type; 1029 const char *cur_string; 1030 size_t cur_len; 1031 int written = 0; 1032 size_t hdr_len = 0; 1033 u16_t acc; 1034 const char *file_ext; 1035 size_t j; 1036 u8_t provide_last_modified = includeLastModified; 1037 1038 memset(hdr_buf, 0, sizeof(hdr_buf)); 1039 1040 if (useHttp11) { 1041 response_type = HTTP_HDR_OK_11; 1042 } 1043 1044 fprintf(data_file, NEWLINE "/* HTTP header */"); 1045 if (strstr(filename, "404") == filename) { 1046 response_type = HTTP_HDR_NOT_FOUND; 1047 if (useHttp11) { 1048 response_type = HTTP_HDR_NOT_FOUND_11; 1049 } 1050 } else if (strstr(filename, "400") == filename) { 1051 response_type = HTTP_HDR_BAD_REQUEST; 1052 if (useHttp11) { 1053 response_type = HTTP_HDR_BAD_REQUEST_11; 1054 } 1055 } else if (strstr(filename, "501") == filename) { 1056 response_type = HTTP_HDR_NOT_IMPL; 1057 if (useHttp11) { 1058 response_type = HTTP_HDR_NOT_IMPL_11; 1059 } 1060 } 1061 cur_string = g_psHTTPHeaderStrings[response_type]; 1062 cur_len = strlen(cur_string); 1063 fprintf(data_file, NEWLINE "/* \"%s\" (%"SZT_F" bytes) */" NEWLINE, cur_string, cur_len); 1064 written += file_put_ascii(data_file, cur_string, cur_len, &i); 1065 i = 0; 1066 if (precalcChksum) { 1067 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 1068 hdr_len += cur_len; 1069 } 1070 1071 cur_string = serverID; 1072 cur_len = strlen(cur_string); 1073 fprintf(data_file, NEWLINE "/* \"%s\" (%"SZT_F" bytes) */" NEWLINE, cur_string, cur_len); 1074 written += file_put_ascii(data_file, cur_string, cur_len, &i); 1075 i = 0; 1076 if (precalcChksum) { 1077 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 1078 hdr_len += cur_len; 1079 } 1080 1081 file_ext = filename; 1082 if (file_ext != NULL) { 1083 while (strstr(file_ext, ".") != NULL) { 1084 file_ext = strstr(file_ext, "."); 1085 file_ext++; 1086 } 1087 } 1088 if ((file_ext == NULL) || (*file_ext == 0)) { 1089 printf("failed to get extension for file \"%s\", using default.\n", filename); 1090 file_type = HTTP_HDR_DEFAULT_TYPE; 1091 } else { 1092 file_type = NULL; 1093 for (j = 0; j < NUM_HTTP_HEADERS; j++) { 1094 if (!strcmp(file_ext, g_psHTTPHeaders[j].extension)) { 1095 file_type = g_psHTTPHeaders[j].content_type; 1096 break; 1097 } 1098 } 1099 if (file_type == NULL) { 1100 printf("failed to get file type for extension \"%s\", using default.\n", file_ext); 1101 file_type = HTTP_HDR_DEFAULT_TYPE; 1102 } 1103 } 1104 1105 /* Content-Length is used for persistent connections in HTTP/1.1 but also for 1106 download progress in older versions 1107 @todo: just use a big-enough buffer and let the HTTPD send spaces? */ 1108 if (provide_content_len) { 1109 char intbuf[MAX_PATH_LEN]; 1110 int content_len = file_size; 1111 memset(intbuf, 0, sizeof(intbuf)); 1112 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH]; 1113 cur_len = strlen(cur_string); 1114 fprintf(data_file, NEWLINE "/* \"%s%d\r\n\" (%"SZT_F"+ bytes) */" NEWLINE, cur_string, content_len, cur_len + 2); 1115 written += file_put_ascii(data_file, cur_string, cur_len, &i); 1116 if (precalcChksum) { 1117 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 1118 hdr_len += cur_len; 1119 } 1120 1121 lwip_itoa(intbuf, sizeof(intbuf), content_len); 1122 strcat(intbuf, "\r\n"); 1123 cur_len = strlen(intbuf); 1124 written += file_put_ascii(data_file, intbuf, cur_len, &i); 1125 i = 0; 1126 if (precalcChksum) { 1127 memcpy(&hdr_buf[hdr_len], intbuf, cur_len); 1128 hdr_len += cur_len; 1129 } 1130 } 1131 if (provide_last_modified) { 1132 char modbuf[256]; 1133 struct stat stat_data; 1134 struct tm *t; 1135 memset(modbuf, 0, sizeof(modbuf)); 1136 memset(&stat_data, 0, sizeof(stat_data)); 1137 cur_string = modbuf; 1138 strcpy(modbuf, "Last-Modified: "); 1139 if (stat(filename, &stat_data) != 0) { 1140 printf("stat(%s) failed with error %d\n", filename, errno); 1141 exit(-1); 1142 } 1143 t = gmtime(&stat_data.st_mtime); 1144 if (t == NULL) { 1145 printf("gmtime() failed with error %d\n", errno); 1146 exit(-1); 1147 } 1148 strftime(&modbuf[15], sizeof(modbuf) - 15, "%a, %d %b %Y %H:%M:%S GMT", t); 1149 cur_len = strlen(cur_string); 1150 fprintf(data_file, NEWLINE "/* \"%s\"\r\n\" (%"SZT_F"+ bytes) */" NEWLINE, cur_string, cur_len + 2); 1151 written += file_put_ascii(data_file, cur_string, cur_len, &i); 1152 if (precalcChksum) { 1153 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 1154 hdr_len += cur_len; 1155 } 1156 1157 modbuf[0] = 0; 1158 strcat(modbuf, "\r\n"); 1159 cur_len = strlen(modbuf); 1160 written += file_put_ascii(data_file, modbuf, cur_len, &i); 1161 i = 0; 1162 if (precalcChksum) { 1163 memcpy(&hdr_buf[hdr_len], modbuf, cur_len); 1164 hdr_len += cur_len; 1165 } 1166 } 1167 1168 /* HTTP/1.1 implements persistent connections */ 1169 if (useHttp11) { 1170 if (provide_content_len) { 1171 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_KEEPALIVE]; 1172 } else { 1173 /* no Content-Length available, so a persistent connection is no possible 1174 because the client does not know the data length */ 1175 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE]; 1176 } 1177 cur_len = strlen(cur_string); 1178 fprintf(data_file, NEWLINE "/* \"%s\" (%"SZT_F" bytes) */" NEWLINE, cur_string, cur_len); 1179 written += file_put_ascii(data_file, cur_string, cur_len, &i); 1180 i = 0; 1181 if (precalcChksum) { 1182 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 1183 hdr_len += cur_len; 1184 } 1185 } 1186 1187#if MAKEFS_SUPPORT_DEFLATE 1188 if (is_compressed) { 1189 /* tell the client about the deflate encoding */ 1190 LWIP_ASSERT("error", deflateNonSsiFiles); 1191 cur_string = "Content-Encoding: deflate\r\n"; 1192 cur_len = strlen(cur_string); 1193 fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); 1194 written += file_put_ascii(data_file, cur_string, cur_len, &i); 1195 i = 0; 1196 } 1197#else 1198 LWIP_UNUSED_ARG(is_compressed); 1199#endif 1200 1201 /* write content-type, ATTENTION: this includes the double-CRLF! */ 1202 cur_string = file_type; 1203 cur_len = strlen(cur_string); 1204 fprintf(data_file, NEWLINE "/* \"%s\" (%"SZT_F" bytes) */" NEWLINE, cur_string, cur_len); 1205 written += file_put_ascii(data_file, cur_string, cur_len, &i); 1206 i = 0; 1207 1208 /* ATTENTION: headers are done now (double-CRLF has been written!) */ 1209 1210 if (precalcChksum) { 1211 LWIP_ASSERT("hdr_len + cur_len <= sizeof(hdr_buf)", hdr_len + cur_len <= sizeof(hdr_buf)); 1212 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 1213 hdr_len += cur_len; 1214 1215 LWIP_ASSERT("strlen(hdr_buf) == hdr_len", strlen(hdr_buf) == hdr_len); 1216 acc = ~inet_chksum(hdr_buf, (u16_t)hdr_len); 1217 *http_hdr_len = (u16_t)hdr_len; 1218 *http_hdr_chksum = acc; 1219 } 1220 1221 return written; 1222} 1223 1224int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i) 1225{ 1226 int x; 1227 for (x = 0; x < len; x++) { 1228 unsigned char cur = ascii_string[x]; 1229 fprintf(file, "0x%02x,", cur); 1230 if ((++(*i) % HEX_BYTES_PER_LINE) == 0) { 1231 fprintf(file, NEWLINE); 1232 } 1233 } 1234 return len; 1235} 1236 1237int s_put_ascii(char *buf, const char *ascii_string, int len, int *i) 1238{ 1239 int x; 1240 int idx = 0; 1241 for (x = 0; x < len; x++) { 1242 unsigned char cur = ascii_string[x]; 1243 sprintf(&buf[idx], "0x%02x,", cur); 1244 idx += 5; 1245 if ((++(*i) % HEX_BYTES_PER_LINE) == 0) { 1246 sprintf(&buf[idx], NEWLINE); 1247 idx += NEWLINE_LEN; 1248 } 1249 } 1250 return len; 1251} 1252