enhanced httpd to support if-modified-since

This commit is contained in:
hyung-hwan 2012-09-14 16:18:35 +00:00
parent 7466287f93
commit 2179c2a88b
5 changed files with 147 additions and 45 deletions

View File

@ -64,6 +64,8 @@
(((qse_ntime_t)(sec) * QSE_MSECS_PER_SEC) + ((qse_ntime_t)(nsec) / QSE_NSECS_PER_MSEC)) (((qse_ntime_t)(sec) * QSE_MSECS_PER_SEC) + ((qse_ntime_t)(nsec) / QSE_NSECS_PER_MSEC))
#define QSE_SEC_TO_MSEC(sec) ((sec) * QSE_MSECS_PER_SEC) #define QSE_SEC_TO_MSEC(sec) ((sec) * QSE_MSECS_PER_SEC)
#define QSE_MSEC_TO_SEC(sec) ((sec) / QSE_MSECS_PER_SEC)
/** /**
* The qse_ntime_t type defines a numeric time type expressed in the * The qse_ntime_t type defines a numeric time type expressed in the
* number of milliseconds since the Epoch (00:00:00 UTC, Jan 1, 1970). * number of milliseconds since the Epoch (00:00:00 UTC, Jan 1, 1970).

View File

@ -180,12 +180,10 @@ int qse_parsehttprange (
qse_http_range_t* range qse_http_range_t* range
); );
/*
int qse_parsehttptime ( int qse_parsehttptime (
const qse_mchar_t* str, const qse_mchar_t* str,
qse_ntime_t* t qse_ntime_t* nt
); );
*/
qse_mchar_t* qse_fmthttptime ( qse_mchar_t* qse_fmthttptime (
qse_ntime_t nt, qse_ntime_t nt,

View File

@ -20,6 +20,7 @@
#include <qse/net/htrd.h> #include <qse/net/htrd.h>
#include <qse/cmn/chr.h> #include <qse/cmn/chr.h>
#include <qse/cmn/path.h>
#include "../cmn/mem.h" #include "../cmn/mem.h"
QSE_IMPLEMENT_COMMON_FUNCTIONS (htrd) QSE_IMPLEMENT_COMMON_FUNCTIONS (htrd)
@ -185,11 +186,10 @@ void qse_htrd_fini (qse_htrd_t* htrd)
#endif #endif
} }
static qse_mchar_t* parse_initial_line ( static qse_mchar_t* parse_initial_line (qse_htrd_t* htrd, qse_mchar_t* line)
qse_htrd_t* htrd, qse_mchar_t* line)
{ {
qse_mchar_t* p = line; qse_mchar_t* p = line;
qse_mcstr_t tmp; qse_mxstr_t tmp;
#if 0 #if 0
/* ignore leading spaces excluding crlf */ /* ignore leading spaces excluding crlf */
@ -293,7 +293,9 @@ static qse_mchar_t* parse_initial_line (
} }
else else
{ {
#if 0
qse_mchar_t* out; qse_mchar_t* out;
#endif
qse_mcstr_t param; qse_mcstr_t param;
/* skip spaces */ /* skip spaces */

View File

@ -189,44 +189,127 @@ int qse_parsehttprange (const qse_mchar_t* str, qse_http_range_t* range)
return 0; return 0;
} }
#if 0 typedef struct mname_t mname_t;
int qse_parsehttptime (const qse_mchar_t* str, qse_ntime_t* t) struct mname_t
{ {
/* TODO: */ const qse_mchar_t* s;
return -1; const qse_mchar_t* l;
};
static mname_t wday_name[] =
{
{ QSE_MT("Sun"), QSE_MT("Sunday") },
{ QSE_MT("Mon"), QSE_MT("Monday") },
{ QSE_MT("Tue"), QSE_MT("Tuesday") },
{ QSE_MT("Wed"), QSE_MT("Wednesday") },
{ QSE_MT("Thu"), QSE_MT("Thursday") },
{ QSE_MT("Fri"), QSE_MT("Friday") },
{ QSE_MT("Sat"), QSE_MT("Saturday") }
};
static mname_t mon_name[] =
{
{ QSE_MT("Jan"), QSE_MT("January") },
{ QSE_MT("Feb"), QSE_MT("February") },
{ QSE_MT("Mar"), QSE_MT("March") },
{ QSE_MT("Apr"), QSE_MT("April") },
{ QSE_MT("May"), QSE_MT("May") },
{ QSE_MT("Jun"), QSE_MT("June") },
{ QSE_MT("Jul"), QSE_MT("July") },
{ QSE_MT("Aug"), QSE_MT("August") },
{ QSE_MT("Sep"), QSE_MT("September") },
{ QSE_MT("Oct"), QSE_MT("October") },
{ QSE_MT("Nov"), QSE_MT("November") },
{ QSE_MT("Dec"), QSE_MT("December") }
};
int qse_parsehttptime (const qse_mchar_t* str, qse_ntime_t* nt)
{
qse_btime_t bt;
const qse_mchar_t* word;
qse_size_t wlen, i;
/* TODO: support more formats */
QSE_MEMSET (&bt, 0, QSE_SIZEOF(bt));
/* weekday */
while (QSE_ISMSPACE(*str)) str++;
for (word = str; QSE_ISMALPHA(*str); str++);
wlen = str - word;
for (i = 0; i < QSE_COUNTOF(wday_name); i++)
{
if (qse_mbsxcmp (word, wlen, wday_name[i].s) == 0)
{
bt.wday = i;
break;
}
}
if (i >= QSE_COUNTOF(wday_name)) return -1;
/* comma - i'm just loose as i don't care if it doesn't exist */
while (QSE_ISMSPACE(*str)) str++;
if (*str == QSE_MT(',')) str++;
/* day */
while (QSE_ISMSPACE(*str)) str++;
if (!QSE_ISMDIGIT(*str)) return -1;
do bt.mday = bt.mday * 10 + *str++ - QSE_MT('0'); while (QSE_ISMDIGIT(*str));
/* month */
while (QSE_ISMSPACE(*str)) str++;
for (word = str; QSE_ISMALPHA(*str); str++);
wlen = str - word;
for (i = 0; i < QSE_COUNTOF(mon_name); i++)
{
if (qse_mbsxcmp (word, wlen, mon_name[i].s) == 0)
{
bt.mon = i;
break;
}
}
if (i >= QSE_COUNTOF(mon_name)) return -1;
/* year */
while (QSE_ISMSPACE(*str)) str++;
if (!QSE_ISMDIGIT(*str)) return -1;
do bt.year = bt.year * 10 + *str++ - QSE_MT('0'); while (QSE_ISMDIGIT(*str));
bt.year -= QSE_BTIME_YEAR_BASE;
/* hour */
while (QSE_ISMSPACE(*str)) str++;
if (!QSE_ISMDIGIT(*str)) return -1;
do bt.hour = bt.hour * 10 + *str++ - QSE_MT('0'); while (QSE_ISMDIGIT(*str));
if (*str != QSE_MT(':')) return -1;
str++;
/* min */
while (QSE_ISMSPACE(*str)) str++;
if (!QSE_ISMDIGIT(*str)) return -1;
do bt.min = bt.min * 10 + *str++ - QSE_MT('0'); while (QSE_ISMDIGIT(*str));
if (*str != QSE_MT(':')) return -1;
str++;
/* sec */
while (QSE_ISMSPACE(*str)) str++;
if (!QSE_ISMDIGIT(*str)) return -1;
do bt.sec = bt.sec * 10 + *str++ - QSE_MT('0'); while (QSE_ISMDIGIT(*str));
/* GMT */
while (QSE_ISMSPACE(*str)) str++;
for (word = str; QSE_ISMALPHA(*str); str++);
wlen = str - word;
if (qse_mbsxcmp (word, wlen, QSE_MT("GMT")) != 0) return -1;
while (QSE_ISMSPACE(*str)) str++;
if (*str != QSE_MT('\0')) return -1;
return qse_timegm (&bt, nt);
} }
#endif
qse_mchar_t* qse_fmthttptime ( qse_mchar_t* qse_fmthttptime (
qse_ntime_t nt, qse_mchar_t* buf, qse_size_t bufsz) qse_ntime_t nt, qse_mchar_t* buf, qse_size_t bufsz)
{ {
static const qse_mchar_t* wday_name[] =
{
QSE_MT("Sun"),
QSE_MT("Mon"),
QSE_MT("Tue"),
QSE_MT("Wed"),
QSE_MT("Thu"),
QSE_MT("Fri"),
QSE_MT("Sat")
};
static const qse_mchar_t* mon_name[] =
{
QSE_MT("Jan"),
QSE_MT("Feb"),
QSE_MT("Mar"),
QSE_MT("Apr"),
QSE_MT("May"),
QSE_MT("Jun"),
QSE_MT("Jul"),
QSE_MT("Aug"),
QSE_MT("Sep"),
QSE_MT("Oct"),
QSE_MT("Nov"),
QSE_MT("Dec")
};
qse_btime_t bt; qse_btime_t bt;
qse_gmtime (nt, &bt); qse_gmtime (nt, &bt);
@ -234,9 +317,9 @@ qse_mchar_t* qse_fmthttptime (
/* TODO: avoid using snprintf () */ /* TODO: avoid using snprintf () */
snprintf (buf, bufsz, snprintf (buf, bufsz,
QSE_MT("%s, %d %s %d %02d:%02d:%02d GMT"), QSE_MT("%s, %d %s %d %02d:%02d:%02d GMT"),
wday_name[bt.wday], wday_name[bt.wday].s,
bt.mday, bt.mday,
mon_name[bt.mon], mon_name[bt.mon].s,
bt.year + QSE_BTIME_YEAR_BASE, bt.year + QSE_BTIME_YEAR_BASE,
bt.hour, bt.min, bt.sec); bt.hour, bt.min, bt.sec);

View File

@ -227,6 +227,23 @@ qse_printf (QSE_T("opening file %hs\n"), file->path);
{ {
qse_mchar_t b_fsize[64]; qse_mchar_t b_fsize[64];
if (file->if_modified_since > 0 &&
QSE_MSEC_TO_SEC(st.mtime) <= QSE_MSEC_TO_SEC(file->if_modified_since))
{
/* i've converted milliseconds to seconds before comparison
* because st.mtime has the actual milliseconds less than 1 second
* while if_modified_since doesn't have such small milliseconds */
x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 304 Not Modified\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Length: 0\r\n\r\n"),
file->version.major, file->version.minor,
qse_httpd_getname (httpd),
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
(file->keepalive? QSE_MT("keep-alive"): QSE_MT("close"))
);
goto no_file_send;
}
qse_fmtuintmaxtombs (b_fsize, QSE_COUNTOF(b_fsize), st.size, 10, -1, QSE_MT('\0'), QSE_NULL); qse_fmtuintmaxtombs (b_fsize, QSE_COUNTOF(b_fsize), st.size, 10, -1, QSE_MT('\0'), QSE_NULL);
/* wget 1.8.2 set 'Connection: keep-alive' in the http 1.0 header. /* wget 1.8.2 set 'Connection: keep-alive' in the http 1.0 header.
@ -288,15 +305,15 @@ qse_httpd_task_t* qse_httpd_entaskfile (
data.range.type = QSE_HTTP_RANGE_NONE; data.range.type = QSE_HTTP_RANGE_NONE;
} }
data.if_modified_since = QSE_TYPE_MIN(qse_ntime_t); /* TODO: support Etag and If-None-Match */
/* data.if_modified_since = 0; /* 0 should be old enough */
TODO: If-Modified-Since...
tmp = qse_htre_getheaderval(req, QSE_MT("If-Modified-Since")); tmp = qse_htre_getheaderval(req, QSE_MT("If-Modified-Since"));
if (tmp) if (tmp)
{ {
qse_httpd_parsegmtime (tmp, & while (tmp->next) tmp = tmp->next; /* get the last value */
if (qse_parsehttptime (tmp->ptr, &data.if_modified_since) <= -1)
data.if_modified_since = 0;
} }
*/
QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
task.init = task_init_file; task.init = task_init_file;