enhanced httpd to support if-modified-since
This commit is contained in:
parent
7466287f93
commit
2179c2a88b
@ -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).
|
||||||
|
@ -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,
|
||||||
|
@ -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 */
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user