From e96cb2ebb4c68b2cbd4c3cfc53528c7bd4d9e3cf Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Wed, 6 May 2020 09:28:36 +0000 Subject: [PATCH] added mio_sys_getrealtime() writing http server --- mio/lib/fmt.c | 1 + mio/lib/htre.c | 20 ++- mio/lib/http-svr.c | 413 ++++++++++++++++++++++++++++++++++++++++++--- mio/lib/http.c | 21 +-- mio/lib/mio-htre.h | 8 +- mio/lib/mio-http.h | 41 +++-- mio/lib/mio-prv.h | 5 + mio/lib/mio.c | 9 +- mio/lib/sys-tim.c | 14 ++ 9 files changed, 477 insertions(+), 55 deletions(-) diff --git a/mio/lib/fmt.c b/mio/lib/fmt.c index 25ab551..7c3dc79 100644 --- a/mio/lib/fmt.c +++ b/mio/lib/fmt.c @@ -1236,6 +1236,7 @@ static int fmt_outv (mio_fmtout_t* fmtout, va_list ap) PUT_OOCH (fmtout, padc, width); } + while (*nbufp) PUT_OOCH (fmtout, *nbufp--, 1); /* output actual digits */ if ((flagc & FLAGC_LEFTADJ) && width > 0 && (width -= tmp) > 0) diff --git a/mio/lib/htre.c b/mio/lib/htre.c index 089126b..3f6dc02 100644 --- a/mio/lib/htre.c +++ b/mio/lib/htre.c @@ -85,7 +85,13 @@ void mio_htre_fini (mio_htre_t* re) mio_htb_fini (&re->trailers); mio_htb_fini (&re->hdrtab); - if (re->orgqpath.buf) mio_freemem (re->mio, re->orgqpath.buf); + if (re->orgqpath.buf) + { + mio_freemem (re->mio, re->orgqpath.buf); + re->orgqpath.buf = MIO_NULL; + re->orgqpath.len = 0; + re->orgqpath.capa = 0; + } } void mio_htre_clear (mio_htre_t* re) @@ -103,8 +109,13 @@ void mio_htre_clear (mio_htre_t* re) re->state = 0; re->flags = 0; - re->orgqpath.ptr = MIO_NULL; - re->orgqpath.len = 0; + if (re->orgqpath.buf) + { + mio_freemem (re->mio, re->orgqpath.buf); + re->orgqpath.buf = MIO_NULL; + re->orgqpath.len = 0; + re->orgqpath.capa = 0; + } MIO_MEMSET (&re->version, 0, MIO_SIZEOF(re->version)); MIO_MEMSET (&re->attr, 0, MIO_SIZEOF(re->attr)); @@ -282,6 +293,7 @@ int mio_htre_perdecqpath (mio_htre_t* re) if (re->orgqpath.buf) { mio_freemem (re->mio, re->orgqpath.buf); + re->orgqpath.len = 0; re->orgqpath.capa = 0; } @@ -298,7 +310,7 @@ int mio_htre_perdecqpath (mio_htre_t* re) } } - re->u.q.path.len = mio_perdechttpstr (re->u.q.path.ptr, re->u.q.path.ptr, &dec_count); + re->u.q.path.len = mio_perdec_http_bcstr(re->u.q.path.ptr, re->u.q.path.ptr, &dec_count); if (dec_count > 0) { /* this assertion is to ensure that mio_is_perenced_http_bstr() diff --git a/mio/lib/http-svr.c b/mio/lib/http-svr.c index ea9e3ef..f6a9a06 100644 --- a/mio/lib/http-svr.c +++ b/mio/lib/http-svr.c @@ -14,10 +14,22 @@ struct mio_svc_httc_t MIO_SVC_HEADER; }; + +struct mio_htts_client_t +{ + mio_skad_t remote_addr; + mio_skad_t local_addr; + mio_skad_t orgdst_addr; + mio_htrd_t* htrd; + mio_becs_t* sbuf; /* temporary buffer for status line formatting */ +}; +typedef struct mio_htts_client_t mio_htts_client_t; + struct sck_xtn_t { mio_svc_htts_t* htts; - mio_htrd_t* htrd; /* used by clients only */ + + mio_htts_client_t c; }; typedef struct sck_xtn_t sck_xtn_t; @@ -28,6 +40,282 @@ struct htrd_xtn_t typedef struct htrd_xtn_t htrd_xtn_t; /* ------------------------------------------------------------------------ */ +static int process_request (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, int peek) +{ + //server_xtn_t* server_xtn = GET_SERVER_XTN(htts, client->server); + //mio_htts_task_t* task; + sck_xtn_t* csckxtn = 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 */ + if (peek) + { + mio_htre_perdecqpath(req); + + /* TODO: proper request logging */ + + MIO_DEBUG2 (htts->mio, "%s %s\n", mio_htre_getqmethodname(req), mio_htre_getqpath(req)); + } +else +{ + MIO_DEBUG2 (htts->mio, "[NOPEEK] %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); + if (peek) + { + /* 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 (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 + { +#if 0 + if (mth == MIO_HTTP_POST && + !(req->flags & MIO_HTRE_ATTR_LENGTH) && + !(req->flags & MIO_HTRE_ATTR_CHUNKED)) + { + /* POST without Content-Length nor not chunked */ + req->flags &= ~MIO_HTRE_ATTR_KEEPALIVE; + mio_htre_discardcontent (req); + task = mio_htts_entaskerror(htts, client, MIO_NULL, 411, req); + if (task) + { + /* 411 Length Required - can't keep alive. Force disconnect */ + task = mio_htts_entaskdisconnect (htts, client, MIO_NULL); + } + +/* + const qse_http_version_t* version = qse_htre_getversion(req); + return qse_httpd_entaskformat ( + httpd, client, pred, + QSE_MT("HTTP/%d.%d 100 Continue\r\n\r\n"), + version->major, version->minor); +*/ + mio_dev_sck_write (csck, data, len, XXXX, MIO_NULL); + } + else if (server_xtn->makersrc(htts, client, req, &rsrc) <= -1) + { + /* failed to make a resource. just send the internal server error. + * the makersrc handler can return a negative number to return + * '500 Internal Server Error'. If it wants to return a specific + * error code, it should return 0 with the MIO_HTTPD_RSRC_ERROR + * resource. */ + mio_htts_discardcontent (req); + task = mio_htts_entaskerror(htts, client, MIO_NULL, 500, req); + } + else + { + + task = MIO_NULL; + + + if ((rsrc.flags & MIO_HTTPD_RSRC_100_CONTINUE) && + (task = mio_htts_entaskcontinue(htts, client, task, req)) == MIO_NULL) + { + /* inject '100 continue' first if it is needed */ + goto oops; + } + + /* arrange the actual resource to be returned */ + task = mio_htts_entaskrsrc(htts, client, task, &rsrc, req); + server_xtn->freersrc (htts, client, req, &rsrc); + + /* if the resource is indicating to return an error, + * discard the contents since i won't return them */ + if (rsrc.type == MIO_HTTPD_RSRC_ERROR) + { + mio_htre_discardcontent (req); + } + } + + if (task == MIO_NULL) goto oops; +#endif + } + } + else + { + /* contents are all received */ +mio_svc_htts_sendstatus (htts, csck, 500, mth, mio_htre_getversion(req), (req->flags & MIO_HTRE_ATTR_KEEPALIVE), MIO_NULL); +return 0; + + if (mth == MIO_HTTP_CONNECT) + { + MIO_DEBUG1 (htts->mio, "Switching HTRD to DUMMY for [%hs]\n", mio_htre_getqpath(req)); + + /* Switch the http read to a dummy mode so that the subsqeuent + * input(request) is just treated as data to the request just + * completed */ + mio_htrd_dummify (csckxtn->c.htrd); + +//////// +#if 0 + if (server_xtn->makersrc(htts, client, req, &rsrc) <= -1) + { + MIO_DEBUG1 (htts->mio, "Cannot make resource for [%hs]\n", mio_htre_getqpath(req)); + + /* failed to make a resource. just send the internal server error. + * the makersrc handler can return a negative number to return + * '500 Internal Server Error'. If it wants to return a specific + * error code, it should return 0 with the MIO_HTTPD_RSRC_ERROR + * resource. */ + task = mio_htts_entaskerror(htts, client, MIO_NULL, 500, req); + } + else + { + /* arrange the actual resource to be returned */ + task = mio_htts_entaskrsrc (htts, client, MIO_NULL, &rsrc, req); + server_xtn->freersrc (htts, client, req, &rsrc); + } + + if (task == MIO_NULL) goto oops; +#endif +//////// + } + else if (req->flags & MIO_HTRE_ATTR_PROXIED) + { + /* the contents should be proxied. + * do nothing locally */ + } + else + { + /* when the request is handled locally, + * there's nothing special to do here */ + } + } + + if (!(req->flags & MIO_HTRE_ATTR_KEEPALIVE) || mth == MIO_HTTP_CONNECT) + { + if (!peek) + { +//// task = mio_htts_entaskdisconnect(htts, client, MIO_NULL); +//// if (MIO_UNLIKELY(!task)) goto oops; + } + } + + return 0; + +oops: + /*mio_htts_markbadclient (htts, client);*/ + 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); + sck_xtn_t* sckxtn = (sck_xtn_t*)mio_dev_sck_getxtn(htrdxtn->sck); + return process_request(sckxtn->htts, htrdxtn->sck, req, 1); +// return xtn->htts->opt.rcb.peekreq(xtn->htts, xtn->client, req); +} + +static int client_htrd_poke_request (mio_htrd_t* htrd, mio_htre_t* req) +{ + htrd_xtn_t* htrdxtn = (htrd_xtn_t*)mio_htrd_getxtn(htrd); + sck_xtn_t* sckxtn = (sck_xtn_t*)mio_dev_sck_getxtn(htrdxtn->sck); + return process_request(sckxtn->htts, htrdxtn->sck, req, 0); +} + +static mio_htrd_recbs_t client_htrd_recbs = +{ + client_htrd_peek_request, + client_htrd_poke_request +}; + +static int init_client (mio_t* mio, mio_htts_client_t* c, mio_dev_sck_t* sck) +{ + htrd_xtn_t* htrdxtn; + + c->htrd = mio_htrd_open(mio, MIO_SIZEOF(*htrdxtn)); + if (MIO_UNLIKELY(!c->htrd)) goto oops; + + c->sbuf = mio_becs_open(mio, 0, 2048); + if (MIO_UNLIKELY(!c->sbuf)) goto oops; + htrdxtn = mio_htrd_getxtn(c->htrd); + htrdxtn->sck = sck; + + mio_htrd_setrecbs (c->htrd, &client_htrd_recbs); + + return 0; + +oops: + if (c->sbuf) + { + mio_becs_close(c->sbuf); + c->sbuf = MIO_NULL; + } + if (c->htrd) + { + mio_htrd_close (c->htrd); + c->htrd = MIO_NULL; + } + return -1; +} + +static void fini_client (mio_t* mio, mio_htts_client_t* c) +{ + if (c->sbuf) + { + mio_becs_close(c->sbuf); + c->sbuf = MIO_NULL; + } + if (c->htrd) + { + mio_htrd_close (c->htrd); + c->htrd = MIO_NULL; + } +} + +/* ------------------------------------------------------------------------ */ + static int client_on_read (mio_dev_sck_t* sck, const void* buf, mio_iolen_t len, const mio_skad_t* srcaddr) { sck_xtn_t* sckxtn = mio_dev_sck_getxtn(sck); @@ -36,7 +324,7 @@ printf ("** HTTS - client read %p %d -> htts:%p\n", sck, (int)len, sckxtn->ht { mio_dev_sck_halt (sck); } - else if (mio_htrd_feed(sckxtn->htrd, buf, len) <= -1) + else if (mio_htrd_feed(sckxtn->c.htrd, buf, len) <= -1) { mio_dev_sck_halt (sck); } @@ -49,12 +337,15 @@ static int client_on_write (mio_dev_sck_t* sck, mio_iolen_t wrlen, void* wrctx, return 0; } -static int client_on_disconnect (mio_dev_sck_t* sck) +static void client_on_disconnect (mio_dev_sck_t* sck) { + sck_xtn_t* sckxtn = mio_dev_sck_getxtn(sck); printf ("** HTTS - client disconnect %p\n", sck); + fini_client (sck->mio, &sckxtn->c); } /* ------------------------------------------------------------------------ */ + static int listener_on_read (mio_dev_sck_t* sck, const void* buf, mio_iolen_t len, const mio_skad_t* srcaddr) { return 0; @@ -72,31 +363,23 @@ static void listener_on_connect (mio_dev_sck_t* sck) if (sck->state & MIO_DEV_SCK_ACCEPTED) { /* accepted a new client */ - htrd_xtn_t* htrdxtn; - - printf ("** HTTS(%p) - accepted... %p %d \n", sckxtn->htts, sck, sck->sck); + MIO_DEBUG3 (sck->mio, "** HTTS(%p) - accepted... %p %d \n", sckxtn->htts, sck, sck->sck); /* the accepted socket inherits various event callbacks. switch some of them to avoid sharing */ sck->on_read = client_on_read; sck->on_write = client_on_write; sck->on_disconnect = client_on_disconnect; - sckxtn->htrd = mio_htrd_open(sck->mio, MIO_SIZEOF(*htrdxtn)); - if (MIO_UNLIKELY(!sckxtn->htrd)) + if (init_client(sck->mio, &sckxtn->c, sck) <= -1) { - MIO_INFO2 (sck->mio, "UNABLE TO OPEN HTTP READER FOR ACCEPTED SOCKET %p %d\n", sck, (int)sck->sck); + MIO_INFO2 (sck->mio, "UNABLE TO INITIALIZE NEW CLIENT %p %d\n", sck, (int)sck->sck); mio_dev_sck_halt (sck); } - else - { - htrdxtn = mio_htrd_getxtn(sckxtn->htrd); - htrdxtn->sck = sck; - } } else if (sck->state & MIO_DEV_SCK_CONNECTED) { /* this will never be triggered as the listing socket never call mio_dev_sck_connect() */ - printf ("** HTTS(%p) - connected... %p %d \n", sckxtn->htts, sck, sck->sck); + MIO_DEBUG3 (sck->mio, "** HTTS(%p) - connected... %p %d \n", sckxtn->htts, sck, sck->sck); } /* MIO_DEV_SCK_CONNECTED must not be seen here as this is only for the listener socket */ @@ -137,11 +420,11 @@ static void listener_on_disconnect (mio_dev_sck_t* sck) break; } - if (sckxtn->htrd) - { - mio_htrd_close (sckxtn->htrd); - sckxtn->htrd = 0; - } + + /* the client sockets are finalized in clinet_on_disconnect(). + * for a listener socket, these fields must be NULL */ + MIO_ASSERT (sck->mio, sckxtn->c.htrd == MIO_NULL); + MIO_ASSERT (sck->mio, sckxtn->c.sbuf == MIO_NULL); } @@ -226,3 +509,93 @@ void mio_svc_htts_stop (mio_svc_htts_t* htts) } +void mio_svc_htts_sendstatus (mio_svc_htts_t* htts, mio_dev_sck_t* csck, int status_code, mio_http_method_t method, const mio_http_version_t* version, int keepalive, void* extra) +{ + sck_xtn_t* csckxtn = mio_dev_sck_getxtn(csck); + mio_bch_t text[1024]; /* TODO: make this buffer dynamic or scalable */ + mio_bch_t dtbuf[64]; + + const mio_bch_t* extrapre = ""; + const mio_bch_t* extrapst = ""; + const mio_bch_t* extraval = ""; + + + text[0] = '\0'; + + switch (status_code) + { +#if 0 + case 301: /* Moved Permanently */ + case 302: /* Found */ + case 303: /* See Other (since HTTP/1.1) */ + case 307: /* Temporary Redirect (since HTTP/1.1) */ + case 308: /* Permanent Redirect (Experimental RFC; RFC 7238) */ + { + mio_svc_htts_rsrc_reloc_t* reloc; + reloc = (mio_htts_rsrc_reloc_t*)extra; + extrapre = "Location: "; + extrapst = (reloc->flags & MIO_SVC_HTTS_RSRC_RELOC_APPENDSLASH)? "/\r\n": "\r\n"; + extraval = reloc->target; + break; + } +#endif + + case 304: + case 200: + case 201: + case 202: + case 203: + case 204: + case 205: + case 206: + /* nothing to do */ + break; + + + default: +#if 0 + if (method != MIO_HTTP_HEAD && + htts->opt.rcb.fmterr(htts, client, code, text, MIO_COUNTOF(text)) <= -1) return QSE_NULL; +#endif + + if (status_code == 401) + { + extrapre = "WWW-Authenticate: Basic realm=\""; + extrapst = "\"\r\n"; + extraval = (const mio_bch_t*)extra; + } + + break; + } + + + mio_svc_htts_fmtgmtime(htts, MIO_NULL, dtbuf, MIO_COUNTOF(dtbuf)); + + mio_becs_fmt (csckxtn->c.sbuf, "HTTP/%d.%d %d %s\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: %u\r\n%s%s%s\r\n%s", + version->major, version->minor, status_code, mio_http_status_to_bcstr(status_code), + "SERVER-NAME", /* TODO: use actual name mio_svc_htts_getservername(). */ + dtbuf, /* DATE */ + (keepalive? "keep-alive": "close"), /* connection */ + mio_count_bcstr(text), /* content length */ + extrapre, extraval, extraval, text + ); + + if (mio_dev_sck_write(csck, MIO_BECS_PTR(csckxtn->c.sbuf), MIO_BECS_LEN(csckxtn->c.sbuf), MIO_NULL, MIO_NULL) <= -1) + { + mio_dev_sck_halt (csck); + } +} + + +void mio_svc_htts_fmtgmtime (mio_svc_htts_t* htts, const mio_ntime_t* nt, mio_bch_t* buf, mio_oow_t len) +{ + mio_ntime_t now; + + if (!nt) + { + mio_sys_getrealtime(htts->mio, &now); + nt = &now; + } + + mio_fmt_http_time_to_bcstr(nt, buf, len); +} diff --git a/mio/lib/http.c b/mio/lib/http.c index d32468d..a13dba4 100644 --- a/mio/lib/http.c +++ b/mio/lib/http.c @@ -380,9 +380,8 @@ mio_bch_t* mio_fmt_http_time_to_bcstr (const mio_ntime_t* nt, mio_bch_t* buf, mi struct tm bt; t = nt->sec; - gmtime_r (&t, &bt); + gmtime_r (&t, &bt); /* TODO: create mio_sys_gmtime() and make it system dependent */ - /* mio_fmttobcstr() works well with MIO_NULL in mio if formatting doesn't involve cross-encoding */ mio_fmttobcstr (MIO_NULL, buf, bufsz, "%hs, %d %hs %d %02d:%02d:%02d GMT", wday_name[bt.tm_wday].s, @@ -418,7 +417,7 @@ int mio_is_perenced_http_bcstr (const mio_bch_t* str) return 1; } -mio_oow_t mio_perdechttpstr (const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* ndecs) +mio_oow_t mio_perdec_http_bcstr (const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* ndecs) { const mio_bch_t* p = str; mio_bch_t* out = buf; @@ -460,7 +459,7 @@ mio_oow_t mio_perdechttpstr (const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* nd #define TO_HEX(v) ("0123456789ABCDEF"[(v) & 15]) -mio_oow_t mio_perenchttpstr (int opt, const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* nencs) +mio_oow_t mio_perenc_http_bcstr (int opt, const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* nencs) { const mio_bch_t* p = str; mio_bch_t* out = buf; @@ -469,7 +468,7 @@ mio_oow_t mio_perenchttpstr (int opt, const mio_bch_t* str, mio_bch_t* buf, mio_ /* this function doesn't accept the size of the buffer. the caller must * ensure that the buffer is large enough */ - if (opt & MIO_PERENCHTTPSTR_KEEP_SLASH) + if (opt & MIO_PERENC_HTTP_KEEP_SLASH) { while (*p != '\0') { @@ -504,14 +503,15 @@ mio_oow_t mio_perenchttpstr (int opt, const mio_bch_t* str, mio_bch_t* buf, mio_ return out - buf; } -mio_bch_t* mio_perenchttpstrdup (int opt, const mio_bch_t* str, mio_mmgr_t* mmgr) +#if 0 +mio_bch_t* mio_perenc_http_bcstrdup (int opt, const mio_bch_t* str, mio_mmgr_t* mmgr) { mio_bch_t* buf; mio_oow_t len = 0; mio_oow_t count = 0; /* count the number of characters that should be encoded */ - if (opt & MIO_PERENCHTTPSTR_KEEP_SLASH) + if (opt & MIO_PERENC_HTTP_KEEP_SLASH) { for (len = 0; str[len] != '\0'; len++) { @@ -530,11 +530,12 @@ mio_bch_t* mio_perenchttpstrdup (int opt, const mio_bch_t* str, mio_mmgr_t* mmgr if (count <= 0) return (mio_bch_t*)str; /* allocate a buffer of an optimal size for escaping, otherwise */ - buf = MIO_MMGR_ALLOC (mmgr, (len + (count * 2) + 1) * MIO_SIZEOF(*buf)); - if (buf == MIO_NULL) return MIO_NULL; + buf = MIO_MMGR_ALLOC(mmgr, (len + (count * 2) + 1) * MIO_SIZEOF(*buf)); + if (!buf) return MIO_NULL; /* perform actual escaping */ - mio_perenchttpstr (opt, str, buf, MIO_NULL); + mio_perenc_http_bcstr (opt, str, buf, MIO_NULL); return buf; } +#endif diff --git a/mio/lib/mio-htre.h b/mio/lib/mio-htre.h index 921d79a..6608d09 100644 --- a/mio/lib/mio-htre.h +++ b/mio/lib/mio-htre.h @@ -49,15 +49,15 @@ typedef enum mio_htre_state_t mio_htre_state_t; typedef int (*mio_htre_concb_t) ( mio_htre_t* re, - const mio_bch_t* ptr, - mio_oow_t len, + const mio_bch_t* ptr, + mio_oow_t len, void* ctx ); struct mio_htre_hdrval_t { - const mio_bch_t* ptr; - mio_oow_t len; + const mio_bch_t* ptr; + mio_oow_t len; mio_htre_hdrval_t* next; }; diff --git a/mio/lib/mio-http.h b/mio/lib/mio-http.h index d933be5..19cedfa 100644 --- a/mio/lib/mio-http.h +++ b/mio/lib/mio-http.h @@ -148,11 +148,11 @@ struct mio_http_range_t typedef struct mio_http_range_t mio_http_range_t; -enum mio_perenchttpstr_opt_t +enum mio_perenc_http_opt_t { - MIO_PERENCHTTPSTR_KEEP_SLASH = (1 << 0) + MIO_PERENC_HTTP_KEEP_SLASH = (1 << 0) }; -typedef enum mio_perenchttpstr_opt_t mio_perenchttpstr_opt_t; +typedef enum mio_perenc_http_opt_t mio_perenc_bcstr_opt_t; /* -------------------------------------------------------------- */ @@ -210,37 +210,40 @@ MIO_EXPORT int mio_is_perenced_http_bcstr ( ); /** - * The mio_perdechttpstr() function performs percent-decoding over a string. + * The mio_perdec_http_bcstr() function performs percent-decoding over a string. * The caller must ensure that the output buffer \a buf is large enough. * If \a ndecs is not #MIO_NULL, it is set to the number of characters * decoded. 0 means no characters in the input string required decoding * \return the length of the output string. */ -MIO_EXPORT mio_oow_t mio_perdechttpstr ( +MIO_EXPORT mio_oow_t mio_perdec_http_bcstr ( const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* ndecs ); /** - * The mio_perenchttpstr() function performs percent-encoding over a string. + * The mio_perenc_http_bcstr() function performs percent-encoding over a string. * The caller must ensure that the output buffer \a buf is large enough. * If \a nencs is not #MIO_NULL, it is set to the number of characters * encoded. 0 means no characters in the input string required encoding. * \return the length of the output string. */ -MIO_EXPORT mio_oow_t mio_perenchttpstr ( - int opt, /**< 0 or bitwise-OR'ed of #mio_perenchttpstr_opt_t */ +MIO_EXPORT mio_oow_t mio_perenc_http_bcstr ( + int opt, /**< 0 or bitwise-OR'ed of #mio_perenc_http_bcstr_opt_t */ const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* nencs ); -MIO_EXPORT mio_bch_t* mio_perenchttpstrdup ( - int opt, /**< 0 or bitwise-OR'ed of #mio_perenchttpstr_opt_t */ +#if 0 +/* TODO: rename this function according to the naming convension */ +MIO_EXPORT mio_bch_t* mio_perenc_http_bcstrdup ( + int opt, /**< 0 or bitwise-OR'ed of #mio_perenc_http_bcstr_opt_t */ const mio_bch_t* str, mio_mmgr_t* mmgr ); +#endif /* ------------------------------------------------------------------------- */ /* HTTP SERVER SERVICE */ @@ -255,6 +258,24 @@ MIO_EXPORT void mio_svc_htts_stop ( mio_svc_htts_t* htts ); + +MIO_EXPORT void mio_svc_htts_sendstatus ( + mio_svc_htts_t* htts, + mio_dev_sck_t* csck, + int status_code, + mio_http_method_t method, + const mio_http_version_t* version, + int keepalive, + void* extra +); + +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 +); + #if defined(__cplusplus) } #endif diff --git a/mio/lib/mio-prv.h b/mio/lib/mio-prv.h index ffbc572..d452742 100644 --- a/mio/lib/mio-prv.h +++ b/mio/lib/mio-prv.h @@ -183,6 +183,11 @@ void mio_sys_gettime ( mio_ntime_t* now ); +void mio_sys_getrealtime ( + mio_t* mio, + mio_ntime_t* now +); + #ifdef __cplusplus } #endif diff --git a/mio/lib/mio.c b/mio/lib/mio.c index 1e3fbd9..ce59419 100644 --- a/mio/lib/mio.c +++ b/mio/lib/mio.c @@ -1592,11 +1592,9 @@ static int fmt_put_bchars_to_uch_buf (mio_fmtout_t* fmtout, const mio_bch_t* ptr mio_oow_t bcslen, ucslen; int n; - if (!b->mio) return -1; /* no mio, no cross encoding formatting */ - bcslen = len; ucslen = b->capa - b->len; - n = mio_conv_bchars_to_uchars_with_cmgr(ptr, &bcslen, &b->ptr[b->len], &ucslen, b->mio->_cmgr, 1); + n = mio_conv_bchars_to_uchars_with_cmgr(ptr, &bcslen, &b->ptr[b->len], &ucslen, (b->mio? b->mio->_cmgr: mio_get_utf8_cmgr()), 1); b->len += ucslen; if (n <= -1) { @@ -1703,11 +1701,9 @@ static int fmt_put_uchars_to_bch_buf (mio_fmtout_t* fmtout, const mio_uch_t* ptr mio_oow_t bcslen, ucslen; int n; - if (!b->mio) return -1; /* no mio, no cross encoding formatting */ - bcslen = b->capa - b->len; ucslen = len; - n = mio_conv_uchars_to_bchars_with_cmgr(ptr, &ucslen, &b->ptr[b->len], &bcslen, b->mio->_cmgr); + n = mio_conv_uchars_to_bchars_with_cmgr(ptr, &ucslen, &b->ptr[b->len], &bcslen, (b->mio? b->mio->_cmgr: mio_get_utf8_cmgr())); b->len += bcslen; if (n <= -1) { @@ -1742,7 +1738,6 @@ mio_oow_t mio_vfmttobcstr (mio_t* mio, mio_bch_t* buf, mio_oow_t bufsz, const mi fb.mio = mio; fb.ptr = buf; fb.capa = bufsz - 1; - if (mio_bfmt_outv(&fo, fmt, ap) <= -1) return -1; buf[fb.len] = '\0'; diff --git a/mio/lib/sys-tim.c b/mio/lib/sys-tim.c index bbe1ea6..b4e5a1a 100644 --- a/mio/lib/sys-tim.c +++ b/mio/lib/sys-tim.c @@ -151,3 +151,17 @@ void mio_sys_gettime (mio_t* mio, mio_ntime_t* now) MIO_INIT_NTIME(now, tv.tv_sec, MIO_USEC_TO_NSEC(tv.tv_usec)); #endif } + + +void mio_sys_getrealtime (mio_t* mio, mio_ntime_t* now) +{ +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) + struct timespec ts; + clock_gettime (CLOCK_REALTIME, &ts); + MIO_INIT_NTIME(now, ts.tv_sec, ts.tv_nsec); +#else + struct timeval tv; + gettimeofday (&tv, MIO_NULL); + MIO_INIT_NTIME(now, tv.tv_sec, MIO_USEC_TO_NSEC(tv.tv_usec)); +#endif +}