Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add support for Last-Modified and If-Modified-Since in althttpd.c. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
130feb0aa035f7cb438d929ba0b26767 |
User & Date: | drh 2018-02-25 01:29:01.208 |
Context
2018-02-25
| ||
17:25 | Change the action codes in the althttpd.c log to be consistent numbers, rather than source code line numbers. Include text at the end of a file that will generate a cross-reference table in SQLite. (check-in: 8aafa56bb9 user: drh tags: trunk) | |
01:29 | Add support for Last-Modified and If-Modified-Since in althttpd.c. (check-in: 130feb0aa0 user: drh tags: trunk) | |
2018-02-23
| ||
21:41 | Add support for the "Test Checklist" named "0demo" in the checklist.tcl application. (check-in: 53dab205ad user: drh tags: trunk) | |
Changes
Changes to misc/althttpd.c.
︙ | ︙ | |||
65 66 67 68 69 70 71 72 73 74 75 76 77 78 | ** $HOST.website subdirectories, each containing web content ** for a single virtual host. If launched as root and if ** "--user USER" also appears on the command-line and if ** "--jail 0" is omitted, then the process runs in a chroot ** jail rooted at this directory and under the userid USER. ** This option is required for xinetd launch but defaults ** to "." for a stand-alone web server. ** ** --user USER Define the user under which the process should run if ** originally launched as root. This process will refuse to ** run as root (for security). If this option is omitted and ** the process is launched as root, it will abort without ** processing any HTTP requests. ** | > > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | ** $HOST.website subdirectories, each containing web content ** for a single virtual host. If launched as root and if ** "--user USER" also appears on the command-line and if ** "--jail 0" is omitted, then the process runs in a chroot ** jail rooted at this directory and under the userid USER. ** This option is required for xinetd launch but defaults ** to "." for a stand-alone web server. ** ** --port N Run in standalone mode listening on TCP port N ** ** --user USER Define the user under which the process should run if ** originally launched as root. This process will refuse to ** run as root (for security). If this option is omitted and ** the process is launched as root, it will abort without ** processing any HTTP requests. ** |
︙ | ︙ | |||
237 238 239 240 241 242 243 244 245 246 247 248 249 250 | static char *zContentLength = 0; /* Content length reported in the header */ static char *zContentType = 0; /* Content type reported in the header */ static char *zQuerySuffix = 0; /* The part of the URL after the first ? */ static char *zAuthType = 0; /* Authorization type (basic or digest) */ static char *zAuthArg = 0; /* Authorization values */ static char *zRemoteUser = 0; /* REMOTE_USER set by authorization module */ static char *zIfNoneMatch= 0; /* The If-None-Match header value */ static int nIn = 0; /* Number of bytes of input */ static int nOut = 0; /* Number of bytes of output */ static char zReplyStatus[4]; /* Reply status code */ static int statusSent = 0; /* True after status line is sent */ static char *zLogFile = 0; /* Log to this file */ static int debugFlag = 0; /* True if being debugged */ static struct timeval beginTime; /* Time when this process starts */ | > | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | static char *zContentLength = 0; /* Content length reported in the header */ static char *zContentType = 0; /* Content type reported in the header */ static char *zQuerySuffix = 0; /* The part of the URL after the first ? */ static char *zAuthType = 0; /* Authorization type (basic or digest) */ static char *zAuthArg = 0; /* Authorization values */ static char *zRemoteUser = 0; /* REMOTE_USER set by authorization module */ static char *zIfNoneMatch= 0; /* The If-None-Match header value */ static char *zIfModifiedSince=0; /* The If-Modified-Since header value */ static int nIn = 0; /* Number of bytes of input */ static int nOut = 0; /* Number of bytes of output */ static char zReplyStatus[4]; /* Reply status code */ static int statusSent = 0; /* True after status line is sent */ static char *zLogFile = 0; /* Log to this file */ static int debugFlag = 0; /* True if being debugged */ static struct timeval beginTime; /* Time when this process starts */ |
︙ | ︙ | |||
483 484 485 486 487 488 489 490 491 492 493 494 495 | ** Break a line at the first \n or \r character seen. */ static void RemoveNewline(char *z){ if( z==0 ) return; while( *z && *z!='\n' && *z!='\r' ){ z++; } *z = 0; } /* ** Print a date tag in the header. The name of the tag is zTag. ** The date is determined from the unix timestamp given. */ static int DateTag(const char *zTag, time_t t){ | > > > > > > > > > > > > > | > > > > > > > | > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > | > > > | > > > > > | 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 | ** Break a line at the first \n or \r character seen. */ static void RemoveNewline(char *z){ if( z==0 ) return; while( *z && *z!='\n' && *z!='\r' ){ z++; } *z = 0; } /* Render seconds since 1970 as an RFC822 date string. Return ** a pointer to that string in a static buffer. */ static char *Rfc822Date(time_t t){ struct tm *tm; static char zDate[100]; tm = gmtime(&t); strftime(zDate, sizeof(zDate), "%a, %d %b %Y %H:%M:%S %z", tm); return zDate; } /* ** Print a date tag in the header. The name of the tag is zTag. ** The date is determined from the unix timestamp given. */ static int DateTag(const char *zTag, time_t t){ return printf("%s: %s\r\n", zTag, Rfc822Date(t)); } /* ** Parse an RFC822-formatted timestamp as we'd expect from HTTP and return ** a Unix epoch time. <= zero is returned on failure. */ time_t ParseRfc822Date(const char *zDate){ int mday, mon, year, yday, hour, min, sec; char zIgnore[4]; char zMonth[4]; static const char *const azMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0}; if( 7==sscanf(zDate, "%3[A-Za-z], %d %3[A-Za-z] %d %d:%d:%d", zIgnore, &mday, zMonth, &year, &hour, &min, &sec)){ if( year > 1900 ) year -= 1900; for(mon=0; azMonths[mon]; mon++){ if( !strncmp( azMonths[mon], zMonth, 3 )){ int nDay; int isLeapYr; static int priorDays[] = { 0, 31, 59, 90,120,151,181,212,243,273,304,334 }; if( mon<0 ){ int nYear = (11 - mon)/12; year -= nYear; mon += nYear*12; }else if( mon>11 ){ year += mon/12; mon %= 12; } isLeapYr = year%4==0 && (year%100!=0 || (year+300)%400==0); yday = priorDays[mon] + mday - 1; if( isLeapYr && mon>1 ) yday++; nDay = (year-70)*365 + (year-69)/4 - year/100 + (year+300)/400 + yday; return ((nDay*24 + hour)*60 + min)*60 + sec; } } } return 0; } /* ** Test procedure for ParseRfc822Date */ void TestParseRfc822Date(void){ time_t t1, t2; for(t1=0; t1<0x7fffffff; t1 += 127){ t2 = ParseRfc822Date(Rfc822Date(t1)); assert( t1==t2 ); } } /* ** Print the first line of a response followed by the server type. */ static void StartResponse(const char *zResultCode){ time_t now; |
︙ | ︙ | |||
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 | /* Get all the optional fields that follow the first line. */ zCookie = 0; zAuthType = 0; zRemoteUser = 0; zReferer = 0; zIfNoneMatch = 0; while( fgets(zLine,sizeof(zLine),stdin) ){ char *zFieldName; char *zVal; #ifdef LOG_HEADER if( hdrLog ) fprintf(hdrLog, "%s", zLine); #endif | > | 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 | /* Get all the optional fields that follow the first line. */ zCookie = 0; zAuthType = 0; zRemoteUser = 0; zReferer = 0; zIfNoneMatch = 0; zIfModifiedSince = 0; while( fgets(zLine,sizeof(zLine),stdin) ){ char *zFieldName; char *zVal; #ifdef LOG_HEADER if( hdrLog ) fprintf(hdrLog, "%s", zLine); #endif |
︙ | ︙ | |||
1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 | if( zRealPort ){ zServerPort = StrDup(zRealPort); } }else if( strcasecmp(zFieldName,"Authorization:")==0 ){ zAuthType = GetFirstElement(StrDup(zVal), &zAuthArg); }else if( strcasecmp(zFieldName,"If-None-Match:")==0 ){ zIfNoneMatch = StrDup(zVal); } } #ifdef LOG_HEADER if( hdrLog ) fclose(hdrLog); #endif /* Disallow requests from certain clients */ | > > | 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 | if( zRealPort ){ zServerPort = StrDup(zRealPort); } }else if( strcasecmp(zFieldName,"Authorization:")==0 ){ zAuthType = GetFirstElement(StrDup(zVal), &zAuthArg); }else if( strcasecmp(zFieldName,"If-None-Match:")==0 ){ zIfNoneMatch = StrDup(zVal); }else if( strcasecmp(zFieldName,"If-Modified-Since:")==0 ){ zIfModifiedSince = StrDup(zVal); } } #ifdef LOG_HEADER if( hdrLog ) fclose(hdrLog); #endif /* Disallow requests from certain clients */ |
︙ | ︙ | |||
1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 | { "CONTENT_TYPE", &zContentType }, { "DOCUMENT_ROOT", &zHome }, { "GATEWAY_INTERFACE", &gateway_interface }, { "HTTP_ACCEPT", &zAccept }, { "HTTP_ACCEPT_ENCODING", &zAcceptEncoding }, { "HTTP_COOKIE", &zCookie }, { "HTTP_HOST", &zHttpHost }, { "HTTP_IF_NONE_MATCH", &zIfNoneMatch }, { "HTTP_REFERER", &zReferer }, { "HTTP_USER_AGENT", &zAgent }, { "PATH", &default_path }, { "PATH_INFO", &zPathInfo }, { "QUERY_STRING", &zQueryString }, { "REMOTE_ADDR", &zRemoteAddr }, | > | 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 | { "CONTENT_TYPE", &zContentType }, { "DOCUMENT_ROOT", &zHome }, { "GATEWAY_INTERFACE", &gateway_interface }, { "HTTP_ACCEPT", &zAccept }, { "HTTP_ACCEPT_ENCODING", &zAcceptEncoding }, { "HTTP_COOKIE", &zCookie }, { "HTTP_HOST", &zHttpHost }, { "HTTP_IF_MODIFIED_SINCE", &zIfModifiedSince }, { "HTTP_IF_NONE_MATCH", &zIfNoneMatch }, { "HTTP_REFERER", &zReferer }, { "HTTP_USER_AGENT", &zAgent }, { "PATH", &default_path }, { "PATH_INFO", &zPathInfo }, { "QUERY_STRING", &zQueryString }, { "REMOTE_ADDR", &zRemoteAddr }, |
︙ | ︙ | |||
1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 | ** actual content file name, report that as a 404 error. */ NotFound(__LINE__); /* LOG: Excess URI content past static file name */ }else{ /* If it isn't executable then it ** must a simple file that needs to be copied to output. */ const char *zContentType = GetMimeType(zFile, lenFile); char zETag[100]; if( zTmpNam ) unlink(zTmpNam); sprintf(zETag, "m%xs%x", (int)statbuf.st_mtime, (int)statbuf.st_size); | > | > > > > > | 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 | ** actual content file name, report that as a 404 error. */ NotFound(__LINE__); /* LOG: Excess URI content past static file name */ }else{ /* If it isn't executable then it ** must a simple file that needs to be copied to output. */ const char *zContentType = GetMimeType(zFile, lenFile); time_t t; char zETag[100]; if( zTmpNam ) unlink(zTmpNam); sprintf(zETag, "m%xs%x", (int)statbuf.st_mtime, (int)statbuf.st_size); if( CompareEtags(zIfNoneMatch,zETag)==0 || (zIfModifiedSince!=0 && (t = ParseRfc822Date(zIfModifiedSince))>0 && t>=statbuf.st_mtime) ){ StartResponse("304 Not Modified"); nOut += DateTag("Last-Modified", statbuf.st_mtime); nOut += printf("Cache-Control: max-age=%d\r\n", mxAge); nOut += printf("ETag: \"%s\"\r\n", zETag); nOut += printf("\r\n"); fflush(stdout); MakeLogEntry(0, __LINE__); /* LOG: ETag Cache Hit */ return; } |
︙ | ︙ | |||
1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 | if( atoi(zArg)==0 ){ useChrootJail = 0; } }else if( strcmp(z, "-debug")==0 ){ if( atoi(zArg) ){ useTimeout = 0; } }else{ Malfunction(__LINE__, /* LOG: unknown command-line argument on launch */ "unknown argument: [%s]\n", z); } argv += 2; argc -= 2; } | > > > > | 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 | if( atoi(zArg)==0 ){ useChrootJail = 0; } }else if( strcmp(z, "-debug")==0 ){ if( atoi(zArg) ){ useTimeout = 0; } }else if( strcmp(z, "-datetest")==0 ){ TestParseRfc822Date(); printf("Ok\n"); exit(0); }else{ Malfunction(__LINE__, /* LOG: unknown command-line argument on launch */ "unknown argument: [%s]\n", z); } argv += 2; argc -= 2; } |
︙ | ︙ |