diff --git a/mio/bin/t01.c b/mio/bin/t01.c index 75433c6..b8ba6e6 100644 --- a/mio/bin/t01.c +++ b/mio/bin/t01.c @@ -748,6 +748,102 @@ static void on_dnc_resolve_brief (mio_svc_dnc_t* dnc, mio_dns_msg_t* reqmsg, mio } } +/* ========================================================================= */ +int process_http_request (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req) +{ + mio_t* mio = mio_svc_htts_getmio(htts); +// mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(csck); + mio_http_method_t mth; + + /* percent-decode the query path to the original buffer + * 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 */ + + MIO_DEBUG2 (mio, "[RAW-REQ] %s %s\n", mio_htre_getqmethodname(req), mio_htre_getqpath(req)); + + mio_htre_perdecqpath(req); + /* TODO: proper request logging */ + + MIO_DEBUG2 (mio, "[REQ] %s %s\n", mio_htre_getqmethodname(req), mio_htre_getqpath(req)); + +#if 0 +mio_printf (MIO_T("================================\n")); +mio_printf (MIO_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"), + (unsigned long)time(NULL), + (peek? MIO_MT("PEEK"): MIO_MT("HANDLE")), + mio_htre_getqpath(req), + mio_htre_getmajorversion(req), + mio_htre_getminorversion(req), + mio_htre_getverstr(req), + mio_htre_getqmethodname(req) +); +if (mio_htre_getqparam(req)) + mio_printf (MIO_T("PARAMS ==> [%hs]\n"), mio_htre_getqparam(req)); + +mio_htb_walk (&req->hdrtab, walk, MIO_NULL); +if (mio_htre_getcontentlen(req) > 0) +{ + mio_printf (MIO_T("CONTENT [%.*S]\n"), (int)mio_htre_getcontentlen(req), mio_htre_getcontentptr(req)); +} +#endif + + mth = mio_htre_getqmethodtype(req); + /* 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 0 + /* TODO support X-HTTP-Method-Override */ + if (data.method == MIO_HTTP_POST) + { + tmp = mio_htre_getheaderval(req, MIO_MT("X-HTTP-Method-Override")); + if (tmp) + { + /*while (tmp->next) tmp = tmp->next;*/ /* get the last value */ + data.method = mio_mbstohttpmethod (tmp->ptr); + } + } +#endif + +#if 0 + if (mth == MIO_HTTP_CONNECT) + { + /* CONNECT method must not have content set. + * however, arrange to discard it if so. + * + * NOTE: CONNECT is implemented to ignore many headers like + * 'Expect: 100-continue' and 'Connection: keep-alive'. */ + mio_htre_discardcontent (req); + } + else + { +/* this part can be checked in actual mio_svc_htts_doXXX() functions. + * some doXXX handlers may not require length for POST. + * it may be able to simply accept till EOF? or treat as if CONTENT_LENGTH is 0*/ + if (mth == MIO_HTTP_POST && !(req->flags & (MIO_HTRE_ATTR_LENGTH | MIO_HTRE_ATTR_CHUNKED))) + { + /* POST without Content-Length nor not chunked */ + mio_htre_discardcontent (req); + /* 411 Length Required - can't keep alive. Force disconnect */ + req->flags &= ~MIO_HTRE_ATTR_KEEPALIVE; /* to cause sendstatus() to close */ + if (mio_svc_htts_sendstatus(htts, csck, req, 411, MIO_NULL) <= -1) goto oops; + } + else + + { +#endif + /*const mio_bch_t* qpath = mio_htre_getqpath(req);*/ + if (mio_svc_htts_docgi(htts, csck, req, "", mio_htre_getqpath(req)) <= -1) goto oops; + + return 0; + +oops: + mio_dev_sck_halt (csck); + return -1; +} + /* ========================================================================= */ static mio_t* g_mio; @@ -976,7 +1072,7 @@ for (i = 0; i < 5; i++) mio_bcstrtoskad (mio, "127.0.0.1:9988", &htts_bind_addr); dnc = mio_svc_dnc_start(mio, &servaddr, MIO_NULL, &send_tmout, &reply_tmout, 2); /* option - send to all, send one by one */ - htts = mio_svc_htts_start(mio, &htts_bind_addr); + htts = mio_svc_htts_start(mio, &htts_bind_addr, process_http_request); mio_svc_htts_setservernamewithbcstr (htts, "MIO-HTTP"); #if 1 diff --git a/mio/lib/htrd.c b/mio/lib/htrd.c index 1348aab..d1d7ed4 100644 --- a/mio/lib/htrd.c +++ b/mio/lib/htrd.c @@ -1217,43 +1217,9 @@ int mio_htrd_feed (mio_htrd_t* htrd, const mio_bch_t* req, mio_oow_t len, mio_oo /* need to clear request on error? clear_feed (htrd); */ return -1; -/// TODO: PEEKONLY doens't seem to be neede. delete it... } //////////////////////////////////////////////////////////////////////////////////////////////////// - if (htrd->option & MIO_HTRD_PEEKONLY) - { - /* when MIO_HTRD_PEEKONLY is set, - * the peek callback is invoked once - * a complete header is seen. the caller - * should not feed more data by calling - * this function again once the callback is - * invoked. the trailing data is appended - * to the content buffer. - * - * NOTE: if the current feed that completed - * the header contains the next request, - * the next request is treated as if it - * belongs to the current request. - * - * In priciple, this option was added for - * reading CGI outputs. So it comes with - * awkwardity described above. - */ - if (ptr < end && push_content(htrd, ptr, end - ptr) <= -1) return -1; - - /* i don't really know if it is really completed - * with content. MIO_HTRD_PEEKONLY is not compatible - * with the completed state. anyway, let me complete - * it. */ - mio_htre_completecontent (&htrd->re); - - /* this jump is only to invoke the peek - * callback. this function should not be fed - * more. */ - goto feedme_more; - } - /* carry on processing content body fed together with the header */ if (htrd->re.flags & MIO_HTRE_ATTR_CHUNKED) { diff --git a/mio/lib/http-svr.c b/mio/lib/http-svr.c index 327b320..23a8297 100644 --- a/mio/lib/http-svr.c +++ b/mio/lib/http-svr.c @@ -3,6 +3,7 @@ #include "mio-pro.h" /* for cgi */ #include "mio-fmt.h" #include "mio-chr.h" +#include "mio-path.h" #include "mio-prv.h" @@ -35,6 +36,8 @@ struct mio_svc_htts_t { MIO_SVC_HEADER; + mio_svc_htts_proc_req_t proc_req; + mio_dev_sck_t* lsck; mio_svc_htts_cli_t cli; /* list head for client list */ @@ -98,110 +101,11 @@ static int test_func_handler (int rfd, int wfd) return -1; } -static int process_request (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req) -{ - //server_xtn_t* server_xtn = GET_SERVER_XTN(htts, client->server); - //mio_htts_task_t* task; - mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(csck); - mio_http_method_t mth; - //mio_htts_rsrc_t rsrc; - - /* percent-decode the query path to the original buffer - * 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 */ - - MIO_DEBUG2 (htts->mio, "[RAW-REQ] %s %s\n", mio_htre_getqmethodname(req), mio_htre_getqpath(req)); - - mio_htre_perdecqpath(req); - /* TODO: proper request logging */ - - MIO_DEBUG2 (htts->mio, "[REQ] %s %s\n", mio_htre_getqmethodname(req), mio_htre_getqpath(req)); - - - -#if 0 -mio_printf (MIO_T("================================\n")); -mio_printf (MIO_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"), - (unsigned long)time(NULL), - (peek? MIO_MT("PEEK"): MIO_MT("HANDLE")), - mio_htre_getqpath(req), - mio_htre_getmajorversion(req), - mio_htre_getminorversion(req), - mio_htre_getverstr(req), - mio_htre_getqmethodname(req) -); -if (mio_htre_getqparam(req)) - mio_printf (MIO_T("PARAMS ==> [%hs]\n"), mio_htre_getqparam(req)); - -mio_htb_walk (&req->hdrtab, walk, MIO_NULL); -if (mio_htre_getcontentlen(req) > 0) -{ - mio_printf (MIO_T("CONTENT [%.*S]\n"), (int)mio_htre_getcontentlen(req), mio_htre_getcontentptr(req)); -} -#endif - - mth = mio_htre_getqmethodtype(req); - /* 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 0 - /* TODO support X-HTTP-Method-Override */ - if (data.method == MIO_HTTP_POST) - { - tmp = mio_htre_getheaderval(req, MIO_MT("X-HTTP-Method-Override")); - if (tmp) - { - /*while (tmp->next) tmp = tmp->next;*/ /* get the last value */ - data.method = mio_mbstohttpmethod (tmp->ptr); - } - } -#endif - -#if 0 - if (mth == MIO_HTTP_CONNECT) - { - /* CONNECT method must not have content set. - * however, arrange to discard it if so. - * - * NOTE: CONNECT is implemented to ignore many headers like - * 'Expect: 100-continue' and 'Connection: keep-alive'. */ - mio_htre_discardcontent (req); - } - else - { -/* this part can be checked in actual mio_svc_htts_doXXX() functions. - * some doXXX handlers may not require length for POST. - * it may be able to simply accept till EOF? or treat as if CONTENT_LENGTH is 0*/ - if (mth == MIO_HTTP_POST && !(req->flags & (MIO_HTRE_ATTR_LENGTH | MIO_HTRE_ATTR_CHUNKED))) - { - /* POST without Content-Length nor not chunked */ - mio_htre_discardcontent (req); - /* 411 Length Required - can't keep alive. Force disconnect */ - req->flags &= ~MIO_HTRE_ATTR_KEEPALIVE; /* to cause sendstatus() to close */ - if (mio_svc_htts_sendstatus(htts, csck, req, 411, MIO_NULL) <= -1) goto oops; - } - else - - { -#endif - /*const mio_bch_t* qpath = mio_htre_getqpath(req);*/ - if (mio_svc_htts_docgi(htts, csck, req, "") <= -1) goto oops; - - return 0; - -oops: - mio_dev_sck_halt (csck); - return -1; -} - static int client_htrd_peek_request (mio_htrd_t* htrd, mio_htre_t* req) { htrd_xtn_t* htrdxtn = (htrd_xtn_t*)mio_htrd_getxtn(htrd); mio_svc_htts_cli_t* sckxtn = (mio_svc_htts_cli_t*)mio_dev_sck_getxtn(htrdxtn->sck); - return process_request(sckxtn->htts, htrdxtn->sck, req); + return sckxtn->htts->proc_req(sckxtn->htts, htrdxtn->sck, req); } @@ -439,7 +343,7 @@ static void listener_on_disconnect (mio_dev_sck_t* sck) /* ------------------------------------------------------------------------ */ -mio_svc_htts_t* mio_svc_htts_start (mio_t* mio, const mio_skad_t* bind_addr) +mio_svc_htts_t* mio_svc_htts_start (mio_t* mio, const mio_skad_t* bind_addr, mio_svc_htts_proc_req_t proc_req) { mio_svc_htts_t* htts = MIO_NULL; union @@ -455,6 +359,7 @@ mio_svc_htts_t* mio_svc_htts_start (mio_t* mio, const mio_skad_t* bind_addr) htts->mio = mio; htts->svc_stop = mio_svc_htts_stop; + htts->proc_req = proc_req; MIO_MEMSET (&info, 0, MIO_SIZEOF(info)); switch (mio_skad_family(bind_addr)) @@ -1314,6 +1219,8 @@ struct cgi_peer_fork_ctx_t mio_svc_htts_cli_t* cli; mio_htre_t* req; const mio_bch_t* docroot; + const mio_bch_t* script; + mio_bch_t* actual_script; }; typedef struct cgi_peer_fork_ctx_t cgi_peer_fork_ctx_t; @@ -1362,24 +1269,27 @@ static int cgi_peer_on_fork (mio_dev_pro_t* pro, void* fork_ctx) cgi_peer_fork_ctx_t* fc = (cgi_peer_fork_ctx_t*)fork_ctx; mio_oow_t content_length; const mio_bch_t* qparam; - const char* path; + const char* path, * lang; mio_bch_t tmp[256]; mio_becs_t dbuf; qparam = mio_htre_getqparam(fc->req); path = getenv("PATH"); + lang = getenv("LANG"); clearenv (); if (path) setenv ("PATH", path, 1); + if (lang) setenv ("LANG", lang, 1); setenv ("GATEWAY_INTERFACE", "CGI/1.1", 1); mio_fmttobcstr (pro->mio, tmp, MIO_COUNTOF(tmp), "HTTP/%d.%d", (int)mio_htre_getmajorversion(fc->req), (int)mio_htre_getminorversion(fc->req)); setenv ("SERVER_PROTOCOL", tmp, 1); - //setenv ("SCRIPT_FILENAME", - //setenv ("SCRIPT_NAME", setenv ("DOCUMENT_ROOT", fc->docroot, 1); + setenv ("SCRIPT_NAME", fc->script, 1); + setenv ("SCRIPT_FILENAME", fc->actual_script, 1); + /* TODO: PATH_INFO */ setenv ("REQUEST_METHOD", mio_htre_getqmethodname(fc->req), 1); setenv ("REQUEST_URI", mio_htre_getqpath(fc->req), 1); @@ -1422,8 +1332,7 @@ static int cgi_peer_on_fork (mio_dev_pro_t* pro, void* fork_ctx) return 0; } - -int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, const mio_bch_t* docroot) +int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, const mio_bch_t* docroot, const mio_bch_t* script) { mio_t* mio = htts->mio; mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(csck); @@ -1439,10 +1348,13 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r fc.cli = cli; fc.req = req; fc.docroot = docroot; + fc.script = script; + fc.actual_script = mio_svc_htts_dupmergepaths(htts, docroot, script); + if (!fc.actual_script) goto oops; MIO_MEMSET (&mi, 0, MIO_SIZEOF(mi)); mi.flags = MIO_DEV_PRO_READOUT | MIO_DEV_PRO_ERRTONUL | MIO_DEV_PRO_WRITEIN /*| MIO_DEV_PRO_FORGET_CHILD*/; - mi.cmd = mio_htre_getqpath(req); /* TODO: combine it with docroot */ + mi.cmd = fc.actual_script; mi.on_read = cgi_peer_on_read; mi.on_write = cgi_peer_on_write; mi.on_close = cgi_peer_on_close; @@ -1468,10 +1380,6 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r MIO_ASSERT (mio, cli->rsrc == MIO_NULL); MIO_SVC_HTTS_RSRC_ATTACH (cgi_state, cli->rsrc); -/* TODO: create cgi environment variables... */ -/* TODO: - * never put Expect: 100-continue to environment variable - */ if (access(mi.cmd, X_OK) == -1) { cgi_state_send_final_status_to_client (cgi_state, 403); /* 403 Forbidden */ @@ -1588,17 +1496,29 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r /* TODO: store current input watching state and use it when destroying the cgi_state data */ if (mio_dev_sck_read(csck, !(cgi_state->over & CGI_STATE_OVER_READ_FROM_CLIENT)) <= -1) goto oops; + mio_freemem (mio, fc.actual_script); return 0; oops: MIO_DEBUG2 (mio, "HTTS(%p) - FAILURE in docgi - socket(%p)\n", htts, csck); if (cgi_state) cgi_state_halt_participating_devices (cgi_state); + if (fc.actual_script) mio_freemem (mio, fc.actual_script); return -1; } /* ----------------------------------------------------------------- */ -int mio_svc_htts_dofile (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, const mio_bch_t* docroot) +#if 0 +int mio_svc_htts_dothrfunc (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, mio_svc_htts_func_t func) +{ + +} +#endif + + +/* ----------------------------------------------------------------- */ + +int mio_svc_htts_dofile (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, const mio_bch_t* docroot, const mio_bch_t* file) { switch (mio_htre_getqmethodtype(req)) { @@ -1668,6 +1588,26 @@ void mio_svc_htts_fmtgmtime (mio_svc_htts_t* htts, const mio_ntime_t* nt, mio_bc mio_fmt_http_time_to_bcstr(nt, buf, len); } +mio_bch_t* mio_svc_htts_dupmergepaths (mio_svc_htts_t* htts, const mio_bch_t* base, const mio_bch_t* path) +{ + mio_bch_t* xpath; + const mio_bch_t* ta[4]; + mio_oow_t idx = 0; + + ta[idx++] = base; + if (path[0] != '\0') + { + ta[idx++] = "/"; + ta[idx++] = path; + } + ta[idx++] = MIO_NULL; + xpath = mio_dupbcstrs(htts->mio, ta, MIO_NULL); + if (MIO_UNLIKELY(!xpath)) return MIO_NULL; + + mio_canon_bcstr_path (xpath, xpath, 0); + return xpath; +} + /* ----------------------------------------------------------------- */ #if 0 diff --git a/mio/lib/mio-dns.h b/mio/lib/mio-dns.h index b2f6957..a839091 100644 --- a/mio/lib/mio-dns.h +++ b/mio/lib/mio-dns.h @@ -387,15 +387,7 @@ typedef void (*mio_svc_dnc_on_resolve_t) ( mio_oow_t len ); -#if defined(MIO_HAVE_INLINE) -static MIO_INLINE mio_t* mio_svc_dns_getmio(mio_svc_dns_t* svc) { return mio_svc_getmio((mio_svc_t*)svc); } -static MIO_INLINE mio_t* mio_svc_dnc_getmio(mio_svc_dnc_t* svc) { return mio_svc_getmio((mio_svc_t*)svc); } -static MIO_INLINE mio_t* mio_svc_dnr_getmio(mio_svc_dnr_t* svc) { return mio_svc_getmio((mio_svc_t*)svc); } -#else -# define mio_svc_dns_getmio(svc) mio_svc_getmio(svc) -# define mio_svc_dnc_getmio(svc) mio_svc_getmio(svc) -# define mio_svc_dnr_getmio(svc) mio_svc_getmio(svc) -#endif + enum mio_svc_dnc_send_flag_t { @@ -476,6 +468,16 @@ MIO_EXPORT void mio_svc_dnc_stop ( mio_svc_dnc_t* dnc ); +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE mio_t* mio_svc_dns_getmio(mio_svc_dns_t* svc) { return mio_svc_getmio((mio_svc_t*)svc); } +static MIO_INLINE mio_t* mio_svc_dnc_getmio(mio_svc_dnc_t* svc) { return mio_svc_getmio((mio_svc_t*)svc); } +static MIO_INLINE mio_t* mio_svc_dnr_getmio(mio_svc_dnr_t* svc) { return mio_svc_getmio((mio_svc_t*)svc); } +#else +# define mio_svc_dns_getmio(svc) mio_svc_getmio(svc) +# define mio_svc_dnc_getmio(svc) mio_svc_getmio(svc) +# define mio_svc_dnr_getmio(svc) mio_svc_getmio(svc) +#endif + MIO_EXPORT mio_dns_msg_t* mio_svc_dnc_sendmsg ( mio_svc_dnc_t* dnc, mio_dns_bhdr_t* bdns, diff --git a/mio/lib/mio-htrd.h b/mio/lib/mio-htrd.h index f4fc7e9..d383e47 100644 --- a/mio/lib/mio-htrd.h +++ b/mio/lib/mio-htrd.h @@ -55,11 +55,10 @@ enum mio_htrd_option_t MIO_HTRD_SKIPEMPTYLINES = (1 << 0), /**< skip leading empty lines before the initial line */ MIO_HTRD_SKIPINITIALLINE = (1 << 1), /**< skip processing an initial line */ MIO_HTRD_CANONQPATH = (1 << 2), /**< canonicalize the query path */ - MIO_HTRD_PEEKONLY = (1 << 3), /**< trigger a peek callback after headers without processing contents */ - MIO_HTRD_REQUEST = (1 << 4), /**< parse input as a request */ - MIO_HTRD_RESPONSE = (1 << 5), /**< parse input as a response */ - MIO_HTRD_TRAILERS = (1 << 6), /**< store trailers in a separate table */ - MIO_HTRD_STRICT = (1 << 7) /**< be more picky */ + MIO_HTRD_REQUEST = (1 << 3), /**< parse input as a request */ + MIO_HTRD_RESPONSE = (1 << 4), /**< parse input as a response */ + MIO_HTRD_TRAILERS = (1 << 5), /**< store trailers in a separate table */ + MIO_HTRD_STRICT = (1 << 6) /**< be more picky */ }; typedef enum mio_htrd_option_t mio_htrd_option_t; diff --git a/mio/lib/mio-htre.h b/mio/lib/mio-htre.h index c1e5f48..e60726c 100644 --- a/mio/lib/mio-htre.h +++ b/mio/lib/mio-htre.h @@ -27,8 +27,74 @@ #ifndef _MIO_HTRE_H_ #define _MIO_HTRE_H_ -#include #include +#include + +/** + * The mio_http_version_t type defines http version. + */ +struct mio_http_version_t +{ + short major; /**< major version */ + short minor; /**< minor version */ +}; + +typedef struct mio_http_version_t mio_http_version_t; + +/** + * The mio_http_method_t type defines http methods . + */ +enum mio_http_method_t +{ + MIO_HTTP_OTHER, + + /* rfc 2616 */ + MIO_HTTP_HEAD, + MIO_HTTP_GET, + MIO_HTTP_POST, + MIO_HTTP_PUT, + MIO_HTTP_DELETE, + MIO_HTTP_OPTIONS, + MIO_HTTP_TRACE, + MIO_HTTP_CONNECT + +#if 0 + /* rfc 2518 */ + MIO_HTTP_PROPFIND, + MIO_HTTP_PROPPATCH, + MIO_HTTP_MKCOL, + MIO_HTTP_COPY, + MIO_HTTP_MOVE, + MIO_HTTP_LOCK, + MIO_HTTP_UNLOCK, + + /* rfc 3253 */ + MIO_HTTP_VERSION_CONTROL, + MIO_HTTP_REPORT, + MIO_HTTP_CHECKOUT, + MIO_HTTP_CHECKIN, + MIO_HTTP_UNCHECKOUT, + MIO_HTTP_MKWORKSPACE, + MIO_HTTP_UPDATE, + MIO_HTTP_LABEL, + MIO_HTTP_MERGE, + MIO_HTTP_BASELINE_CONTROL, + MIO_HTTP_MKACTIVITY, + + /* microsoft */ + MIO_HTTP_BPROPFIND, + MIO_HTTP_BPROPPATCH, + MIO_HTTP_BCOPY, + MIO_HTTP_BDELETE, + MIO_HTTP_BMOVE, + MIO_HTTP_NOTIFY, + MIO_HTTP_POLL, + MIO_HTTP_SUBSCRIBE, + MIO_HTTP_UNSUBSCRIBE, +#endif +}; + +typedef enum mio_http_method_t mio_http_method_t; /* * You should not manipulate an object of the #mio_htre_t @@ -37,7 +103,7 @@ */ /* header and contents of request/response */ -/*typedef struct mio_htre_t mio_htre_t; <--- defined in mio-http.h TODO: remove recursive definition */ +typedef struct mio_htre_t mio_htre_t; typedef struct mio_htre_hdrval_t mio_htre_hdrval_t; enum mio_htre_state_t diff --git a/mio/lib/mio-http.h b/mio/lib/mio-http.h index 65832dc..5a69bb6 100644 --- a/mio/lib/mio-http.h +++ b/mio/lib/mio-http.h @@ -27,77 +27,12 @@ #include #include +#include /** \file * This file provides basic data types and functions for the http protocol. */ -/** - * The mio_http_version_t type defines http version. - */ -struct mio_http_version_t -{ - short major; /**< major version */ - short minor; /**< minor version */ -}; - -typedef struct mio_http_version_t mio_http_version_t; - -/** - * The mio_http_method_t type defines http methods . - */ -enum mio_http_method_t -{ - MIO_HTTP_OTHER, - - /* rfc 2616 */ - MIO_HTTP_HEAD, - MIO_HTTP_GET, - MIO_HTTP_POST, - MIO_HTTP_PUT, - MIO_HTTP_DELETE, - MIO_HTTP_OPTIONS, - MIO_HTTP_TRACE, - MIO_HTTP_CONNECT - -#if 0 - /* rfc 2518 */ - MIO_HTTP_PROPFIND, - MIO_HTTP_PROPPATCH, - MIO_HTTP_MKCOL, - MIO_HTTP_COPY, - MIO_HTTP_MOVE, - MIO_HTTP_LOCK, - MIO_HTTP_UNLOCK, - - /* rfc 3253 */ - MIO_HTTP_VERSION_CONTROL, - MIO_HTTP_REPORT, - MIO_HTTP_CHECKOUT, - MIO_HTTP_CHECKIN, - MIO_HTTP_UNCHECKOUT, - MIO_HTTP_MKWORKSPACE, - MIO_HTTP_UPDATE, - MIO_HTTP_LABEL, - MIO_HTTP_MERGE, - MIO_HTTP_BASELINE_CONTROL, - MIO_HTTP_MKACTIVITY, - - /* microsoft */ - MIO_HTTP_BPROPFIND, - MIO_HTTP_BPROPPATCH, - MIO_HTTP_BCOPY, - MIO_HTTP_BDELETE, - MIO_HTTP_BMOVE, - MIO_HTTP_NOTIFY, - MIO_HTTP_POLL, - MIO_HTTP_SUBSCRIBE, - MIO_HTTP_UNSUBSCRIBE, -#endif -}; - -typedef enum mio_http_method_t mio_http_method_t; - /** * The #mio_http_range_int_t type defines an integer that can represent * a range offset. Depening on the size of #mio_foff_t, it is defined to @@ -155,7 +90,6 @@ typedef enum mio_perenc_http_opt_t mio_perenc_bcstr_opt_t; /* -------------------------------------------------------------- */ -typedef struct mio_htre_t mio_htre_t; typedef struct mio_svc_htts_t mio_svc_htts_t; typedef struct mio_svc_httc_t mio_svc_httc_t; @@ -180,6 +114,14 @@ struct mio_svc_htts_rsrc_t #define MIO_SVC_HTTS_RSRC_ATTACH(rsrc, var) do { (var) = (rsrc); ++(rsrc)->rsrc_refcnt; } while(0) #define MIO_SVC_HTTS_RSRC_DETACH(rsrc_var) do { if (--(rsrc_var)->rsrc_refcnt == 0) { mio_svc_htts_rsrc_t* __rsrc_tmp = (rsrc_var); (rsrc_var) = MIO_NULL; mio_svc_htts_rsrc_kill(__rsrc_tmp); } else { (rsrc_var) = MIO_NULL; } } while(0) + + +typedef int (*mio_svc_htts_proc_req_t) ( + mio_svc_htts_t* htts, + mio_dev_sck_t* sck, + mio_htre_t* req +); + /* -------------------------------------------------------------- */ #if defined(__cplusplus) @@ -279,42 +221,32 @@ MIO_EXPORT mio_bch_t* mio_perenc_http_bcstrdup ( /* ------------------------------------------------------------------------- */ MIO_EXPORT mio_svc_htts_t* mio_svc_htts_start ( - mio_t* mio, - const mio_skad_t* bind_addr + mio_t* mio, + const mio_skad_t* bind_addr, + mio_svc_htts_proc_req_t proc_req ); MIO_EXPORT void mio_svc_htts_stop ( mio_svc_htts_t* htts ); +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE mio_t* mio_svc_htts_getmio(mio_svc_htts_t* svc) { return mio_svc_getmio((mio_svc_t*)svc); } +#else +# define mio_svc_htts_getmio(svc) mio_svc_getmio(svc) +#endif + MIO_EXPORT int mio_svc_htts_setservernamewithbcstr ( mio_svc_htts_t* htts, const mio_bch_t* server_name ); MIO_EXPORT int mio_svc_htts_docgi ( - mio_svc_htts_t* htts, - mio_dev_sck_t* csck, - mio_htre_t* req, - const mio_bch_t* docroot -); - - -MIO_EXPORT int mio_svc_htts_sendfile ( - mio_svc_htts_t* htts, - mio_dev_sck_t* csck, - const mio_bch_t* file_path, - int status_code, - mio_http_method_t method, - const mio_http_version_t* version, - int keepalive -); - -MIO_EXPORT void mio_svc_htts_fmtgmtime ( - mio_svc_htts_t* htts, - const mio_ntime_t* nt, - mio_bch_t* buf, - mio_oow_t len + mio_svc_htts_t* htts, + mio_dev_sck_t* csck, + mio_htre_t* req, + const mio_bch_t* docroot, + const mio_bch_t* script ); MIO_EXPORT mio_svc_htts_rsrc_t* mio_svc_htts_rsrc_make ( @@ -335,6 +267,12 @@ MIO_EXPORT void mio_svc_htts_fmtgmtime ( mio_oow_t len ); +MIO_EXPORT mio_bch_t* mio_svc_htts_dupmergepaths ( + mio_svc_htts_t* htts, + const mio_bch_t* base, + const mio_bch_t* path +); + #if defined(__cplusplus) } #endif diff --git a/mio/lib/mio.c b/mio/lib/mio.c index 00b4e0d..a59523f 100644 --- a/mio/lib/mio.c +++ b/mio/lib/mio.c @@ -1776,7 +1776,6 @@ static int fmt_put_bchars_to_bch_buf (mio_fmtout_t* fmtout, const mio_bch_t* ptr return 1; /* success */ } - static int fmt_put_uchars_to_bch_buf (mio_fmtout_t* fmtout, const mio_uch_t* ptr, mio_oow_t len) { fmt_bch_buf_t* b = (fmt_bch_buf_t*)fmtout->ctx; diff --git a/mio/lib/mio.h b/mio/lib/mio.h index 243f886..5e0bfb6 100644 --- a/mio/lib/mio.h +++ b/mio/lib/mio.h @@ -1113,6 +1113,18 @@ MIO_EXPORT mio_bch_t* mio_dupbcstr ( mio_oow_t* bcslen /* [OUT] length */ ); +MIO_EXPORT mio_uch_t* mio_dupucstrs ( + mio_t* mio, + const mio_uch_t* ucs[], + mio_oow_t* ucslen +); + +MIO_EXPORT mio_bch_t* mio_dupbcstrs ( + mio_t* mio, + const mio_bch_t* bcs[], + mio_oow_t* bcslen +); + #if defined(MIO_OOCH_IS_UCH) # define mio_dupoochars(mio,oocs,oocslen) mio_dupuchars(mio,oocs,oocslen) # define mio_dupoocstr(mio,oocs,oocslen) mio_dupucstr(mio,oocs,oocslen) diff --git a/mio/lib/utl.c b/mio/lib/utl.c index ea0fb84..b7f8a93 100644 --- a/mio/lib/utl.c +++ b/mio/lib/utl.c @@ -1729,5 +1729,39 @@ mio_bch_t* mio_dupbcstr (mio_t* mio, const mio_bch_t* bcs, mio_oow_t* bcslen) return ptr; } +mio_uch_t* mio_dupucstrs (mio_t* mio, const mio_uch_t* ucs[], mio_oow_t* ucslen) +{ + mio_uch_t* ptr; + mio_oow_t len, i; + for (i = 0, len = 0; ucs[i]; i++) len += mio_count_ucstr(ucs[i]); + + ptr = (mio_uch_t*)mio_allocmem(mio, (len + 1) * MIO_SIZEOF(mio_uch_t)); + if (!ptr) return MIO_NULL; + + for (i = 0, len = 0; ucs[i]; i++) + len += mio_copy_ucstr_unlimited(&ptr[len], ucs[i]); + ptr[len] = '\0'; + + if (ucslen) *ucslen = len; + return ptr; +} + +mio_bch_t* mio_dupbcstrs (mio_t* mio, const mio_bch_t* bcs[], mio_oow_t* bcslen) +{ + mio_bch_t* ptr; + mio_oow_t len, i; + + for (i = 0, len = 0; bcs[i]; i++) len += mio_count_bcstr(bcs[i]); + + ptr = (mio_bch_t*)mio_allocmem(mio, (len + 1) * MIO_SIZEOF(mio_bch_t)); + if (!ptr) return MIO_NULL; + + for (i = 0, len = 0; bcs[i]; i++) + len += mio_copy_bcstr_unlimited(&ptr[len], bcs[i]); + ptr[len] = '\0'; + + if (bcslen) *bcslen = len; + return ptr; +} /* ========================================================================= */