enabled the http file handler to accept POST, PUT, DELETE

This commit is contained in:
hyung-hwan 2022-10-10 01:41:07 +09:00
parent 7ec3ba3ab7
commit 855e0fb88e
14 changed files with 294 additions and 217 deletions

View File

@ -19,7 +19,7 @@ rpm: dist-gzip
cp @PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz "@abs_builddir@/pkgs/RPM/SOURCES" cp @PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz "@abs_builddir@/pkgs/RPM/SOURCES"
rpmbuild --define "_topdir @abs_builddir@/pkgs/RPM" -ba @abs_builddir@/pkgs/hio.spec --target=@build_cpu@ rpmbuild --define "_topdir @abs_builddir@/pkgs/RPM" -ba @abs_builddir@/pkgs/hio.spec --target=@build_cpu@
docker: docker: all
mkdir -p data mkdir -p data
rm -rf data/* rm -rf data/*
tar -cvf hio-webs.tar bin/hio-webs data tar -cvf hio-webs.tar bin/hio-webs data

View File

@ -165,7 +165,7 @@ am__DIST_COMMON = $(srcdir)/Dockerfile.in $(srcdir)/Makefile.in \
$(top_srcdir)/ac/config.guess $(top_srcdir)/ac/config.sub \ $(top_srcdir)/ac/config.guess $(top_srcdir)/ac/config.sub \
$(top_srcdir)/ac/install-sh $(top_srcdir)/ac/ltmain.sh \ $(top_srcdir)/ac/install-sh $(top_srcdir)/ac/ltmain.sh \
$(top_srcdir)/ac/missing $(top_srcdir)/pkgs/hio.spec.in \ $(top_srcdir)/ac/missing $(top_srcdir)/pkgs/hio.spec.in \
ac/ar-lib ac/compile ac/config.guess ac/config.sub \ ac/ar-lib ac/compile ac/config.guess ac/config.sub ac/depcomp \
ac/install-sh ac/ltmain.sh ac/missing ac/install-sh ac/ltmain.sh ac/missing
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION) distdir = $(PACKAGE)-$(VERSION)
@ -846,7 +846,7 @@ rpm: dist-gzip
cp @PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz "@abs_builddir@/pkgs/RPM/SOURCES" cp @PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz "@abs_builddir@/pkgs/RPM/SOURCES"
rpmbuild --define "_topdir @abs_builddir@/pkgs/RPM" -ba @abs_builddir@/pkgs/hio.spec --target=@build_cpu@ rpmbuild --define "_topdir @abs_builddir@/pkgs/RPM" -ba @abs_builddir@/pkgs/hio.spec --target=@build_cpu@
docker: docker: all
mkdir -p data mkdir -p data
rm -rf data/* rm -rf data/*
tar -cvf hio-webs.tar bin/hio-webs data tar -cvf hio-webs.tar bin/hio-webs data

View File

@ -961,7 +961,7 @@ if (hio_htre_getcontentlen(req) > 0)
hio_htre_discardcontent (req); hio_htre_discardcontent (req);
/* 411 Length Required - can't keep alive. Force disconnect */ /* 411 Length Required - can't keep alive. Force disconnect */
req->flags &= ~HIO_HTRE_ATTR_KEEPALIVE; /* to cause sendstatus() to close */ req->flags &= ~HIO_HTRE_ATTR_KEEPALIVE; /* to cause sendstatus() to close */
if (hio_svc_htts_sendstatus(htts, csck, req, 411, HIO_NULL) <= -1) goto oops; if (hio_svc_htts_sendstatus(htts, csck, req, HIO_HTTP_STATUS_LENGTH_REQUIRED, HIO_NULL) <= -1) goto oops;
} }
else else
@ -970,13 +970,13 @@ if (hio_htre_getcontentlen(req) > 0)
const hio_bch_t* qpath = hio_htre_getqpath(req); const hio_bch_t* qpath = hio_htre_getqpath(req);
int x; int x;
if (hio_comp_bcstr_limited(qpath, "/thr/", 5, 1) == 0) if (hio_comp_bcstr_limited(qpath, "/thr/", 5, 1) == 0)
x = hio_svc_htts_dothr(htts, csck, req, on_htts_thr_request, HIO_NULL); x = hio_svc_htts_dothr(htts, csck, req, on_htts_thr_request, HIO_NULL, 0);
else if (hio_comp_bcstr_limited(qpath, "/txt/", 5, 1) == 0) else if (hio_comp_bcstr_limited(qpath, "/txt/", 5, 1) == 0)
x = hio_svc_htts_dotxt(htts, csck, req, 200, "text/plain", qpath); x = hio_svc_htts_dotxt(htts, csck, req, HIO_HTTP_STATUS_OK, "text/plain", qpath, 0);
else if (hio_comp_bcstr_limited(qpath, "/cgi/", 5, 1) == 0) else if (hio_comp_bcstr_limited(qpath, "/cgi/", 5, 1) == 0)
x = hio_svc_htts_docgi(htts, csck, req, "", qpath + 4); x = hio_svc_htts_docgi(htts, csck, req, "", qpath + 4, 0);
else else
x = hio_svc_htts_dofile(htts, csck, req, "", qpath, "text/plain"); x = hio_svc_htts_dofile(htts, csck, req, "", qpath, "text/plain", 0);
if (x <= -1) goto oops; if (x <= -1) goto oops;
} }
#if 0 #if 0

View File

@ -45,7 +45,7 @@ static void on_htts_thr_request (hio_t* hio, hio_dev_thr_iopair_t* iop, hio_svc_
return; return;
} }
fprintf (fp, "Status: 200\r\n"); fprintf (fp, "Status: %d\r\n", HIO_HTTP_STATUS_OK);
fprintf (fp, "Content-Type: text/html\r\n\r\n"); fprintf (fp, "Content-Type: text/html\r\n\r\n");
fprintf (fp, "request path = %s\n", tfi->req_path); fprintf (fp, "request path = %s\n", tfi->req_path);
@ -82,13 +82,13 @@ static void on_htts_thr2_request (hio_t* hio, hio_dev_thr_iopair_t* iop, hio_svc
sf = fopen(&tfi->req_path[5], "r"); sf = fopen(&tfi->req_path[5], "r");
if (!sf) if (!sf)
{ {
fprintf (fp, "Status: 404\r\n\r\n"); fprintf (fp, "Status: %d\r\n\r\n", HIO_HTTP_STATUS_NOT_FOUND);
} }
else else
{ {
char buf[4096]; char buf[4096];
fprintf (fp, "Status: 200\r\n"); fprintf (fp, "Status: %d\r\n", HIO_HTTP_STATUS_OK);
fprintf (fp, "Content-Type: text/html\r\n\r\n"); fprintf (fp, "Content-Type: text/html\r\n\r\n");
while (!feof(sf) && !ferror(sf)) while (!feof(sf) && !ferror(sf))
@ -188,7 +188,7 @@ if (hio_htre_getcontentlen(req) > 0)
hio_htre_discardcontent (req); hio_htre_discardcontent (req);
/* 411 Length Required - can't keep alive. Force disconnect */ /* 411 Length Required - can't keep alive. Force disconnect */
req->flags &= ~HIO_HTRE_ATTR_KEEPALIVE; /* to cause sendstatus() to close */ req->flags &= ~HIO_HTRE_ATTR_KEEPALIVE; /* to cause sendstatus() to close */
if (hio_svc_htts_sendstatus(htts, csck, req, 411, HIO_NULL) <= -1) goto oops; if (hio_svc_htts_sendstatus(htts, csck, req, HIO_HTTP_STATUS_LENGTH_REQUIRED, HIO_NULL) <= -1) goto oops;
} }
else else
@ -197,21 +197,21 @@ if (hio_htre_getcontentlen(req) > 0)
const hio_bch_t* qpath = hio_htre_getqpath(req); const hio_bch_t* qpath = hio_htre_getqpath(req);
int x; int x;
if (hio_comp_bcstr_limited(qpath, "/thr/", 5, 1) == 0) if (hio_comp_bcstr_limited(qpath, "/thr/", 5, 1) == 0)
x = hio_svc_htts_dothr(htts, csck, req, on_htts_thr_request, HIO_NULL); x = hio_svc_htts_dothr(htts, csck, req, on_htts_thr_request, HIO_NULL, HIO_SVC_HTTS_THR_NO_100_CONTINUE);
else if (hio_comp_bcstr_limited(qpath, "/thr2/", 6, 1) == 0) else if (hio_comp_bcstr_limited(qpath, "/thr2/", 6, 1) == 0)
x = hio_svc_htts_dothr(htts, csck, req, on_htts_thr2_request, HIO_NULL); x = hio_svc_htts_dothr(htts, csck, req, on_htts_thr2_request, HIO_NULL, HIO_SVC_HTTS_THR_NO_100_CONTINUE);
else if (hio_comp_bcstr_limited(qpath, "/txt/", 5, 1) == 0) else if (hio_comp_bcstr_limited(qpath, "/txt/", 5, 1) == 0)
x = hio_svc_htts_dotxt(htts, csck, req, 200, "text/plain", qpath); x = hio_svc_htts_dotxt(htts, csck, req, HIO_HTTP_STATUS_OK, "text/plain", qpath, 0);
else if (hio_comp_bcstr_limited(qpath, "/cgi/", 5, 1) == 0) else if (hio_comp_bcstr_limited(qpath, "/cgi/", 5, 1) == 0)
x = hio_svc_htts_docgi(htts, csck, req, "", qpath + 4); x = hio_svc_htts_docgi(htts, csck, req, "", qpath + 4, 0);
else if (hio_comp_bcstr_limited(qpath, "/fcgi/", 5, 1) == 0) else if (hio_comp_bcstr_limited(qpath, "/fcgi/", 5, 1) == 0)
{ {
hio_skad_t fcgis_addr; hio_skad_t fcgis_addr;
hio_bcstrtoskad(hio, "127.0.0.1:9000", &fcgis_addr); hio_bcstrtoskad(hio, "127.0.0.1:9000", &fcgis_addr);
x = hio_svc_htts_dofcgi(htts, csck, req, &fcgis_addr); x = hio_svc_htts_dofcgi(htts, csck, req, &fcgis_addr, 0);
} }
else else
x = hio_svc_htts_dofile(htts, csck, req, "", qpath, "text/plain"); x = hio_svc_htts_dofile(htts, csck, req, "", qpath, "text/plain", 0);
if (x <= -1) goto oops; if (x <= -1) goto oops;
} }
#if 0 #if 0

