2011-02-11 07:48:51 +00:00
|
|
|
|
2011-07-12 10:31:33 +00:00
|
|
|
#include <qse/net/httpd.h>
|
|
|
|
#include <qse/cmn/stdio.h>
|
|
|
|
#include <qse/cmn/main.h>
|
2011-08-02 09:43:48 +00:00
|
|
|
#include <qse/cmn/str.h>
|
2011-12-28 14:26:02 +00:00
|
|
|
#include <qse/cmn/mem.h>
|
2011-02-11 07:48:51 +00:00
|
|
|
#include <signal.h>
|
|
|
|
|
2011-07-20 10:18:54 +00:00
|
|
|
#define MAX_SENDFILE_SIZE 4096
|
2011-07-15 10:00:37 +00:00
|
|
|
typedef struct httpd_xtn_t httpd_xtn_t;
|
|
|
|
struct httpd_xtn_t
|
|
|
|
{
|
|
|
|
const qse_httpd_cbs_t* orgcbs;
|
|
|
|
};
|
|
|
|
|
2011-07-20 10:18:54 +00:00
|
|
|
static qse_htb_walk_t walk (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx)
|
|
|
|
{
|
2011-12-05 13:43:56 +00:00
|
|
|
qse_printf (QSE_T("HEADER OK %d[%hs] %d[%hs]\n"), (int)QSE_HTB_KLEN(pair), QSE_HTB_KPTR(pair), (int)QSE_HTB_VLEN(pair), QSE_HTB_VPTR(pair));
|
2011-07-20 10:18:54 +00:00
|
|
|
return QSE_HTB_WALK_FORWARD;
|
|
|
|
}
|
|
|
|
|
2011-07-15 10:00:37 +00:00
|
|
|
static int handle_request (
|
|
|
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
|
|
|
{
|
2011-07-20 10:18:54 +00:00
|
|
|
int method;
|
2011-07-30 02:14:04 +00:00
|
|
|
qse_httpd_task_t* x;
|
2011-07-20 10:18:54 +00:00
|
|
|
|
|
|
|
#if 0
|
2011-07-15 10:00:37 +00:00
|
|
|
httpd_xtn_t* xtn = (httpd_xtn_t*) qse_httpd_getxtn (httpd);
|
|
|
|
return xtn->orgcbs->handle_request (httpd, client, req);
|
2011-07-20 10:18:54 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
qse_printf (QSE_T("================================\n"));
|
2011-12-05 13:43:56 +00:00
|
|
|
qse_printf (QSE_T("REQUEST ==> [%hs] version[%d.%d] method[%d]\n"),
|
2011-07-20 10:18:54 +00:00
|
|
|
qse_htre_getqpathptr(req),
|
|
|
|
qse_htre_getmajorversion(req),
|
|
|
|
qse_htre_getminorversion(req),
|
|
|
|
qse_htre_getqmethod(req)
|
|
|
|
);
|
|
|
|
if (qse_htre_getqparamlen(req) > 0)
|
|
|
|
{
|
2011-12-05 13:43:56 +00:00
|
|
|
qse_printf (QSE_T("PARAMS ==> [%hs]\n"), qse_htre_getqparamptr(req));
|
2011-07-20 10:18:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
qse_htb_walk (&req->hdrtab, walk, QSE_NULL);
|
|
|
|
if (QSE_MBS_LEN(&req->content) > 0)
|
|
|
|
{
|
|
|
|
qse_printf (QSE_T("content = [%.*S]\n"),
|
|
|
|
(int)QSE_MBS_LEN(&req->content),
|
|
|
|
QSE_MBS_PTR(&req->content));
|
|
|
|
}
|
|
|
|
|
|
|
|
method = qse_htre_getqmethod (req);
|
|
|
|
|
|
|
|
if (method == QSE_HTTP_GET || method == QSE_HTTP_POST)
|
|
|
|
{
|
2011-07-28 08:35:28 +00:00
|
|
|
const qse_mchar_t* rangestr;
|
|
|
|
qse_http_range_t range;
|
2011-07-20 10:18:54 +00:00
|
|
|
|
2011-08-02 09:43:48 +00:00
|
|
|
const qse_mchar_t* qpath = qse_htre_getqpathptr(req);
|
|
|
|
const qse_mchar_t* dot = qse_mbsrchr (qpath, QSE_MT('.'));
|
|
|
|
|
|
|
|
if (dot && qse_mbscmp (dot, QSE_MT(".cgi")) == 0)
|
|
|
|
{
|
2011-08-05 09:43:28 +00:00
|
|
|
/* cgi */
|
2011-08-11 10:18:35 +00:00
|
|
|
x = qse_httpd_entaskcgi (
|
|
|
|
httpd, client, QSE_NULL, qpath, req);
|
2011-08-05 09:43:28 +00:00
|
|
|
if (x == QSE_NULL) goto oops;
|
2011-08-02 09:43:48 +00:00
|
|
|
|
2011-07-30 02:14:04 +00:00
|
|
|
#if 0
|
2011-08-05 09:43:28 +00:00
|
|
|
x = qse_httpd_entasknphcgi (httpd, client, QSE_NULL, QSE_T("/tmp/test.cgi"), qse_htre_getversion(req));
|
2011-07-30 02:14:04 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-08-11 10:18:35 +00:00
|
|
|
rangestr = qse_htre_getheaderval (req, QSE_MT("Range"));
|
2011-08-05 09:43:28 +00:00
|
|
|
if (rangestr && qse_parsehttprange (rangestr, &range) <= -1)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
qse_httpd_entaskstatictext (httpd, client, QSE_NULL, QSE_MT("HTTP/1.1 416 Requested range not satisfiable\r\nContent-Length: 5\r\n\r\nA\r\n\r\n"));
|
|
|
|
#endif
|
|
|
|
const qse_mchar_t* msg;
|
|
|
|
msg = QSE_MT("<html><head><title>Requested range not satisfiable</title></head><body><b>REQUESTED RANGE NOT SATISFIABLE</b></body></html>");
|
|
|
|
x = qse_httpd_entaskformat (
|
|
|
|
httpd, client, QSE_NULL,
|
|
|
|
QSE_MT("HTTP/%d.%d 416 Requested range not satisfiable\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
|
|
|
|
req->version.major, req->version.minor,
|
|
|
|
(int)qse_mbslen(msg) + 4, msg
|
|
|
|
);
|
|
|
|
if (x == QSE_NULL) goto oops;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x = qse_httpd_entaskpath (
|
|
|
|
httpd, client, QSE_NULL,
|
|
|
|
qse_htre_getqpathptr(req),
|
|
|
|
(rangestr? &range: QSE_NULL),
|
|
|
|
qse_htre_getversion(req)
|
|
|
|
);
|
|
|
|
if (x == QSE_NULL) goto oops;
|
|
|
|
}
|
2011-07-20 10:18:54 +00:00
|
|
|
}
|
|
|
|
}
|
2011-07-22 09:50:38 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
const qse_mchar_t* msg = QSE_MT("<html><head><title>Method not allowed</title></head><body><b>REQUEST METHOD NOT ALLOWED</b></body></html>");
|
2011-07-30 02:14:04 +00:00
|
|
|
x = qse_httpd_entaskformat (
|
|
|
|
httpd, client, QSE_NULL,
|
2011-07-22 09:50:38 +00:00
|
|
|
QSE_MT("HTTP/%d.%d 405 Method not allowed\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
|
|
|
|
req->version.major, req->version.minor,
|
2011-07-30 02:14:04 +00:00
|
|
|
(int)qse_mbslen(msg) + 4, msg
|
|
|
|
);
|
|
|
|
if (x == QSE_NULL) goto oops;
|
2011-07-22 09:50:38 +00:00
|
|
|
}
|
2011-07-20 10:18:54 +00:00
|
|
|
|
2011-08-02 09:43:48 +00:00
|
|
|
done:
|
2011-07-20 10:18:54 +00:00
|
|
|
if (req->attr.connection_close)
|
|
|
|
{
|
2011-07-30 02:14:04 +00:00
|
|
|
x = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
|
|
|
if (x == QSE_NULL) goto oops;
|
2011-07-20 10:18:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2011-07-22 09:50:38 +00:00
|
|
|
|
|
|
|
oops:
|
2011-07-30 02:14:04 +00:00
|
|
|
/*qse_httpd_markclientbad (httpd, client);*/
|
2011-07-22 09:50:38 +00:00
|
|
|
return 0;
|
2011-07-15 10:00:37 +00:00
|
|
|
}
|
2011-02-11 07:48:51 +00:00
|
|
|
|
2011-07-15 10:00:37 +00:00
|
|
|
static int handle_expect_continue (
|
|
|
|
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
|
|
|
|
{
|
|
|
|
httpd_xtn_t* xtn = (httpd_xtn_t*) qse_httpd_getxtn (httpd);
|
|
|
|
return xtn->orgcbs->handle_expect_continue (httpd, client, req);
|
|
|
|
}
|
|
|
|
|
2011-12-23 15:28:00 +00:00
|
|
|
const qse_mchar_t* get_mime_type (qse_httpd_t* httpd, const qse_mchar_t* path)
|
|
|
|
{
|
|
|
|
if (qse_mbsend (path, QSE_MT(".html"))) return QSE_MT("text/html");
|
|
|
|
if (qse_mbsend (path, QSE_MT(".txt"))) return QSE_MT("text/plain");
|
|
|
|
if (qse_mbsend (path, QSE_MT(".jpg"))) return QSE_MT("image/jpeg");
|
|
|
|
if (qse_mbsend (path, QSE_MT(".mp4"))) return QSE_MT("video/mp4");
|
|
|
|
return QSE_NULL;
|
|
|
|
}
|
|
|
|
|
2011-07-15 10:00:37 +00:00
|
|
|
static qse_httpd_t* httpd = NULL;
|
2011-02-11 07:48:51 +00:00
|
|
|
|
2011-07-12 10:31:33 +00:00
|
|
|
static void sigint (int sig)
|
2011-07-06 09:45:00 +00:00
|
|
|
{
|
2011-07-12 10:31:33 +00:00
|
|
|
qse_httpd_stop (httpd);
|
2011-06-23 10:17:35 +00:00
|
|
|
}
|
|
|
|
|
2011-07-15 10:00:37 +00:00
|
|
|
static qse_httpd_cbs_t httpd_cbs =
|
|
|
|
{
|
2011-12-23 15:28:00 +00:00
|
|
|
{ get_mime_type, QSE_NULL, },
|
2011-07-15 10:00:37 +00:00
|
|
|
handle_request,
|
|
|
|
handle_expect_continue
|
|
|
|
};
|
|
|
|
|
2011-07-12 10:31:33 +00:00
|
|
|
int httpd_main (int argc, qse_char_t* argv[])
|
2011-06-23 10:17:35 +00:00
|
|
|
{
|
2011-07-12 10:31:33 +00:00
|
|
|
int n;
|
|
|
|
httpd_xtn_t* xtn;
|
2011-06-23 10:17:35 +00:00
|
|
|
|
2011-07-12 10:31:33 +00:00
|
|
|
if (argc != 2)
|
2011-06-22 09:58:50 +00:00
|
|
|
{
|
2011-07-12 10:31:33 +00:00
|
|
|
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s <listener_uri>\n"), argv[0]);
|
2011-06-23 10:17:35 +00:00
|
|
|
return -1;
|
2011-06-22 09:58:50 +00:00
|
|
|
}
|
2011-06-23 10:17:35 +00:00
|
|
|
|
2011-02-11 07:48:51 +00:00
|
|
|
|
2011-12-28 14:26:02 +00:00
|
|
|
httpd = qse_httpd_open (QSE_MMGR_GETDFL(), QSE_SIZEOF(httpd_xtn_t));
|
2011-07-12 10:31:33 +00:00
|
|
|
if (httpd == QSE_NULL)
|
2011-02-11 07:48:51 +00:00
|
|
|
{
|
2011-07-12 10:31:33 +00:00
|
|
|
qse_fprintf (QSE_STDERR, QSE_T("Cannot open httpd\n"));
|
2011-02-11 07:48:51 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-07-12 10:31:33 +00:00
|
|
|
xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd);
|
2011-07-15 10:00:37 +00:00
|
|
|
xtn->orgcbs = qse_httpd_getcbs (httpd);
|
|
|
|
|
2011-07-12 10:31:33 +00:00
|
|
|
if (qse_httpd_addlisteners (httpd, argv[1]) <= -1)
|
2011-02-11 07:48:51 +00:00
|
|
|
{
|
2011-07-12 10:31:33 +00:00
|
|
|
qse_fprintf (QSE_STDERR, QSE_T("Failed to add httpd listeners\n"));
|
|
|
|
qse_httpd_close (httpd);
|
2011-02-11 07:48:51 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-07-15 10:00:37 +00:00
|
|
|
qse_httpd_setcbs (httpd, &httpd_cbs);
|
|
|
|
|
2011-07-12 10:31:33 +00:00
|
|
|
signal (SIGINT, sigint);
|
|
|
|
signal (SIGPIPE, SIG_IGN);
|
2011-06-22 09:58:50 +00:00
|
|
|
|
2011-07-28 21:57:39 +00:00
|
|
|
n = qse_httpd_loop (httpd, 0);
|
2011-06-23 10:17:35 +00:00
|
|
|
|
2011-07-12 10:31:33 +00:00
|
|
|
signal (SIGINT, SIG_DFL);
|
|
|
|
signal (SIGPIPE, SIG_DFL);
|
2011-06-22 09:58:50 +00:00
|
|
|
|
2011-07-12 10:31:33 +00:00
|
|
|
qse_httpd_close (httpd);
|
|
|
|
return n;
|
2011-06-22 09:58:50 +00:00
|
|
|
}
|
|
|
|
|
2011-07-12 10:31:33 +00:00
|
|
|
int qse_main (int argc, qse_achar_t* argv[])
|
2011-06-22 09:58:50 +00:00
|
|
|
{
|
2011-07-12 10:31:33 +00:00
|
|
|
return qse_runmain (argc, argv, httpd_main);
|
2011-06-22 09:58:50 +00:00
|
|
|
}
|
|
|
|
|