changed the request inspection order for resource making
This commit is contained in:
parent
433b0da96d
commit
597824fc89
@ -100,6 +100,7 @@ struct qse_htre_t
|
||||
#define QSE_HTRE_ATTR_KEEPALIVE (1 << 2)
|
||||
#define QSE_HTRE_ATTR_EXPECT (1 << 3)
|
||||
#define QSE_HTRE_ATTR_EXPECT100 (1 << 4)
|
||||
#define QSE_HTRE_ATTR_PROXIED (1 << 5)
|
||||
int flags;
|
||||
qse_size_t content_length;
|
||||
const qse_mchar_t* status; /* for cgi */
|
||||
|
@ -469,6 +469,11 @@ enum qse_httpd_rsrc_type_t
|
||||
};
|
||||
typedef enum qse_httpd_rsrc_type_t qse_httpd_rsrc_type_t;
|
||||
|
||||
enum qse_httpd_rsrc_flag_t
|
||||
{
|
||||
QSE_HTTPD_RSRC_100_CONTINUE = (1 << 0)
|
||||
};
|
||||
|
||||
typedef struct qse_httpd_rsrc_cgi_t qse_httpd_rsrc_cgi_t;
|
||||
struct qse_httpd_rsrc_cgi_t
|
||||
{
|
||||
@ -484,6 +489,7 @@ typedef struct qse_httpd_rsrc_t qse_httpd_rsrc_t;
|
||||
struct qse_httpd_rsrc_t
|
||||
{
|
||||
qse_httpd_rsrc_type_t type;
|
||||
int flags; /**< bitwised-ORed of #qse_httpd_rsrc_flag_t */
|
||||
union
|
||||
{
|
||||
struct
|
||||
|
@ -30,6 +30,7 @@ struct task_dir_t
|
||||
qse_mcstr_t qpath;
|
||||
qse_http_version_t version;
|
||||
int keepalive;
|
||||
int headonly;
|
||||
};
|
||||
|
||||
typedef struct task_dseg_t task_dseg_t;
|
||||
@ -457,6 +458,9 @@ qse_httpd_task_t* qse_httpd_entaskdir (
|
||||
{
|
||||
qse_httpd_task_t task;
|
||||
task_dir_t data;
|
||||
int meth;
|
||||
|
||||
meth = qse_htre_getqmethodtype(req);
|
||||
|
||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||
data.path.ptr = path;
|
||||
@ -466,6 +470,25 @@ qse_httpd_task_t* qse_httpd_entaskdir (
|
||||
data.version = *qse_htre_getversion(req);
|
||||
data.keepalive = (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE);
|
||||
|
||||
switch (meth)
|
||||
{
|
||||
case QSE_HTTP_HEAD:
|
||||
data.headonly = 1;
|
||||
break;
|
||||
|
||||
case QSE_HTTP_OPTIONS:
|
||||
break;
|
||||
|
||||
case QSE_HTTP_GET:
|
||||
case QSE_HTTP_POST:
|
||||
case QSE_HTTP_PUT:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Method not allowed */
|
||||
return qse_httpd_entaskerr (httpd, client, pred, 405, req);
|
||||
}
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
task.init = task_init_dir;
|
||||
task.main = task_main_dir;
|
||||
|
@ -36,6 +36,7 @@ struct task_file_t
|
||||
qse_ntime_t if_modified_since;
|
||||
qse_http_version_t version;
|
||||
int keepalive;
|
||||
int headonly;
|
||||
};
|
||||
|
||||
typedef struct task_fseg_t task_fseg_t;
|
||||
@ -234,6 +235,7 @@ static QSE_INLINE int task_main_file (
|
||||
);
|
||||
if (x)
|
||||
{
|
||||
if (file->headonly) goto no_file_send;
|
||||
x = entask_file_segment (
|
||||
httpd, client, x,
|
||||
handle,
|
||||
@ -288,7 +290,11 @@ static QSE_INLINE int task_main_file (
|
||||
qse_httpd_fmtgmtimetobb (httpd, &st.mtime, 1),
|
||||
etag
|
||||
);
|
||||
if (x) x = entask_file_segment (httpd, client, x, handle, 0, st.size);
|
||||
if (x)
|
||||
{
|
||||
if (file->headonly) goto no_file_send;
|
||||
x = entask_file_segment (httpd, client, x, handle, 0, st.size);
|
||||
}
|
||||
}
|
||||
|
||||
if (x) return 0;
|
||||
@ -311,6 +317,9 @@ qse_httpd_task_t* qse_httpd_entaskfile (
|
||||
qse_httpd_task_t task;
|
||||
task_file_t data;
|
||||
const qse_htre_hdrval_t* tmp;
|
||||
int meth;
|
||||
|
||||
meth = qse_htre_getqmethodtype(req);;
|
||||
|
||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||
data.path.ptr = path;
|
||||
@ -323,6 +332,25 @@ qse_httpd_task_t* qse_httpd_entaskfile (
|
||||
data.version = *qse_htre_getversion(req);
|
||||
data.keepalive = (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE);
|
||||
|
||||
switch (meth)
|
||||
{
|
||||
case QSE_HTTP_HEAD:
|
||||
data.headonly = 1;
|
||||
break;
|
||||
|
||||
case QSE_HTTP_OPTIONS:
|
||||
break;
|
||||
|
||||
case QSE_HTTP_GET:
|
||||
case QSE_HTTP_POST:
|
||||
case QSE_HTTP_PUT:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Method not allowed */
|
||||
return qse_httpd_entaskerr (httpd, client, pred, 405, req);
|
||||
}
|
||||
|
||||
tmp = qse_htre_getheaderval(req, QSE_MT("Range"));
|
||||
if (tmp)
|
||||
{
|
||||
|
@ -1826,18 +1826,13 @@ qse_printf (QSE_T("HEADER OK %d[%hs] %d[%hs]\n"), (int)QSE_HTB_KLEN(pair), QSE_
|
||||
static int process_request (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, int peek)
|
||||
{
|
||||
int method;
|
||||
qse_httpd_task_t* task;
|
||||
int content_received;
|
||||
server_xtn_t* server_xtn;
|
||||
|
||||
server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, client->server);
|
||||
|
||||
method = qse_htre_getqmethodtype(req);
|
||||
content_received = (qse_htre_getcontentlen(req) > 0);
|
||||
|
||||
/* percent-decode the query path to the original buffer
|
||||
* since i'm not gonna need it in the original form
|
||||
* since i'm not going to need it in the original form
|
||||
* any more. once it's decoded in the peek mode,
|
||||
* the decoded query path is made available in the
|
||||
* non-peek mode as well */
|
||||
@ -1866,84 +1861,68 @@ if (qse_htre_getcontentlen(req) > 0)
|
||||
|
||||
if (peek)
|
||||
{
|
||||
#if 0
|
||||
if (method == QSE_HTTP_HEAD || method == QSE_HTTP_GET)
|
||||
qse_httpd_rsrc_t rsrc;
|
||||
|
||||
/* determine what to do once the header fields are all received.
|
||||
* i don't want to delay this until the contents are received.
|
||||
* if you don't like this behavior, you must implement your own
|
||||
* callback function for request handling. */
|
||||
|
||||
if (qse_htre_getqmethodtype(req) == QSE_HTTP_POST &&
|
||||
!(req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
|
||||
!(req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
|
||||
{
|
||||
/* i'll discard request contents if the method is HEAD or GET */
|
||||
/* POST without Content-Length nor not chunked */
|
||||
req->attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE;
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
}
|
||||
#endif
|
||||
if ((req->attr.flags & QSE_HTRE_ATTR_EXPECT) &&
|
||||
(req->version.major > 1 ||
|
||||
(req->version.major == 1 && req->version.minor >= 1)) &&
|
||||
!content_received)
|
||||
{
|
||||
int code;
|
||||
|
||||
/* "Expect" in the header, version 1.1 or higher,
|
||||
* and no content received yet.
|
||||
* if the partial or complete content is already received,
|
||||
* we don't need to send '100 continue'. */
|
||||
|
||||
if (req->attr.flags & QSE_HTRE_ATTR_EXPECT100)
|
||||
task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 411, req);
|
||||
if (task)
|
||||
{
|
||||
/* "Expect: 100-continue" in the header */
|
||||
if (qse_httpd_entaskcontinue (httpd, client, QSE_NULL, req) == QSE_NULL) return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if expectation fails, the client must not send the contents.
|
||||
* however, some erroneous clients may do that.
|
||||
* calling qse_httpd_discardcontent() won't do any harms */
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 417, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
/* 411 Length Required - can't keep alive. Force disconnect */
|
||||
task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (method == QSE_HTTP_GET || method == QSE_HTTP_POST)
|
||||
{
|
||||
if (peek)
|
||||
{
|
||||
qse_httpd_rsrc_t rsrc;
|
||||
|
||||
if (method == QSE_HTTP_POST &&
|
||||
!(req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
|
||||
!(req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
|
||||
{
|
||||
req->attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE;
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 411, req);
|
||||
if (task)
|
||||
{
|
||||
/* 411 Length Required - can't keep alive. Force disconnect */
|
||||
task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
||||
}
|
||||
}
|
||||
else if (server_xtn->makersrc (httpd, client, req, &rsrc) <= -1)
|
||||
{
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 500, req);
|
||||
}
|
||||
else
|
||||
{
|
||||
task = qse_httpd_entaskrsrc (httpd, client, QSE_NULL, &rsrc, req);
|
||||
server_xtn->freersrc (httpd, client, req, &rsrc);
|
||||
}
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (peek)
|
||||
else if (server_xtn->makersrc (httpd, client, req, &rsrc) <= -1)
|
||||
{
|
||||
/* failed to make a resource. just send the internal server error.
|
||||
* the makersrc handler can return a negative number to return
|
||||
* '500 Internal Server Error'. If it wants to return a specific
|
||||
* error code, it should return 0 with the QSE_HTTPD_RSRC_ERR
|
||||
* resource. */
|
||||
qse_httpd_discardcontent (httpd, req);
|
||||
task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 500, req);
|
||||
}
|
||||
else
|
||||
{
|
||||
task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 405, req);
|
||||
if (task == QSE_NULL) goto oops;
|
||||
task = QSE_NULL;
|
||||
|
||||
/* inject '100 continue' first if it is needed */
|
||||
if ((rsrc.flags & QSE_HTTPD_RSRC_100_CONTINUE) &&
|
||||
(task = qse_httpd_entaskcontinue (httpd, client, task, req)) == QSE_NULL) goto oops;
|
||||
|
||||
/* arrange the actual resource to be returned */
|
||||
task = qse_httpd_entaskrsrc (httpd, client, task, &rsrc, req);
|
||||
server_xtn->freersrc (httpd, client, req, &rsrc);
|
||||
|
||||
/* if the resource is indicating to return an error,
|
||||
* discard the contents since i won't return them */
|
||||
if (rsrc.type == QSE_HTTPD_RSRC_ERR) qse_httpd_discardcontent (httpd, req);
|
||||
}
|
||||
if (task == QSE_NULL) goto oops;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* contents are all received */
|
||||
|
||||
if (req->attr.flags & QSE_HTRE_ATTR_PROXIED)
|
||||
{
|
||||
/* the contents should be proxied.
|
||||
* do nothing locally */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* when the request is handled locally,
|
||||
* there's nothing special to do here */
|
||||
}
|
||||
}
|
||||
|
||||
@ -2435,7 +2414,7 @@ static int make_resource (
|
||||
struct rsrc_tmp_t tmp;
|
||||
|
||||
qse_httpd_stat_t st;
|
||||
int n, stx;
|
||||
int n, stx, meth;
|
||||
|
||||
QSE_MEMSET (&tmp, 0, QSE_SIZEOF(tmp));
|
||||
tmp.qpath = qse_htre_getqpath(req);
|
||||
@ -2445,7 +2424,7 @@ static int make_resource (
|
||||
|
||||
server_xtn = qse_httpd_getserverxtn (httpd, client->server);
|
||||
|
||||
if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_ROOT, &tmp.root) <= -1) return -1;
|
||||
if (server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_ROOT, &tmp.root) <= -1) return -1;
|
||||
if (tmp.root.type == QSE_HTTPD_SERVERSTD_ROOT_NWAD)
|
||||
{
|
||||
/* proxy the request */
|
||||
@ -2453,13 +2432,30 @@ static int make_resource (
|
||||
/*target->u.proxy.dst = client->orgdst_addr;*/
|
||||
target->u.proxy.dst = tmp.root.u.nwad;
|
||||
target->u.proxy.src = client->remote_addr;
|
||||
|
||||
/* mark that this request is going to be proxied. */
|
||||
req->attr.flags |= QSE_HTRE_ATTR_PROXIED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* handle the request locally */
|
||||
|
||||
#if 0
|
||||
meth = qse_htre_getqmethodtype(req);
|
||||
if (meth != QSE_HTTP_GET && meth != QSE_HTTP_POST && meth != QSE_HTTP_PUT && method != QSE_HTTP_)
|
||||
{
|
||||
/* TODO: handle more method types */
|
||||
/* method not allowed */
|
||||
target->type = QSE_HTTPD_RSRC_ERR;
|
||||
target->u.err.code = 405;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
QSE_ASSERT (tmp.root.type == QSE_HTTPD_SERVERSTD_ROOT_PATH);
|
||||
|
||||
if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_REALM, &tmp.realm) <= -1 ||
|
||||
server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_INDEX, &tmp.index) <= -1)
|
||||
if (server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_REALM, &tmp.realm) <= -1 ||
|
||||
server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_INDEX, &tmp.index) <= -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@ -2477,7 +2473,7 @@ static int make_resource (
|
||||
authv = qse_htre_getheaderval (req, QSE_MT("Authorization"));
|
||||
if (authv)
|
||||
{
|
||||
while (authv->next) authv = authv->next;
|
||||
/*while (authv->next) authv = authv->next;*/
|
||||
|
||||
if (qse_mbszcasecmp(authv->ptr, QSE_MT("Basic "), 6) == 0)
|
||||
{
|
||||
@ -2488,11 +2484,11 @@ static int make_resource (
|
||||
authl = qse_mbslen(&authv->ptr[6]);
|
||||
if (authl > server_xtn->auth.len)
|
||||
{
|
||||
qse_mchar_t* tmp;
|
||||
tmp = qse_httpd_reallocmem (httpd, server_xtn->auth.ptr, authl * QSE_SIZEOF(qse_mchar_t));
|
||||
if (!tmp) return -1;
|
||||
qse_mchar_t* tptr;
|
||||
tptr = qse_httpd_reallocmem (httpd, server_xtn->auth.ptr, authl * QSE_SIZEOF(qse_mchar_t));
|
||||
if (!tptr) return -1;
|
||||
|
||||
server_xtn->auth.ptr = tmp;
|
||||
server_xtn->auth.ptr = tptr;
|
||||
/* the maximum capacity that can hold the largest authorization value */
|
||||
server_xtn->auth.len = authl;
|
||||
}
|
||||
@ -2503,7 +2499,7 @@ static int make_resource (
|
||||
|
||||
tmp.auth.key.ptr = server_xtn->auth.ptr;
|
||||
tmp.auth.key.len = authl2;
|
||||
if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_AUTH, &tmp.auth) >= 0 && tmp.auth.authok) goto auth_ok;
|
||||
if (server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_AUTH, &tmp.auth) >= 0 && tmp.auth.authok) goto auth_ok;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2513,6 +2509,34 @@ static int make_resource (
|
||||
}
|
||||
|
||||
auth_ok:
|
||||
|
||||
/* if authentication is ok or no authentication is required,
|
||||
* handle 'Expect: 100-continue' if it is contained in the header */
|
||||
if ((req->attr.flags & QSE_HTRE_ATTR_EXPECT) &&
|
||||
(req->version.major > 1 || (req->version.major == 1 && req->version.minor >= 1)) &&
|
||||
qse_htre_getcontentlen(req) <= 0)
|
||||
{
|
||||
/* "Expect" in the header, version 1.1 or higher,
|
||||
* and no content received yet. don't care about the method type.
|
||||
*
|
||||
* if the partial or complete content is already received,
|
||||
* we don't need to send '100 continue'. */
|
||||
|
||||
if (req->attr.flags & QSE_HTRE_ATTR_EXPECT100)
|
||||
{
|
||||
/* "Expect: 100-continue" in the header.
|
||||
* mark to return "100 continue" */
|
||||
target->flags |= QSE_HTTPD_RSRC_100_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Expectation Failed */
|
||||
target->type = QSE_HTTPD_RSRC_ERR;
|
||||
target->u.err.code = 417;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
tmp.xpath = merge_paths (httpd, tmp.root.u.path.val, tmp.qpath_rp);
|
||||
if (tmp.xpath == QSE_NULL) return -1;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user