View File

@ -21,21 +21,22 @@ static int process_http_request (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_
mth = hio_htre_getqmethodtype(req); mth = hio_htre_getqmethodtype(req);
qpath = hio_htre_getqpath(req); qpath = hio_htre_getqpath(req);
if (mth == HIO_HTTP_GET || mth == HIO_HTTP_POST)
// if (mth == HIO_HTTP_GET || mth == HIO_HTTP_POST)
{ {
/* TODO: proper mime-type */ /* TODO: proper mime-type */
const hio_bch_t* dot; const hio_bch_t* dot;
hio_bch_t mt[128]; hio_bch_t mt[128];
dot = hio_rfind_bchar_in_bcstr(qpath, '.'); dot = hio_rfind_bchar_in_bcstr(qpath, '.');
hio_fmttobcstr (hio, mt, HIO_COUNTOF(mt), "text/%hs", ((dot && dot[1] != '\0')? &dot[1]: "plain")); /* TODO: error check */ hio_fmttobcstr (hio, mt, HIO_COUNTOF(mt), "text/%hs", ((dot && dot[1] != '\0')? &dot[1]: "plain")); /* TODO: error check */
if (hio_svc_htts_dofile(htts, csck, req, ext->docroot, qpath, mt) <= -1) goto oops; if (hio_svc_htts_dofile(htts, csck, req, ext->docroot, qpath, mt, 0) <= -1) goto oops;
} }
#if 0
else else
{ {
if (hio_svc_htts_dotxt(htts, csck, req, 403, "text/plain", hio_http_status_to_bcstr(403)) <= -1) goto oops; if (hio_svc_htts_dotxt(htts, csck, req, HIO_HTTP_STATUS_FORBIDDEN, "text/plain", hio_http_status_to_bcstr(403), 0) <= -1) goto oops;
} }
#endif
return 0; return 0;
oops: oops:

View File

@ -92,9 +92,37 @@ enum hio_http_method_t
HIO_HTTP_UNSUBSCRIBE, HIO_HTTP_UNSUBSCRIBE,
#endif #endif
}; };
typedef enum hio_http_method_t hio_http_method_t; typedef enum hio_http_method_t hio_http_method_t;
enum hio_http_status_t
{
HIO_HTTP_STATUS_CONTINUE = 100,
HIO_HTTP_STATUS_SWITCH_PROTOCOL = 101,
HIO_HTTP_STATUS_OK = 200,
HIO_HTTP_STATUS_CREATED = 201,
HIO_HTTP_STATUS_ACCEPTED = 202,
HIO_HTTP_STATUS_NON_AUTHORITATIVE = 203,
HIO_HTTP_STATUS_NO_CONTENT = 204,
HIO_HTTP_STATUS_RESET_CONTENT = 205,
HIO_HTTP_STATUS_PARTIAL_CONTENT = 206,
HIO_HTTP_STATUS_MOVED_PERMANENTLY = 301,
HIO_HTTP_STATUS_NOT_MODIFIED = 304,
HIO_HTTP_STATUS_BAD_REQUEST = 400,
HIO_HTTP_STATUS_FORBIDDEN = 403,
HIO_HTTP_STATUS_NOT_FOUND = 404,
HIO_HTTP_STATUS_METHOD_NOT_ALLOWED = 405,
HIO_HTTP_STATUS_LENGTH_REQUIRED = 411,
HIO_HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416,
HIO_HTTP_STATUS_EXPECTATION_FAILED = 417,
HIO_HTTP_STATUS_INTERNAL_SERVER_ERROR = 500,
};
typedef enum hio_http_status_t hio_http_status_t;
/* /*
* You should not manipulate an object of the #hio_htre_t * You should not manipulate an object of the #hio_htre_t
* type directly since it's complex. Use #hio_htrd_t to * type directly since it's complex. Use #hio_htrd_t to

View File

@ -137,6 +137,30 @@ typedef void (*hio_svc_htts_thr_func_t) (
/* -------------------------------------------------------------- */ /* -------------------------------------------------------------- */
enum hio_svc_htts_cgi_option_t
{
HIO_SVC_HTTS_CGI_NO_100_CONTINUE = (1 << 0)
};
enum hio_svc_htts_file_option_t
{
HIO_SVC_HTTS_FILE_NO_100_CONTINUE = (1 << 0),
HIO_SVC_HTTS_FILE_READ_ONLY = (1 << 1)
};
enum hio_svc_htts_thr_option_t
{
HIO_SVC_HTTS_THR_NO_100_CONTINUE = (1 << 0)
};
#if 0
enum hio_svc_htts_txt_option_t
{
/* no option yet */
};
#endif
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { extern "C" {
#endif #endif
@ -307,14 +331,16 @@ HIO_EXPORT int hio_svc_htts_docgi (
hio_dev_sck_t* csck, hio_dev_sck_t* csck,
hio_htre_t* req, hio_htre_t* req,
const hio_bch_t* docroot, const hio_bch_t* docroot,
const hio_bch_t* script const hio_bch_t* script,
int options
); );
HIO_EXPORT int hio_svc_htts_dofcgi ( HIO_EXPORT int hio_svc_htts_dofcgi (
hio_svc_htts_t* htts, hio_svc_htts_t* htts,
hio_dev_sck_t* csck, hio_dev_sck_t* csck,
hio_htre_t* req, hio_htre_t* req,
const hio_skad_t* fcgis_addr const hio_skad_t* fcgis_addr,
int options
); );
HIO_EXPORT int hio_svc_htts_dofile ( HIO_EXPORT int hio_svc_htts_dofile (
@ -323,7 +349,8 @@ HIO_EXPORT int hio_svc_htts_dofile (
hio_htre_t* req, hio_htre_t* req,
const hio_bch_t* docroot, const hio_bch_t* docroot,
const hio_bch_t* filepath, const hio_bch_t* filepath,
const hio_bch_t* mime_type const hio_bch_t* mime_type,
int options
); );
HIO_EXPORT int hio_svc_htts_dothr ( HIO_EXPORT int hio_svc_htts_dothr (
@ -331,7 +358,8 @@ HIO_EXPORT int hio_svc_htts_dothr (
hio_dev_sck_t* csck, hio_dev_sck_t* csck,
hio_htre_t* req, hio_htre_t* req,
hio_svc_htts_thr_func_t func, hio_svc_htts_thr_func_t func,
void* ctx void* ctx,
int options
); );
HIO_EXPORT int hio_svc_htts_dotxt ( HIO_EXPORT int hio_svc_htts_dotxt (
@ -340,7 +368,8 @@ HIO_EXPORT int hio_svc_htts_dotxt (
hio_htre_t* req, hio_htre_t* req,
int status_code, int status_code,
const hio_bch_t* content_type, const hio_bch_t* content_type,
const hio_bch_t* content_text const hio_bch_t* content_text,
int options
); );
HIO_EXPORT hio_svc_htts_rsrc_t* hio_svc_htts_rsrc_make ( HIO_EXPORT hio_svc_htts_rsrc_t* hio_svc_htts_rsrc_make (

View File

@ -58,6 +58,7 @@ struct cgi_t
{ {
HIO_SVC_HTTS_RSRC_HEADER; HIO_SVC_HTTS_RSRC_HEADER;
int options;
hio_oow_t num_pending_writes_to_client; hio_oow_t num_pending_writes_to_client;
hio_oow_t num_pending_writes_to_peer; hio_oow_t num_pending_writes_to_peer;
hio_dev_pro_t* peer; hio_dev_pro_t* peer;
@ -69,6 +70,7 @@ struct cgi_t
unsigned int keep_alive: 1; unsigned int keep_alive: 1;
unsigned int req_content_length_unlimited: 1; unsigned int req_content_length_unlimited: 1;
unsigned int ever_attempted_to_write_to_client: 1; unsigned int ever_attempted_to_write_to_client: 1;
unsigned int client_eof_detected: 1;
unsigned int client_disconnected: 1; unsigned int client_disconnected: 1;
unsigned int client_htrd_recbs_changed: 1; unsigned int client_htrd_recbs_changed: 1;
hio_oow_t req_content_length; /* client request content length */ hio_oow_t req_content_length; /* client request content length */
@ -160,7 +162,7 @@ static int cgi_write_last_chunk_to_client (cgi_t* cgi)
{ {
if (!cgi->ever_attempted_to_write_to_client) if (!cgi->ever_attempted_to_write_to_client)
{ {
if (cgi_send_final_status_to_client(cgi, 500, 0) <= -1) return -1; if (cgi_send_final_status_to_client(cgi, HIO_HTTP_STATUS_INTERNAL_SERVER_ERROR, 0) <= -1) return -1;
} }
else else
{ {
@ -226,7 +228,7 @@ static HIO_INLINE void cgi_mark_over (cgi_t* cgi, int over_bits)
hio_dev_pro_halt (cgi->peer); hio_dev_pro_halt (cgi->peer);
} }
if (cgi->keep_alive) if (cgi->keep_alive && !cgi->client_eof_detected)
{ {
/* how to arrange to delete this cgi object and put the socket back to the normal waiting state??? */ /* how to arrange to delete this cgi object and put the socket back to the normal waiting state??? */
HIO_ASSERT (cgi->htts->hio, cgi->client->rsrc == (hio_svc_htts_rsrc_t*)cgi); HIO_ASSERT (cgi->htts->hio, cgi->client->rsrc == (hio_svc_htts_rsrc_t*)cgi);
@ -379,6 +381,7 @@ static int peer_on_read (hio_dev_pro_t* pro, hio_dev_pro_sid_t sid, const void*
if (dlen == 0) if (dlen == 0)
{ {
HIO_DEBUG3 (hio, "HTTS(%p) - EOF from peer %p(pid=%u)\n", cgi->client->htts, pro, (unsigned int)pro->child_pid); HIO_DEBUG3 (hio, "HTTS(%p) - EOF from peer %p(pid=%u)\n", cgi->client->htts, pro, (unsigned int)pro->child_pid);
cgi->client_eof_detected = 1;
if (!(cgi->over & CGI_OVER_READ_FROM_PEER)) if (!(cgi->over & CGI_OVER_READ_FROM_PEER))
{ {
@ -404,7 +407,7 @@ static int peer_on_read (hio_dev_pro_t* pro, hio_dev_pro_sid_t sid, const void*
if (!cgi->ever_attempted_to_write_to_client && if (!cgi->ever_attempted_to_write_to_client &&
!(cgi->over & CGI_OVER_WRITE_TO_CLIENT)) !(cgi->over & CGI_OVER_WRITE_TO_CLIENT))
{ {
cgi_send_final_status_to_client (cgi, 500, 1); /* don't care about error because it jumps to oops below anyway */ cgi_send_final_status_to_client (cgi, HIO_HTTP_STATUS_INTERNAL_SERVER_ERROR, 1); /* don't care about error because it jumps to oops below anyway */
} }
goto oops; goto oops;
@ -921,7 +924,7 @@ static int peer_on_fork (hio_dev_pro_t* pro, void* fork_ctx)
return 0; return 0;
} }
int hio_svc_htts_docgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, const hio_bch_t* docroot, const hio_bch_t* script) int hio_svc_htts_docgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, const hio_bch_t* docroot, const hio_bch_t* script, int options)
{ {
hio_t* hio = htts->hio; hio_t* hio = htts->hio;
hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck); hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck);
@ -953,6 +956,7 @@ int hio_svc_htts_docgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
cgi = (cgi_t*)hio_svc_htts_rsrc_make(htts, HIO_SIZEOF(*cgi), cgi_on_kill); cgi = (cgi_t*)hio_svc_htts_rsrc_make(htts, HIO_SIZEOF(*cgi), cgi_on_kill);
if (HIO_UNLIKELY(!cgi)) goto oops; if (HIO_UNLIKELY(!cgi)) goto oops;
cgi->options = options;
cgi->client = cli; cgi->client = cli;
/*cgi->num_pending_writes_to_client = 0; /*cgi->num_pending_writes_to_client = 0;
cgi->num_pending_writes_to_peer = 0;*/ cgi->num_pending_writes_to_peer = 0;*/
@ -973,7 +977,7 @@ int hio_svc_htts_docgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
if (access(mi.cmd, X_OK) == -1) if (access(mi.cmd, X_OK) == -1)
{ {
cgi_send_final_status_to_client (cgi, 403, 1); /* 403 Forbidden */ cgi_send_final_status_to_client (cgi, HIO_HTTP_STATUS_FORBIDDEN, 1); /* 403 Forbidden */
goto oops; /* TODO: must not go to oops. just destroy the cgi and finalize the request .. */ goto oops; /* TODO: must not go to oops. just destroy the cgi and finalize the request .. */
} }
@ -999,7 +1003,7 @@ int hio_svc_htts_docgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
* option 2. send 411 Length Required immediately * option 2. send 411 Length Required immediately
* option 3. set Content-Length to -1 and use EOF to indicate the end of content [Non-Standard] */ * option 3. set Content-Length to -1 and use EOF to indicate the end of content [Non-Standard] */
if (cgi_send_final_status_to_client(cgi, 411, 1) <= -1) goto oops; if (cgi_send_final_status_to_client(cgi, HIO_HTTP_STATUS_LENGTH_REQUIRED, 1) <= -1) goto oops;
} }
#endif #endif
@ -1007,7 +1011,8 @@ int hio_svc_htts_docgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
{ {
/* TODO: Expect: 100-continue? who should handle this? cgi? or the http server? */ /* TODO: Expect: 100-continue? who should handle this? cgi? or the http server? */
/* CAN I LET the cgi SCRIPT handle this? */ /* CAN I LET the cgi SCRIPT handle this? */
if (hio_comp_http_version_numbers(&req->version, 1, 1) >= 0 && if (!(options & HIO_SVC_HTTS_CGI_NO_100_CONTINUE) &&
hio_comp_http_version_numbers(&req->version, 1, 1) >= 0 &&
(cgi->req_content_length_unlimited || cgi->req_content_length > 0)) (cgi->req_content_length_unlimited || cgi->req_content_length > 0))
{ {
/* /*
@ -1026,7 +1031,7 @@ int hio_svc_htts_docgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
hio_bch_t msgbuf[64]; hio_bch_t msgbuf[64];
hio_oow_t msglen; hio_oow_t msglen;
msglen = hio_fmttobcstr(hio, msgbuf, HIO_COUNTOF(msgbuf), "HTTP/%d.%d 100 Continue\r\n\r\n", cgi->req_version.major, cgi->req_version.minor); msglen = hio_fmttobcstr(hio, msgbuf, HIO_COUNTOF(msgbuf), "HTTP/%d.%d %d %hs\r\n\r\n", cgi->req_version.major, cgi->req_version.minor, HIO_HTTP_STATUS_CONTINUE, hio_http_status_to_bcstr(HIO_HTTP_STATUS_CONTINUE));
if (cgi_write_to_client(cgi, msgbuf, msglen) <= -1) goto oops; if (cgi_write_to_client(cgi, msgbuf, msglen) <= -1) goto oops;
cgi->ever_attempted_to_write_to_client = 0; /* reset this as it's polluted for 100 continue */ cgi->ever_attempted_to_write_to_client = 0; /* reset this as it's polluted for 100 continue */
} }
@ -1034,7 +1039,7 @@ int hio_svc_htts_docgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
else if (req->flags & HIO_HTRE_ATTR_EXPECT) else if (req->flags & HIO_HTRE_ATTR_EXPECT)
{ {
/* 417 Expectation Failed */ /* 417 Expectation Failed */
cgi_send_final_status_to_client(cgi, 417, 1); cgi_send_final_status_to_client(cgi, HIO_HTTP_STATUS_EXPECTATION_FAILED, 1);
goto oops; goto oops;
} }

View File

@ -497,7 +497,7 @@ static void fcgi_on_kill (fcgi_t* fcgi)
#endif #endif
} }
int hio_svc_htts_dofcgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, const hio_skad_t* fcgis_addr) int hio_svc_htts_dofcgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, const hio_skad_t* fcgis_addr, int options)
{ {
hio_t* hio = htts->hio; hio_t* hio = htts->hio;
hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck); hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck);
@ -565,7 +565,7 @@ int hio_svc_htts_dofcgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t*
* option 2. send 411 Length Required immediately * option 2. send 411 Length Required immediately
* option 3. set Content-Length to -1 and use EOF to indicate the end of content [Non-Standard] */ * option 3. set Content-Length to -1 and use EOF to indicate the end of content [Non-Standard] */
if (cgi_send_final_status_to_client(cgi, 411, 1) <= -1) goto oops; if (cgi_send_final_status_to_client(cgi, HIO_HTTP_STATUS_LENGTH_REQUIRED, 1) <= -1) goto oops;
} }
#endif #endif
@ -573,7 +573,8 @@ int hio_svc_htts_dofcgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t*
{ {
/* TODO: Expect: 100-continue? who should handle this? cgi? or the http server? */ /* TODO: Expect: 100-continue? who should handle this? cgi? or the http server? */
/* CAN I LET the cgi SCRIPT handle this? */ /* CAN I LET the cgi SCRIPT handle this? */
if (hio_comp_http_version_numbers(&req->version, 1, 1) >= 0 && if (!(options & HIO_SVC_HTTS_CGI_NO_100_CONTINUE) &&
hio_comp_http_version_numbers(&req->version, 1, 1) >= 0 &&
(fcgi->req_content_length_unlimited || fcgi->req_content_length > 0)) (fcgi->req_content_length_unlimited || fcgi->req_content_length > 0))
{ {
/* /*
@ -592,7 +593,7 @@ int hio_svc_htts_dofcgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t*
hio_bch_t msgbuf[64]; hio_bch_t msgbuf[64];
hio_oow_t msglen; hio_oow_t msglen;
msglen = hio_fmttobcstr(hio, msgbuf, HIO_COUNTOF(msgbuf), "HTTP/%d.%d 100 Continue\r\n\r\n", fcgi->req_version.major, fcgi->req_version.minor); msglen = hio_fmttobcstr(hio, msgbuf, HIO_COUNTOF(msgbuf), "HTTP/%d.%d %d %hs\r\n\r\n", fcgi->req_version.major, fcgi->req_version.minor, HIO_HTTP_STATUS_CONTINUE, hio_http_status_to_bcstr(HIO_HTTP_STATUS_CONTINUE));
if (fcgi_write_to_client(fcgi, msgbuf, msglen) <= -1) goto oops; if (fcgi_write_to_client(fcgi, msgbuf, msglen) <= -1) goto oops;
fcgi->ever_attempted_to_write_to_client = 0; /* reset this as it's polluted for 100 continue */ fcgi->ever_attempted_to_write_to_client = 0; /* reset this as it's polluted for 100 continue */
} }
@ -600,7 +601,7 @@ int hio_svc_htts_dofcgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t*
else if (req->flags & HIO_HTRE_ATTR_EXPECT) else if (req->flags & HIO_HTRE_ATTR_EXPECT)
{ {
/* 417 Expectation Failed */ /* 417 Expectation Failed */
fcgi_send_final_status_to_client(fcgi, 417, 1); fcgi_send_final_status_to_client(fcgi, HIO_HTTP_STATUS_EXPECTATION_FAILED, 1);
goto oops; goto oops;
} }

View File

@ -43,8 +43,6 @@ enum file_res_mode_t
}; };
typedef enum file_res_mode_t file_res_mode_t; typedef enum file_res_mode_t file_res_mode_t;
#define FILE_PENDING_IO_THRESHOLD 5
#define FILE_OVER_READ_FROM_CLIENT (1 << 0) #define FILE_OVER_READ_FROM_CLIENT (1 << 0)
#define FILE_OVER_READ_FROM_PEER (1 << 1) #define FILE_OVER_READ_FROM_PEER (1 << 1)
#define FILE_OVER_WRITE_TO_CLIENT (1 << 2) #define FILE_OVER_WRITE_TO_CLIENT (1 << 2)
@ -55,6 +53,7 @@ struct file_t
{ {
HIO_SVC_HTTS_RSRC_HEADER; HIO_SVC_HTTS_RSRC_HEADER;
int options;
hio_oow_t num_pending_writes_to_client; hio_oow_t num_pending_writes_to_client;
hio_oow_t num_pending_writes_to_peer; hio_oow_t num_pending_writes_to_peer;
int sendfile_ok; int sendfile_ok;
@ -98,7 +97,7 @@ static void file_halt_participating_devices (file_t* file)
HIO_ASSERT (file->client->htts->hio, file->client != HIO_NULL); HIO_ASSERT (file->client->htts->hio, file->client != HIO_NULL);
HIO_ASSERT (file->client->htts->hio, file->client->sck != HIO_NULL); HIO_ASSERT (file->client->htts->hio, file->client->sck != HIO_NULL);
HIO_DEBUG3 (file->client->htts->hio, "HTTS(%p) - file(c=%d,p=%d) Halting participating devices in file state\n", file->client->htts, (int)file->client->sck->hnd, (int)file->peer); HIO_DEBUG3 (file->client->htts->hio, "HTTS(%p) - file(c=%d,p=%d) Halting participating devices\n", file->client->htts, (int)file->client->sck->hnd, (int)file->peer);
/* only the client socket device. /* only the client socket device.
* the peer side is just a file descriptor - no hio-managed device */ * the peer side is just a file descriptor - no hio-managed device */
@ -116,11 +115,6 @@ static int file_write_to_client (file_t* file, const void* data, hio_iolen_t dle
return -1; return -1;
} }
if (file->num_pending_writes_to_client > FILE_PENDING_IO_THRESHOLD)
{
/* STOP READING */
/*if (hio_dev_pro_read(file->peer, HIO_DEV_PRO_OUT, 0) <= -1) return -1;*/
}
return 0; return 0;
} }
@ -135,11 +129,6 @@ static int file_sendfile_to_client (file_t* file, hio_foff_t foff, hio_iolen_t l
return -1; return -1;
} }
if (file->num_pending_writes_to_client > FILE_PENDING_IO_THRESHOLD)
{
/* STOP READING */
/*if (hio_dev_pro_read(file->peer, HIO_DEV_PRO_OUT, 0) <= -1) return -1;*/
}
return 0; return 0;
} }
@ -248,10 +237,20 @@ static int file_write_to_peer (file_t* file, const void* data, hio_iolen_t dlen)
} }
else else
{ {
hio_iolen_t pos, rem, n;
if (file->req_method == HIO_HTTP_GET) return 0; if (file->req_method == HIO_HTTP_GET) return 0;
if (file->peer <= -1) return 0; /* peer open proabably failed */
HIO_ASSERT (hio, file->peer >= 0); /* TODO: async file io -> create a file device?? */
return write(file->peer, data, dlen) <= -1? -1: 0; pos = 0;
rem = dlen;
while (rem > 0)
{
n = write(file->peer, &((const hio_uint8_t*)data)[pos], rem);
if (n <= -1) return -1;
rem -= n;
pos += n;
}
} }
return 0; return 0;
@ -334,9 +333,10 @@ static int file_client_on_read (hio_dev_sck_t* sck, const void* buf, hio_iolen_t
goto oops; goto oops;
} }
if (!file->peer) if (file->peer <= -1)
{ {
/* the peer is gone */ /* the peer is gone or not even opened */
HIO_DEBUG3 (cli->htts->hio, "HTTS(%p) - file(c=%d,p=%d) read on client, no peer to write\n", file->client->htts, (int)sck->hnd, file->peer);
goto oops; /* do what? just return 0? */ goto oops; /* do what? just return 0? */
} }
@ -344,12 +344,14 @@ static int file_client_on_read (hio_dev_sck_t* sck, const void* buf, hio_iolen_t
{ {
/* EOF on the client side. arrange to close */ /* EOF on the client side. arrange to close */
HIO_DEBUG3 (cli->htts->hio, "HTTS(%p) - file(c=%d,p=%d) EOF detected on client\n", file->client->htts, (int)sck->hnd, file->peer); HIO_DEBUG3 (cli->htts->hio, "HTTS(%p) - file(c=%d,p=%d) EOF detected on client\n", file->client->htts, (int)sck->hnd, file->peer);
file->client_eof_detected = 1;
if (!(file->over & FILE_OVER_READ_FROM_CLIENT)) /* if this is true, EOF is received without file_client_htrd_poke() */ if (!(file->over & FILE_OVER_READ_FROM_CLIENT)) /* if this is true, EOF is received without file_client_htrd_poke() */
{ {
if (file_write_to_peer(file, HIO_NULL, 0) <= -1) goto oops; int n;
file->client_eof_detected = 1; n = file_write_to_peer(file, HIO_NULL, 0);
file_mark_over (file, FILE_OVER_READ_FROM_CLIENT); file_mark_over (file, FILE_OVER_READ_FROM_CLIENT);
if (n <= -1) goto oops;
} }
} }
else else
@ -422,7 +424,6 @@ oops:
return 0; return 0;
} }
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
static int file_client_htrd_poke (hio_htrd_t* htrd, hio_htre_t* req) static int file_client_htrd_poke (hio_htrd_t* htrd, hio_htre_t* req)
@ -438,7 +439,7 @@ static int file_client_htrd_poke (hio_htrd_t* htrd, hio_htre_t* req)
if (file->req_method != HIO_HTTP_GET) if (file->req_method != HIO_HTTP_GET)
{ {
if (file_send_final_status_to_client(file, 200, 0) <= -1) return -1; if (file_send_final_status_to_client(file, HIO_HTTP_STATUS_OK, 0) <= -1) return -1;
} }
file_mark_over (file, FILE_OVER_READ_FROM_CLIENT); file_mark_over (file, FILE_OVER_READ_FROM_CLIENT);
@ -476,7 +477,7 @@ static int file_send_header_to_client (file_t* file, int status_code, int force_
if (!force_close) force_close = !file->keep_alive; if (!force_close) force_close = !file->keep_alive;
content_length = file->end_offset - file->start_offset + 1; content_length = file->end_offset - file->start_offset + 1;
if (status_code == 200 && file->total_size != content_length) status_code = 206; if (status_code == HIO_HTTP_STATUS_OK && file->total_size != content_length) status_code = HIO_HTTP_STATUS_PARTIAL_CONTENT;
if (hio_becs_fmt(cli->sbuf, "HTTP/%d.%d %d %hs\r\nServer: %hs\r\nDate: %s\r\nConnection: %hs\r\nAccept-Ranges: bytes\r\nContent-Type: %hs\r\n", if (hio_becs_fmt(cli->sbuf, "HTTP/%d.%d %d %hs\r\nServer: %hs\r\nDate: %s\r\nConnection: %hs\r\nAccept-Ranges: bytes\r\nContent-Type: %hs\r\n",
file->req_version.major, file->req_version.minor, file->req_version.major, file->req_version.minor,
@ -485,7 +486,7 @@ static int file_send_header_to_client (file_t* file, int status_code, int force_
(force_close? "close": "keep-alive"), mime_type) == (hio_oow_t)-1) return -1; (force_close? "close": "keep-alive"), mime_type) == (hio_oow_t)-1) return -1;
if (file->req_method == HIO_HTTP_GET && hio_becs_fcat(cli->sbuf, "ETag: %hs\r\n", file->peer_etag) == (hio_oow_t)-1) return -1; if (file->req_method == HIO_HTTP_GET && hio_becs_fcat(cli->sbuf, "ETag: %hs\r\n", file->peer_etag) == (hio_oow_t)-1) return -1;
if (status_code == 206 && hio_becs_fcat(cli->sbuf, "Content-Ranges: bytes %ju-%ju/%ju\r\n", (hio_uintmax_t)file->start_offset, (hio_uintmax_t)file->end_offset, (hio_uintmax_t)file->total_size) == (hio_oow_t)-1) return -1; if (status_code == HIO_HTTP_STATUS_PARTIAL_CONTENT && hio_becs_fcat(cli->sbuf, "Content-Ranges: bytes %ju-%ju/%ju\r\n", (hio_uintmax_t)file->start_offset, (hio_uintmax_t)file->end_offset, (hio_uintmax_t)file->total_size) == (hio_oow_t)-1) return -1;
/* ----- */ /* ----- */
// TODO: Allow-Contents // TODO: Allow-Contents
@ -566,7 +567,12 @@ static int file_send_contents_to_client (file_t* file)
return 0; return 0;
} }
static HIO_INLINE int process_range_header (file_t* file, hio_htre_t* req) #define ERRNO_TO_STATUS_CODE(x) ( \
((x) == ENOENT)? HIO_HTTP_STATUS_NOT_FOUND: \
((x) == EPERM || (x) == EACCES)? HIO_HTTP_STATUS_FORBIDDEN: HIO_HTTP_STATUS_INTERNAL_SERVER_ERROR \
)
static HIO_INLINE int process_range_header (file_t* file, hio_htre_t* req, int* error_status)
{ {
struct stat st; struct stat st;
const hio_htre_hdrval_t* tmp; const hio_htre_hdrval_t* tmp;
@ -574,14 +580,14 @@ static HIO_INLINE int process_range_header (file_t* file, hio_htre_t* req)
if (fstat(file->peer, &st) <= -1) if (fstat(file->peer, &st) <= -1)
{ {
file_send_final_status_to_client (file, 500, 1); *error_status = ERRNO_TO_STATUS_CODE(errno);
return -1; return -1;
} }
if ((st.st_mode & S_IFMT) != S_IFREG) if ((st.st_mode & S_IFMT) != S_IFREG)
{ {
/* TODO: support directory listing if S_IFDIR? still disallow special files. */ /* TODO: support directory listing if S_IFDIR? still disallow special files. */
file_send_final_status_to_client (file, 403, 1); /* forbidden */ *error_status = HIO_HTTP_STATUS_FORBIDDEN;
return -1; return -1;
} }
@ -617,7 +623,7 @@ static HIO_INLINE int process_range_header (file_t* file, hio_htre_t* req)
if (hio_parse_http_range_bcstr(tmp->ptr, &range) <= -1) if (hio_parse_http_range_bcstr(tmp->ptr, &range) <= -1)
{ {
range_not_satisifiable: range_not_satisifiable:
file_send_final_status_to_client (file, 416, 1); /* 406 Requested Range Not Satisfiable */ *error_status = HIO_HTTP_STATUS_RANGE_NOT_SATISFIABLE;
return -1; return -1;
} }
@ -646,7 +652,13 @@ static HIO_INLINE int process_range_header (file_t* file, hio_htre_t* req)
} }
if (file->start_offset > 0) if (file->start_offset > 0)
lseek(file->peer, file->start_offset, SEEK_SET); {
if (lseek(file->peer, file->start_offset, SEEK_SET) <= -1)
{
*error_status = ERRNO_TO_STATUS_CODE(errno);
return -1;
}
}
} }
else else
@ -660,86 +672,39 @@ static HIO_INLINE int process_range_header (file_t* file, hio_htre_t* req)
return 0; return 0;
} }
#define ERRNO_TO_STATUS_CODE(x) ( \ static int open_peer_with_mode (file_t* file, const hio_bch_t* actual_file, int flags, int* error_status)
((x) == ENOENT)? 404: \
((x) == EPERM || (x) == EACCES)? 403: 500 \
)
static int open_peer (file_t* file, const hio_bch_t* actual_file)
{ {
switch (file->req_method) flags |= O_NONBLOCK;
{ #if defined(O_CLOEXEC)
case HIO_HTTP_GET:
case HIO_HTTP_HEAD:
{
int flags;
if (access(actual_file, R_OK) == -1)
{
file_send_final_status_to_client (file, ERRNO_TO_STATUS_CODE(errno), 1); /* 404 not found 403 Forbidden */
return -1;
}
flags = O_RDONLY | O_NONBLOCK;
#if defined(O_CLOEXEC)
flags |= O_CLOEXEC; flags |= O_CLOEXEC;
#endif #endif
#if defined(O_LARGEFILE) #if defined(O_LARGEFILE)
flags |= O_LARGEFILE; flags |= O_LARGEFILE;
#endif
file->peer = open(actual_file, flags);
if (HIO_UNLIKELY(file->peer <= -1))
{
file_send_final_status_to_client (file, ERRNO_TO_STATUS_CODE(errno), 1);
return -1;
}
return 0;
}
#if 0
case HIO_HTTP_PUT:
case HIO_HTTP_POST:
/* TOOD: this is destructive. jump to default if not allowed by flags... */
file->peer = open(actual_file, O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK | O_CLOEXEC, 0644);
if (HIO_UNLIKELY(file->peer <= -1))
{
file_send_final_status_to_client (file, ERRNO_TO_STATUS_CODE(errno), 1);
return -1;
}
return 0;
case HIO_HTTP_PATCH:
/* TOOD: this is destructive. jump to default if not allowed by flags... */
file->peer = open(actual_file, O_WRONLY | O_NONBLOCK | O_CLOEXEC, 0644);
if (HIO_UNLIKELY(file->peer <= -1))
{
file_send_final_status_to_client (file, ERRNO_TO_STATUS_CODE(errno), 1);
return -1;
}
return 0;
#endif #endif
#if 0 file->peer = open(actual_file, flags, 0644);
case HIO_HTTP_DELETE: if (HIO_UNLIKELY(file->peer <= -1))
/* TODO: */ {
#endif *error_status = ERRNO_TO_STATUS_CODE(errno);
return -1;
} }
file_send_final_status_to_client (file, 405, 1); /* 405: method not allowed */ return 0;
return -1;
} }
static HIO_INLINE void fadvise_on_peer (file_t* file) static HIO_INLINE void set_tcp_cork (hio_dev_sck_t* sck)
{ {
#if defined(HAVE_POSIX_FADVISE) #if defined(TCP_CORK)
if (file->req_method == HIO_HTTP_GET) int tcp_cork = 1;
posix_fadvise (file->peer, file->start_offset, file->end_offset - file->start_offset + 1, POSIX_FADV_SEQUENTIAL); #if defined(SOL_TCP)
hio_dev_sck_setsockopt (sck, SOL_TCP, TCP_CORK, &tcp_cork, HIO_SIZEOF(tcp_cork));
#elif defined(IPPROTO_TCP)
hio_dev_sck_setsockopt (sck, IPPROTO_TCP, TCP_CORK, &tcp_cork, HIO_SIZEOF(tcp_cork));
#endif
#endif #endif
} }
int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, const hio_bch_t* docroot, const hio_bch_t* filepath, const hio_bch_t* mime_type) int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, const hio_bch_t* docroot, const hio_bch_t* filepath, const hio_bch_t* mime_type, int options)
{ {
/* TODO: ETag, Last-Modified... */ /* TODO: ETag, Last-Modified... */
@ -747,6 +712,7 @@ int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t*
hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck); hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck);
file_t* file = HIO_NULL; file_t* file = HIO_NULL;
hio_bch_t* actual_file = HIO_NULL; hio_bch_t* actual_file = HIO_NULL;
int status_code;
/* ensure that you call this function before any contents is received */ /* ensure that you call this function before any contents is received */
HIO_ASSERT (hio, hio_htre_getcontentlen(req) == 0); HIO_ASSERT (hio, hio_htre_getcontentlen(req) == 0);
@ -760,6 +726,7 @@ int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t*
file = (file_t*)hio_svc_htts_rsrc_make(htts, HIO_SIZEOF(*file), file_on_kill); file = (file_t*)hio_svc_htts_rsrc_make(htts, HIO_SIZEOF(*file), file_on_kill);
if (HIO_UNLIKELY(!file)) goto oops; if (HIO_UNLIKELY(!file)) goto oops;
file->options = options;
file->client = cli; file->client = cli;
file->sendfile_ok = hio_dev_sck_sendfileok(cli->sck); file->sendfile_ok = hio_dev_sck_sendfileok(cli->sck);
/*file->num_pending_writes_to_client = 0; /*file->num_pending_writes_to_client = 0;
@ -781,11 +748,6 @@ int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t*
file->peer_tmridx = HIO_TMRIDX_INVALID; file->peer_tmridx = HIO_TMRIDX_INVALID;
file->peer = -1; file->peer = -1;
if (open_peer(file, actual_file) <= -1 ||
process_range_header(file, req) <= -1) goto oops;
fadvise_on_peer (file);
#if !defined(FILE_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) #if !defined(FILE_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH)
if (file->req_content_length_unlimited) if (file->req_content_length_unlimited)
{ {
@ -794,21 +756,21 @@ int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t*
/* option 1. buffer contents. if it gets too large, send 413 Request Entity Too Large. /* option 1. buffer contents. if it gets too large, send 413 Request Entity Too Large.
* option 2. send 411 Length Required immediately * option 2. send 411 Length Required immediately
* option 3. set Content-Length to -1 and use EOF to indicate the end of content [Non-Standard] */ * option 3. set Content-Length to -1 and use EOF to indicate the end of content [Non-Standard] */
if (file_send_final_status_to_client(file, HIO_HTTP_STATUS_LENGTH_REQUIRED, 1) <= -1) goto oops;
if (file_send_final_status_to_client(file, 411, 1) <= -1) goto oops;
} }
#endif #endif
if (req->flags & HIO_HTRE_ATTR_EXPECT100) if (req->flags & HIO_HTRE_ATTR_EXPECT100)
{ {
if (hio_comp_http_version_numbers(&req->version, 1, 1) >= 0 && if (!(options & HIO_SVC_HTTS_FILE_NO_100_CONTINUE) &&
hio_comp_http_version_numbers(&req->version, 1, 1) >= 0 &&
(file->req_content_length_unlimited || file->req_content_length > 0) && (file->req_content_length_unlimited || file->req_content_length > 0) &&
(file->req_method != HIO_HTTP_GET && file->req_method != HIO_HTTP_HEAD)) (file->req_method != HIO_HTTP_GET && file->req_method != HIO_HTTP_HEAD))
{ {
hio_bch_t msgbuf[64]; hio_bch_t msgbuf[64];
hio_oow_t msglen; hio_oow_t msglen;
msglen = hio_fmttobcstr(hio, msgbuf, HIO_COUNTOF(msgbuf), "HTTP/%d.%d 100 Continue\r\n\r\n", file->req_version.major, file->req_version.minor); msglen = hio_fmttobcstr(hio, msgbuf, HIO_COUNTOF(msgbuf), "HTTP/%d.%d %d %hs\r\n\r\n", file->req_version.major, file->req_version.minor, HIO_HTTP_STATUS_CONTINUE, hio_http_status_to_bcstr(HIO_HTTP_STATUS_CONTINUE));
if (file_write_to_client(file, msgbuf, msglen) <= -1) goto oops; if (file_write_to_client(file, msgbuf, msglen) <= -1) goto oops;
file->ever_attempted_to_write_to_client = 0; /* reset this as it's polluted for 100 continue */ file->ever_attempted_to_write_to_client = 0; /* reset this as it's polluted for 100 continue */
} }
@ -816,7 +778,7 @@ int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t*
else if (req->flags & HIO_HTRE_ATTR_EXPECT) else if (req->flags & HIO_HTRE_ATTR_EXPECT)
{ {
/* 417 Expectation Failed */ /* 417 Expectation Failed */
file_send_final_status_to_client (file, 417, 1); file_send_final_status_to_client (file, HIO_HTTP_STATUS_EXPECTATION_FAILED, 1);
goto oops; goto oops;
} }
@ -843,9 +805,15 @@ int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t*
else else
{ {
/* no content to be uploaded from the client */ /* no content to be uploaded from the client */
#if 0
/* indicate EOF to the peer and disable input wathching from the client */ /* indicate EOF to the peer and disable input wathching from the client */
if (file_write_to_peer(file, HIO_NULL, 0) <= -1) goto oops; if (file_write_to_peer(file, HIO_NULL, 0) <= -1) goto oops;
HIO_ASSERT (hio, file->over | FILE_OVER_WRITE_TO_PEER); /* must be set by the call to file_write_to_peer() above */
file_mark_over (file, FILE_OVER_READ_FROM_CLIENT);
#else
/* no peer is open yet. so simply set the mars forcibly instead of calling file_write_to_peer() with null data */
file_mark_over (file, FILE_OVER_READ_FROM_CLIENT | FILE_OVER_WRITE_TO_PEER); file_mark_over (file, FILE_OVER_READ_FROM_CLIENT | FILE_OVER_WRITE_TO_PEER);
#endif
} }
#if defined(FILE_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) #if defined(FILE_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH)
} }
@ -863,34 +831,74 @@ int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t*
file->res_mode_to_cli = FILE_RES_MODE_CLOSE; file->res_mode_to_cli = FILE_RES_MODE_CLOSE;
} }
if (file->req_method == HIO_HTTP_GET) switch (file->req_method)
{ {
case HIO_HTTP_GET:
if (open_peer_with_mode(file, actual_file, O_RDONLY, &status_code) <= -1) goto done_with_status_code;
if (process_range_header(file, req, &status_code) <= -1) goto done_with_status_code;
if (file->etag_match) if (file->etag_match)
{ {
/* 304 not modified */ status_code = HIO_HTTP_STATUS_NOT_MODIFIED;
if (file_send_final_status_to_client(file, 304, 0) <= -1) goto oops; goto done_with_status_code;
file_mark_over (file, FILE_OVER_READ_FROM_PEER | FILE_OVER_WRITE_TO_PEER);
} }
else
{
/* normal full transfer */
#if defined(TCP_CORK)
int tcp_cork = 1;
#if defined(SOL_TCP)
hio_dev_sck_setsockopt(file->client->sck, SOL_TCP, TCP_CORK, &tcp_cork, HIO_SIZEOF(tcp_cork));
#elif defined(IPPROTO_TCP)
hio_dev_sck_setsockopt(file->client->sck, IPPROTO_TCP, TCP_CORK, &tcp_cork, HIO_SIZEOF(tcp_cork));
#endif
#endif
if (file_send_header_to_client(file, 200, 0, mime_type) <= -1 || /* normal full transfer */
#if defined(HAVE_POSIX_FADVISE)
posix_fadvise (file->peer, file->start_offset, file->end_offset - file->start_offset + 1, POSIX_FADV_SEQUENTIAL);
#endif
set_tcp_cork (file->client->sck);
if (file_send_header_to_client(file, HIO_HTTP_STATUS_OK, 0, mime_type) <= -1 ||
file_send_contents_to_client(file) <= -1) goto oops; file_send_contents_to_client(file) <= -1) goto oops;
}
} break;
else if (file->req_method == HIO_HTTP_HEAD)
case HIO_HTTP_HEAD:
if (open_peer_with_mode(file, actual_file, O_RDONLY, &status_code) <= -1) goto done_with_status_code;
if (process_range_header(file, req, &status_code) <= -1) goto done_with_status_code;
status_code = HIO_HTTP_STATUS_OK;
goto done_with_status_code;
case HIO_HTTP_POST:
case HIO_HTTP_PUT:
if (file->options & HIO_SVC_HTTS_FILE_READ_ONLY)
{ {
if (file_send_header_to_client(file, 200, 0, mime_type) <= -1) goto oops; status_code = HIO_HTTP_STATUS_METHOD_NOT_ALLOWED;
goto done_with_status_code;
}
if (open_peer_with_mode(file, actual_file, O_WRONLY | O_TRUNC | O_CREAT, &status_code) <= -1) goto done_with_status_code;
/* the client input must be written to the peer side */
file_mark_over (file, FILE_OVER_READ_FROM_PEER);
break;
case HIO_HTTP_DELETE:
if (file->options & HIO_SVC_HTTS_FILE_READ_ONLY)
{
status_code = HIO_HTTP_STATUS_METHOD_NOT_ALLOWED;
goto done_with_status_code;
}
if (unlink(actual_file) <= -1)
{
if (errno != EISDIR || (errno == EISDIR && rmdir(actual_file) <= -1))
{
status_code = ERRNO_TO_STATUS_CODE(errno);
goto done_with_status_code;
}
}
status_code = HIO_HTTP_STATUS_OK;
goto done_with_status_code;
default:
status_code = HIO_HTTP_STATUS_METHOD_NOT_ALLOWED;
done_with_status_code:
if (file_send_final_status_to_client(file, status_code, 0) <= -1) goto oops;
file_mark_over (file, FILE_OVER_READ_FROM_PEER | FILE_OVER_WRITE_TO_PEER); file_mark_over (file, FILE_OVER_READ_FROM_PEER | FILE_OVER_WRITE_TO_PEER);
break;
} }
/* TODO: store current input watching state and use it when destroying the file data */ /* TODO: store current input watching state and use it when destroying the file data */

