From 2179c2a88b1327238cf52d09d21baa4df56e6ad1 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Fri, 14 Sep 2012 16:18:35 +0000 Subject: [PATCH] enhanced httpd to support if-modified-since --- qse/include/qse/cmn/time.h | 2 + qse/include/qse/net/http.h | 4 +- qse/lib/net/htrd.c | 8 +- qse/lib/net/http.c | 151 ++++++++++++++++++++++++++++--------- qse/lib/net/httpd-file.c | 27 +++++-- 5 files changed, 147 insertions(+), 45 deletions(-) diff --git a/qse/include/qse/cmn/time.h b/qse/include/qse/cmn/time.h index 9aa2d4fd..065c7661 100644 --- a/qse/include/qse/cmn/time.h +++ b/qse/include/qse/cmn/time.h @@ -64,6 +64,8 @@ (((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_MSEC_TO_SEC(sec) ((sec) / QSE_MSECS_PER_SEC) + /** * 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). diff --git a/qse/include/qse/net/http.h b/qse/include/qse/net/http.h index 434172bc..73e0e4c2 100644 --- a/qse/include/qse/net/http.h +++ b/qse/include/qse/net/http.h @@ -180,12 +180,10 @@ int qse_parsehttprange ( qse_http_range_t* range ); -/* int qse_parsehttptime ( const qse_mchar_t* str, - qse_ntime_t* t + qse_ntime_t* nt ); -*/ qse_mchar_t* qse_fmthttptime ( qse_ntime_t nt, diff --git a/qse/lib/net/htrd.c b/qse/lib/net/htrd.c index 57016c44..bea44734 100644 --- a/qse/lib/net/htrd.c +++ b/qse/lib/net/htrd.c @@ -20,6 +20,7 @@ #include #include +#include #include "../cmn/mem.h" QSE_IMPLEMENT_COMMON_FUNCTIONS (htrd) @@ -185,11 +186,10 @@ void qse_htrd_fini (qse_htrd_t* htrd) #endif } -static qse_mchar_t* parse_initial_line ( - qse_htrd_t* htrd, qse_mchar_t* line) +static qse_mchar_t* parse_initial_line (qse_htrd_t* htrd, qse_mchar_t* line) { qse_mchar_t* p = line; - qse_mcstr_t tmp; + qse_mxstr_t tmp; #if 0 /* ignore leading spaces excluding crlf */ @@ -293,7 +293,9 @@ static qse_mchar_t* parse_initial_line ( } else { +#if 0 qse_mchar_t* out; +#endif qse_mcstr_t param; /* skip spaces */ diff --git a/qse/lib/net/http.c b/qse/lib/net/http.c index 39210d8e..ab3e12cb 100644 --- a/qse/lib/net/http.c +++ b/qse/lib/net/http.c @@ -189,44 +189,127 @@ int qse_parsehttprange (const qse_mchar_t* str, qse_http_range_t* range) return 0; } -#if 0 -int qse_parsehttptime (const qse_mchar_t* str, qse_ntime_t* t) +typedef struct mname_t mname_t; +struct mname_t { -/* TODO: */ - return -1; + const qse_mchar_t* s; + 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_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_gmtime (nt, &bt); @@ -234,9 +317,9 @@ qse_mchar_t* qse_fmthttptime ( /* TODO: avoid using snprintf () */ snprintf (buf, bufsz, QSE_MT("%s, %d %s %d %02d:%02d:%02d GMT"), - wday_name[bt.wday], + wday_name[bt.wday].s, bt.mday, - mon_name[bt.mon], + mon_name[bt.mon].s, bt.year + QSE_BTIME_YEAR_BASE, bt.hour, bt.min, bt.sec); diff --git a/qse/lib/net/httpd-file.c b/qse/lib/net/httpd-file.c index 275ce88b..fb732698 100644 --- a/qse/lib/net/httpd-file.c +++ b/qse/lib/net/httpd-file.c @@ -227,6 +227,23 @@ qse_printf (QSE_T("opening file %hs\n"), file->path); { 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); /* 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.if_modified_since = QSE_TYPE_MIN(qse_ntime_t); -/* -TODO: If-Modified-Since... +/* TODO: support Etag and If-None-Match */ + data.if_modified_since = 0; /* 0 should be old enough */ tmp = qse_htre_getheaderval(req, QSE_MT("If-Modified-Since")); 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)); task.init = task_init_file;