View File

@ -59,6 +59,7 @@ struct thr_state_t
{ {
HIO_SVC_HTTS_RSRC_HEADER; HIO_SVC_HTTS_RSRC_HEADER;
int options;
hio_oow_t num_pending_writes_to_client; hio_oow_t num_pending_writes_to_client;
hio_oow_t num_pending_writes_to_peer; hio_oow_t num_pending_writes_to_peer;
hio_dev_thr_t* peer; hio_dev_thr_t* peer;
@ -70,6 +71,7 @@ struct thr_state_t
unsigned int keep_alive: 1; unsigned int keep_alive: 1;
unsigned int req_content_length_unlimited: 1; unsigned int req_content_length_unlimited: 1;
unsigned int ever_attempted_to_write_to_client: 1; unsigned int ever_attempted_to_write_to_client: 1;
unsigned int client_eof_detected: 1;
unsigned int client_disconnected: 1; unsigned int client_disconnected: 1;
unsigned int client_htrd_recbs_changed: 1; unsigned int client_htrd_recbs_changed: 1;
hio_oow_t req_content_length; /* client request content length */ hio_oow_t req_content_length; /* client request content length */
@ -160,7 +162,7 @@ static int thr_state_write_last_chunk_to_client (thr_state_t* thr_state)
{ {
if (!thr_state->ever_attempted_to_write_to_client) if (!thr_state->ever_attempted_to_write_to_client)
{ {
if (thr_state_send_final_status_to_client(thr_state, 500, 0) <= -1) return -1; if (thr_state_send_final_status_to_client(thr_state, HIO_HTTP_STATUS_INTERNAL_SERVER_ERROR, 0) <= -1) return -1;
} }
else else
{ {
@ -225,7 +227,7 @@ static HIO_INLINE void thr_state_mark_over (thr_state_t* thr_state, int over_bit
hio_dev_thr_halt (thr_state->peer); hio_dev_thr_halt (thr_state->peer);
} }
if (thr_state->keep_alive) if (thr_state->keep_alive && !thr_state->client_eof_detected)
{ {
/* how to arrange to delete this thr_state object and put the socket back to the normal waiting state??? */ /* how to arrange to delete this thr_state object and put the socket back to the normal waiting state??? */
HIO_ASSERT (thr_state->htts->hio, thr_state->client->rsrc == (hio_svc_htts_rsrc_t*)thr_state); HIO_ASSERT (thr_state->htts->hio, thr_state->client->rsrc == (hio_svc_htts_rsrc_t*)thr_state);
@ -396,7 +398,7 @@ static int thr_peer_on_read (hio_dev_thr_t* thr, const void* data, hio_iolen_t d
if (!thr_state->ever_attempted_to_write_to_client && if (!thr_state->ever_attempted_to_write_to_client &&
!(thr_state->over & THR_STATE_OVER_WRITE_TO_CLIENT)) !(thr_state->over & THR_STATE_OVER_WRITE_TO_CLIENT))
{ {
thr_state_send_final_status_to_client (thr_state, 500, 1); /* don't care about error because it jumps to oops below anyway */ thr_state_send_final_status_to_client (thr_state, HIO_HTTP_STATUS_INTERNAL_SERVER_ERROR, 1); /* don't care about error because it jumps to oops below anyway */
} }
goto oops; goto oops;
@ -452,7 +454,7 @@ static int thr_peer_htrd_peek (hio_htrd_t* htrd, hio_htre_t* req)
thr_state_t* thr_state = thr_peer->state; thr_state_t* thr_state = thr_peer->state;
hio_svc_htts_cli_t* cli = thr_state->client; hio_svc_htts_cli_t* cli = thr_state->client;
hio_bch_t dtbuf[64]; hio_bch_t dtbuf[64];
int status_code = 200; int status_code = HIO_HTTP_STATUS_OK;
if (req->attr.content_length) if (req->attr.content_length)
{ {
@ -693,11 +695,14 @@ static int thr_client_on_read (hio_dev_sck_t* sck, const void* buf, hio_iolen_t
{ {
/* EOF on the client side. arrange to close */ /* EOF on the client side. arrange to close */
HIO_DEBUG3 (hio, "HTTPS(%p) - EOF from client %p(hnd=%d)\n", thr_state->client->htts, sck, (int)sck->hnd); HIO_DEBUG3 (hio, "HTTPS(%p) - EOF from client %p(hnd=%d)\n", thr_state->client->htts, sck, (int)sck->hnd);
thr_state->client_eof_detected = 1;
if (!(thr_state->over & THR_STATE_OVER_READ_FROM_CLIENT)) /* if this is true, EOF is received without thr_client_htrd_poke() */ if (!(thr_state->over & THR_STATE_OVER_READ_FROM_CLIENT)) /* if this is true, EOF is received without thr_client_htrd_poke() */
{ {
if (thr_state_write_to_peer(thr_state, HIO_NULL, 0) <= -1) goto oops; int n;
n = thr_state_write_to_peer(thr_state, HIO_NULL, 0);
thr_state_mark_over (thr_state, THR_STATE_OVER_READ_FROM_CLIENT); thr_state_mark_over (thr_state, THR_STATE_OVER_READ_FROM_CLIENT);
if (n <= -1) goto oops;
} }
} }
else else
@ -812,7 +817,7 @@ static int thr_capture_request_header (hio_htre_t* req, const hio_bch_t* key, co
return 0; return 0;
} }
int hio_svc_htts_dothr (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, hio_svc_htts_thr_func_t func, void* ctx) int hio_svc_htts_dothr (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, hio_svc_htts_thr_func_t func, void* ctx, int options)
{ {
hio_t* hio = htts->hio; hio_t* hio = htts->hio;
hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck); hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck);
@ -857,6 +862,7 @@ int hio_svc_htts_dothr (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
thr_state = (thr_state_t*)hio_svc_htts_rsrc_make(htts, HIO_SIZEOF(*thr_state), thr_state_on_kill); thr_state = (thr_state_t*)hio_svc_htts_rsrc_make(htts, HIO_SIZEOF(*thr_state), thr_state_on_kill);
if (HIO_UNLIKELY(!thr_state)) goto oops; if (HIO_UNLIKELY(!thr_state)) goto oops;
thr_state->options = options;
thr_state->client = cli; thr_state->client = cli;
/*thr_state->num_pending_writes_to_client = 0; /*thr_state->num_pending_writes_to_client = 0;
thr_state->num_pending_writes_to_peer = 0;*/ thr_state->num_pending_writes_to_peer = 0;*/
@ -902,7 +908,7 @@ int hio_svc_htts_dothr (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
* option 2. send 411 Length Required immediately * option 2. send 411 Length Required immediately
* option 3. set Content-Length to -1 and use EOF to indicate the end of content [Non-Standard] */ * option 3. set Content-Length to -1 and use EOF to indicate the end of content [Non-Standard] */
if (thr_state_send_final_status_to_client(thr_state, 411, 1) <= -1) goto oops; if (thr_state_send_final_status_to_client(thr_state, HIO_HTTP_STATUS_LENGTH_REQUIRED, 1) <= -1) goto oops;
} }
#endif #endif
@ -910,7 +916,8 @@ int hio_svc_htts_dothr (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
{ {
/* TODO: Expect: 100-continue? who should handle this? thr? or the http server? */ /* TODO: Expect: 100-continue? who should handle this? thr? or the http server? */
/* CAN I LET the thr SCRIPT handle this? */ /* CAN I LET the thr SCRIPT handle this? */
if (hio_comp_http_version_numbers(&req->version, 1, 1) >= 0 && if (!(options & HIO_SVC_HTTS_THR_NO_100_CONTINUE) &&
hio_comp_http_version_numbers(&req->version, 1, 1) >= 0 &&
(thr_state->req_content_length_unlimited || thr_state->req_content_length > 0)) (thr_state->req_content_length_unlimited || thr_state->req_content_length > 0))
{ {
/* /*
@ -929,7 +936,7 @@ int hio_svc_htts_dothr (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
hio_bch_t msgbuf[64]; hio_bch_t msgbuf[64];
hio_oow_t msglen; hio_oow_t msglen;
msglen = hio_fmttobcstr(hio, msgbuf, HIO_COUNTOF(msgbuf), "HTTP/%d.%d 100 Continue\r\n\r\n", thr_state->req_version.major, thr_state->req_version.minor); msglen = hio_fmttobcstr(hio, msgbuf, HIO_COUNTOF(msgbuf), "HTTP/%d.%d %d %hs\r\n\r\n", thr_state->req_version.major, thr_state->req_version.minor, HIO_HTTP_STATUS_CONTINUE, hio_http_status_to_bcstr(HIO_HTTP_STATUS_CONTINUE));
if (thr_state_write_to_client(thr_state, msgbuf, msglen) <= -1) goto oops; if (thr_state_write_to_client(thr_state, msgbuf, msglen) <= -1) goto oops;
thr_state->ever_attempted_to_write_to_client = 0; /* reset this as it's polluted for 100 continue */ thr_state->ever_attempted_to_write_to_client = 0; /* reset this as it's polluted for 100 continue */
} }
@ -937,7 +944,7 @@ int hio_svc_htts_dothr (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
else if (req->flags & HIO_HTRE_ATTR_EXPECT) else if (req->flags & HIO_HTRE_ATTR_EXPECT)
{ {
/* 417 Expectation Failed */ /* 417 Expectation Failed */
thr_state_send_final_status_to_client(thr_state, 417, 1); thr_state_send_final_status_to_client(thr_state, HIO_HTTP_STATUS_EXPECTATION_FAILED, 1);
goto oops; goto oops;
} }

View File

@ -33,6 +33,7 @@ struct txt_t
{ {
HIO_SVC_HTTS_RSRC_HEADER; HIO_SVC_HTTS_RSRC_HEADER;
int options;
hio_oow_t num_pending_writes_to_client; hio_oow_t num_pending_writes_to_client;
hio_svc_htts_cli_t* client; hio_svc_htts_cli_t* client;
hio_http_version_t req_version; /* client request */ hio_http_version_t req_version; /* client request */
@ -40,6 +41,7 @@ struct txt_t
unsigned int over: 2; /* must be large enough to accomodate TXT_OVER_ALL */ unsigned int over: 2; /* must be large enough to accomodate TXT_OVER_ALL */
unsigned int keep_alive: 1; unsigned int keep_alive: 1;
unsigned int req_content_length_unlimited: 1; unsigned int req_content_length_unlimited: 1;
unsigned int client_eof_detected: 1;
unsigned int client_disconnected: 1; unsigned int client_disconnected: 1;
unsigned int client_htrd_recbs_changed: 1; unsigned int client_htrd_recbs_changed: 1;
hio_oow_t req_content_length; /* client request content length */ hio_oow_t req_content_length; /* client request content length */
@ -133,7 +135,7 @@ static HIO_INLINE void txt_mark_over (txt_t* txt, int over_bits)
if (old_over != TXT_OVER_ALL && txt->over == TXT_OVER_ALL) if (old_over != TXT_OVER_ALL && txt->over == TXT_OVER_ALL)
{ {
/* ready to stop */ /* ready to stop */
if (txt->keep_alive) if (txt->keep_alive && !txt->client_eof_detected)
{ {
/* how to arrange to delete this txt object and put the socket back to the normal waiting state??? */ /* how to arrange to delete this txt object and put the socket back to the normal waiting state??? */
HIO_ASSERT (txt->htts->hio, txt->client->rsrc == (hio_svc_htts_rsrc_t*)txt); HIO_ASSERT (txt->htts->hio, txt->client->rsrc == (hio_svc_htts_rsrc_t*)txt);
@ -248,6 +250,7 @@ static int txt_client_on_read (hio_dev_sck_t* sck, const void* buf, hio_iolen_t
{ {
/* EOF on the client side. arrange to close */ /* EOF on the client side. arrange to close */
HIO_DEBUG3 (hio, "HTTPS(%p) - EOF from client %p(hnd=%d)\n", txt->client->htts, sck, (int)sck->hnd); HIO_DEBUG3 (hio, "HTTPS(%p) - EOF from client %p(hnd=%d)\n", txt->client->htts, sck, (int)sck->hnd);
txt->client_eof_detected = 1;
if (!(txt->over & TXT_OVER_READ_FROM_CLIENT)) /* if this is true, EOF is received without txt_client_htrd_poke() */ if (!(txt->over & TXT_OVER_READ_FROM_CLIENT)) /* if this is true, EOF is received without txt_client_htrd_poke() */
{ {
@ -316,7 +319,7 @@ oops:
return 0; return 0;
} }
int hio_svc_htts_dotxt (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, int status_code, const hio_bch_t* content_type, const hio_bch_t* content_text) int hio_svc_htts_dotxt (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, int status_code, const hio_bch_t* content_type, const hio_bch_t* content_text, int options)
{ {
hio_t* hio = htts->hio; hio_t* hio = htts->hio;
hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck); hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck);
@ -328,6 +331,7 @@ int hio_svc_htts_dotxt (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
txt = (txt_t*)hio_svc_htts_rsrc_make(htts, HIO_SIZEOF(*txt), txt_on_kill); txt = (txt_t*)hio_svc_htts_rsrc_make(htts, HIO_SIZEOF(*txt), txt_on_kill);
if (HIO_UNLIKELY(!txt)) goto oops; if (HIO_UNLIKELY(!txt)) goto oops;
txt->options = options;
txt->client = cli; txt->client = cli;
/*txt->num_pending_writes_to_client = 0;*/ /*txt->num_pending_writes_to_client = 0;*/
txt->req_version = *hio_htre_getversion(req); txt->req_version = *hio_htre_getversion(req);
@ -350,7 +354,7 @@ int hio_svc_htts_dotxt (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r
else if (req->flags & HIO_HTRE_ATTR_EXPECT) else if (req->flags & HIO_HTRE_ATTR_EXPECT)
{ {
/* 417 Expectation Failed */ /* 417 Expectation Failed */
txt_send_final_status_to_client(txt, 417, HIO_NULL, HIO_NULL, 1); txt_send_final_status_to_client(txt, HIO_HTTP_STATUS_EXPECTATION_FAILED, HIO_NULL, HIO_NULL, 1);
goto oops; goto oops;
} }

View File

@ -46,50 +46,50 @@ const hio_bch_t* hio_http_status_to_bcstr (int code)
switch (code) switch (code)
{ {
case 100: msg = "Continue"; break; case HIO_HTTP_STATUS_CONTINUE: msg = "Continue"; break;
case 101: msg = "Switching Protocols"; break; case HIO_HTTP_STATUS_SWITCH_PROTOCOL: msg = "Switching Protocols"; break;
case 200: msg = "OK"; break; case HIO_HTTP_STATUS_OK: msg = "OK"; break;
case 201: msg = "Created"; break; case HIO_HTTP_STATUS_CREATED: msg = "Created"; break;
case 202: msg = "Accepted"; break; case HIO_HTTP_STATUS_ACCEPTED: msg = "Accepted"; break;
case 203: msg = "Non-Authoritative Information"; break; case HIO_HTTP_STATUS_NON_AUTHORITATIVE: msg = "Non-Authoritative Information"; break;
case 204: msg = "No Content"; break; case HIO_HTTP_STATUS_NO_CONTENT: msg = "No Content"; break;
case 205: msg = "Reset Content"; break; case HIO_HTTP_STATUS_RESET_CONTENT: msg = "Reset Content"; break;
case 206: msg = "Partial Content"; break; case HIO_HTTP_STATUS_PARTIAL_CONTENT: msg = "Partial Content"; break;
case 300: msg = "Multiple Choices"; break; case 300: msg = "Multiple Choices"; break;
case 301: msg = "Moved Permanently"; break; case HIO_HTTP_STATUS_MOVED_PERMANENTLY: msg = "Moved Permanently"; break;
case 302: msg = "Found"; break; case 302: msg = "Found"; break;
case 303: msg = "See Other"; break; case 303: msg = "See Other"; break;
case 304: msg = "Not Modified"; break; case HIO_HTTP_STATUS_NOT_MODIFIED: msg = "Not Modified"; break;
case 305: msg = "Use Proxy"; break; case 305: msg = "Use Proxy"; break;
case 307: msg = "Temporary Redirect"; break; case 307: msg = "Temporary Redirect"; break;
case 308: msg = "Permanent Redirect"; break; case 308: msg = "Permanent Redirect"; break;
case 400: msg = "Bad Request"; break; case HIO_HTTP_STATUS_BAD_REQUEST: msg = "Bad Request"; break;
case 401: msg = "Unauthorized"; break; case 401: msg = "Unauthorized"; break;
case 402: msg = "Payment Required"; break; case 402: msg = "Payment Required"; break;
case 403: msg = "Forbidden"; break; case HIO_HTTP_STATUS_FORBIDDEN: msg = "Forbidden"; break;
case 404: msg = "Not Found"; break; case HIO_HTTP_STATUS_NOT_FOUND: msg = "Not Found"; break;
case 405: msg = "Method Not Allowed"; break; case HIO_HTTP_STATUS_METHOD_NOT_ALLOWED: msg = "Method Not Allowed"; break;
case 406: msg = "Not Acceptable"; break; case 406: msg = "Not Acceptable"; break;
case 407: msg = "Proxy Authentication Required"; break; case 407: msg = "Proxy Authentication Required"; break;
case 408: msg = "Request Timeout"; break; case 408: msg = "Request Timeout"; break;
case 409: msg = "Conflict"; break; case 409: msg = "Conflict"; break;
case 410: msg = "Gone"; break; case 410: msg = "Gone"; break;
case 411: msg = "Length Required"; break; case HIO_HTTP_STATUS_LENGTH_REQUIRED: msg = "Length Required"; break;
case 412: msg = "Precondition Failed"; break; case 412: msg = "Precondition Failed"; break;
case 413: msg = "Request Entity Too Large"; break; case 413: msg = "Request Entity Too Large"; break;
case 414: msg = "Request-URI Too Long"; break; case 414: msg = "Request-URI Too Long"; break;
case 415: msg = "Unsupported Media Type"; break; case 415: msg = "Unsupported Media Type"; break;
case 416: msg = "Requested Range Not Satisfiable"; break; case HIO_HTTP_STATUS_RANGE_NOT_SATISFIABLE: msg = "Requested Range Not Satisfiable"; break;
case 417: msg = "Expectation Failed"; break; case HIO_HTTP_STATUS_EXPECTATION_FAILED: msg = "Expectation Failed"; break;
case 426: msg = "Upgrade Required"; break; case 426: msg = "Upgrade Required"; break;
case 428: msg = "Precondition Required"; break; case 428: msg = "Precondition Required"; break;
case 429: msg = "Too Many Requests"; break; case 429: msg = "Too Many Requests"; break;
case 431: msg = "Request Header Fields Too Large"; break; case 431: msg = "Request Header Fields Too Large"; break;
case 500: msg = "Internal Server Error"; break; case HIO_HTTP_STATUS_INTERNAL_SERVER_ERROR: msg = "Internal Server Error"; break;
case 501: msg = "Not Implemented"; break; case 501: msg = "Not Implemented"; break;
case 502: msg = "Bad Gateway"; break; case 502: msg = "Bad Gateway"; break;
case 503: msg = "Service Unavailable"; break; case 503: msg = "Service Unavailable"; break;
@ -217,13 +217,7 @@ int hio_parse_http_range_bcstr (const hio_bch_t* str, hio_http_range_t* range)
hio_foff_t from, to; hio_foff_t from, to;
int type = HIO_HTTP_RANGE_PROPER; int type = HIO_HTTP_RANGE_PROPER;
if (str[0] != 'b' || if (str[0] != 'b' || str[1] != 'y' || str[2] != 't' || str[3] != 'e' || str[4] != 's' || str[5] != '=') return -1;
str[1] != 'y' ||
str[2] != 't' ||
str[3] != 'e' ||
str[4] != 's' ||
str[5] != '=') return -1;
str += 6; str += 6;
from = to = 0; from = to = 0;