added some files for future work

This commit is contained in:
hyung-hwan 2020-03-03 13:47:51 +00:00
parent 252c801544
commit 1a8cb3610b
10 changed files with 3316 additions and 6 deletions

View File

@ -14,7 +14,7 @@ LDFLAGS_ALL_COMMON = -L$(abs_builddir) -L$(abs_builddir)/../lib -L$(libdir)
##################################################
CPPFLAGS_LIB_COMMON = $(CPPFLAGS_ALL_COMMON)
LDFLAGS_LIB_COMMON = $(LDFLAGS_ALL_COMMON) -version-info 1:0:0 -no-undefined
LDFLAGS_LIB_COMMON = $(LDFLAGS_ALL_COMMON) -no-undefined
LIBADD_LIB_COMMON = $(LIBM)
bin_PROGRAMS = mio-execd

View File

@ -359,7 +359,7 @@ LDFLAGS_ALL_COMMON = -L$(abs_builddir) -L$(abs_builddir)/../lib -L$(libdir)
# MAIN LIBRARY
##################################################
CPPFLAGS_LIB_COMMON = $(CPPFLAGS_ALL_COMMON)
LDFLAGS_LIB_COMMON = $(LDFLAGS_ALL_COMMON) -version-info 1:0:0 -no-undefined
LDFLAGS_LIB_COMMON = $(LDFLAGS_ALL_COMMON) -no-undefined
LIBADD_LIB_COMMON = $(LIBM)
mio_execd_SOURCES = execd.c
mio_execd_CPPFLAGS = $(CPPFLAGS_LIB_COMMON)

1735
mio/lib/htrd.c Normal file

File diff suppressed because it is too large Load Diff

320
mio/lib/htre.c Normal file
View File

@ -0,0 +1,320 @@
/*
* $Id$
*
Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <mio-htre.h>
#include "mio-prv.h"
static void free_hdrval (mio_htb_t* htb, void* vptr, mio_size_t vlen)
{
mio_htre_hdrval_t* val;
mio_htre_hdrval_t* tmp;
val = vptr;
while (val)
{
tmp = val;
val = val->next;
MIO_MMGR_FREE (htb->mmgr, tmp);
}
}
int mio_htre_init (mio_htre_t* re, mio_mmgr_t* mmgr)
{
static mio_htb_style_t style =
{
{
MIO_HTB_COPIER_DEFAULT,
MIO_HTB_COPIER_DEFAULT
},
{
MIO_HTB_FREEER_DEFAULT,
free_hdrval
},
MIO_HTB_COMPER_DEFAULT,
MIO_HTB_KEEPER_DEFAULT,
MIO_HTB_SIZER_DEFAULT,
MIO_HTB_HASHER_DEFAULT
};
MIO_MEMSET (re, 0, MIO_SIZEOF(*re));
re->mmgr = mmgr;
if (mio_htb_init (&re->hdrtab, mmgr, 60, 70, 1, 1) <= -1) return -1;
if (mio_htb_init (&re->trailers, mmgr, 20, 70, 1, 1) <= -1) return -1;
mio_htb_setstyle (&re->hdrtab, &style);
mio_htb_setstyle (&re->trailers, &style);
mio_mbs_init (&re->content, mmgr, 0);
#if 0
mio_mbs_init (&re->iniline, mmgr, 0);
#endif
return 0;
}
void mio_htre_fini (mio_htre_t* re)
{
#if 0
mio_mbs_fini (&re->iniline);
#endif
mio_mbs_fini (&re->content);
mio_htb_fini (&re->trailers);
mio_htb_fini (&re->hdrtab);
if (re->orgqpath.buf)
MIO_MMGR_FREE (re->mmgr, re->orgqpath.buf);
}
void mio_htre_clear (mio_htre_t* re)
{
if (!(re->state & MIO_HTRE_COMPLETED) &&
!(re->state & MIO_HTRE_DISCARDED))
{
if (re->concb)
{
re->concb (re, MIO_NULL, 0, re->concb_ctx); /* indicate end of content */
mio_htre_unsetconcb (re);
}
}
re->state = 0;
re->flags = 0;
re->orgqpath.ptr = MIO_NULL;
re->orgqpath.len = 0;
MIO_MEMSET (&re->version, 0, MIO_SIZEOF(re->version));
MIO_MEMSET (&re->attr, 0, MIO_SIZEOF(re->attr));
mio_htb_clear (&re->hdrtab);
mio_htb_clear (&re->trailers);
mio_mbs_clear (&re->content);
#if 0
mio_mbs_clear (&re->iniline);
#endif
}
const mio_htre_hdrval_t* mio_htre_getheaderval (
const mio_htre_t* re, const mio_mchar_t* name)
{
mio_htb_pair_t* pair;
pair = mio_htb_search (&re->hdrtab, name, mio_mbslen(name));
if (pair == MIO_NULL) return MIO_NULL;
return MIO_HTB_VPTR(pair);
}
const mio_htre_hdrval_t* mio_htre_gettrailerval (
const mio_htre_t* re, const mio_mchar_t* name)
{
mio_htb_pair_t* pair;
pair = mio_htb_search (&re->trailers, name, mio_mbslen(name));
if (pair == MIO_NULL) return MIO_NULL;
return MIO_HTB_VPTR(pair);
}
struct header_walker_ctx_t
{
mio_htre_t* re;
mio_htre_header_walker_t walker;
void* ctx;
int ret;
};
static mio_htb_walk_t walk_headers (
mio_htb_t* htb, mio_htb_pair_t* pair, void* ctx)
{
struct header_walker_ctx_t* hwctx = (struct header_walker_ctx_t*)ctx;
if (hwctx->walker (hwctx->re, MIO_HTB_KPTR(pair), MIO_HTB_VPTR(pair), hwctx->ctx) <= -1)
{
hwctx->ret = -1;
return MIO_HTB_WALK_STOP;
}
return MIO_HTB_WALK_FORWARD;
}
int mio_htre_walkheaders (
mio_htre_t* re, mio_htre_header_walker_t walker, void* ctx)
{
struct header_walker_ctx_t hwctx;
hwctx.re = re;
hwctx.walker = walker;
hwctx.ctx = ctx;
hwctx.ret = 0;
mio_htb_walk (&re->hdrtab, walk_headers, &hwctx);
return hwctx.ret;
}
int mio_htre_walktrailers (
mio_htre_t* re, mio_htre_header_walker_t walker, void* ctx)
{
struct header_walker_ctx_t hwctx;
hwctx.re = re;
hwctx.walker = walker;
hwctx.ctx = ctx;
hwctx.ret = 0;
mio_htb_walk (&re->trailers, walk_headers, &hwctx);
return hwctx.ret;
}
int mio_htre_addcontent (
mio_htre_t* re, const mio_mchar_t* ptr, mio_size_t len)
{
/* see comments in mio_htre_discardcontent() */
if (re->state & (MIO_HTRE_COMPLETED | MIO_HTRE_DISCARDED)) return 0; /* skipped */
if (re->concb)
{
/* if the callback is set, the content goes to the callback. */
if (re->concb (re, ptr, len, re->concb_ctx) <= -1) return -1;
}
else
{
/* if the callback is not set, the contents goes to the internal buffer */
if (mio_mbs_ncat (&re->content, ptr, len) == (mio_size_t)-1) return -1;
}
return 1; /* added successfully */
}
void mio_htre_completecontent (mio_htre_t* re)
{
/* see comments in mio_htre_discardcontent() */
if (!(re->state & MIO_HTRE_COMPLETED) &&
!(re->state & MIO_HTRE_DISCARDED))
{
re->state |= MIO_HTRE_COMPLETED;
if (re->concb)
{
/* indicate end of content */
re->concb (re, MIO_NULL, 0, re->concb_ctx);
}
}
}
void mio_htre_discardcontent (mio_htre_t* re)
{
/* you can't discard this if it's completed.
* you can't complete this if it's discarded
* you can't add contents to this if it's completed or discarded
*/
if (!(re->state & MIO_HTRE_COMPLETED) &&
!(re->state & MIO_HTRE_DISCARDED))
{
re->state |= MIO_HTRE_DISCARDED;
/* mio_htre_addcontent()...
* mio_thre_setconcb()...
* mio_htre_discardcontent()... <-- POINT A.
*
* at point A, the content must contain something
* and concb is also set. for simplicity,
* clear the content buffer and invoke the callback
*
* likewise, you may produce many weird combinations
* of these functions. however, these functions are
* designed to serve a certain usage pattern not including
* weird combinations.
*/
mio_mbs_clear (&re->content);
if (re->concb)
{
/* indicate end of content */
re->concb (re, MIO_NULL, 0, re->concb_ctx);
}
}
}
void mio_htre_unsetconcb (mio_htre_t* re)
{
re->concb = MIO_NULL;
re->concb_ctx = MIO_NULL;
}
void mio_htre_setconcb (mio_htre_t* re, mio_htre_concb_t concb, void* ctx)
{
re->concb = concb;
re->concb_ctx = ctx;
}
int mio_htre_perdecqpath (mio_htre_t* re)
{
mio_size_t dec_count;
/* percent decode the query path*/
if (re->type != MIO_HTRE_Q || (re->flags & MIO_HTRE_QPATH_PERDEC)) return -1;
MIO_ASSERT (re->orgqpath.len <= 0);
MIO_ASSERT (re->orgqpath.ptr == MIO_NULL);
if (mio_isperencedhttpstr(re->u.q.path.ptr))
{
/* the string is percent-encoded. keep the original request
* in a separately allocated buffer */
if (re->orgqpath.buf && re->u.q.path.len <= re->orgqpath.capa)
{
re->orgqpath.len = mio_mbscpy (re->orgqpath.buf, re->u.q.path.ptr);
re->orgqpath.ptr = re->orgqpath.buf;
}
else
{
if (re->orgqpath.buf)
{
MIO_MMGR_FREE (re->mmgr, re->orgqpath.buf);
re->orgqpath.capa = 0;
}
re->orgqpath.buf = mio_mbsxdup (re->u.q.path.ptr, re->u.q.path.len, re->mmgr);
if (!re->orgqpath.buf) return -1;
re->orgqpath.capa = re->u.q.path.len;
re->orgqpath.ptr = re->orgqpath.buf;
re->orgqpath.len = re->orgqpath.capa;
/* orgqpath.buf and orgqpath.ptr are the same here. the caller
* is free to change orgqpath.ptr to point to a differnt position
* in the buffer. */
}
}
re->u.q.path.len = mio_perdechttpstr (re->u.q.path.ptr, re->u.q.path.ptr, &dec_count);
if (dec_count > 0)
{
/* this assertion is to ensure that mio_isperencedhttpstr()
* returned true when dec_count is greater than 0 */
MIO_ASSERT (re->orgqpath.buf != MIO_NULL);
MIO_ASSERT (re->orgqpath.ptr != MIO_NULL);
re->flags |= MIO_HTRE_QPATH_PERDEC;
}
return 0;
}

534
mio/lib/http.c Normal file
View File

@ -0,0 +1,534 @@
/*
Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <mio-http.h>
#include "mio-prv.h"
int mio_comparehttpversions (
const mio_http_version_t* v1,
const mio_http_version_t* v2)
{
if (v1->major == v2->major) return v1->minor - v2->minor;
return v1->major - v2->major;
}
const mio_mchar_t* mio_httpstatustombs (int code)
{
const mio_mchar_t* msg;
switch (code)
{
case 100: msg = "Continue"; break;
case 101: msg = "Switching Protocols"; break;
case 200: msg = "OK"; break;
case 201: msg = "Created"; break;
case 202: msg = "Accepted"; break;
case 203: msg = "Non-Authoritative Information"; break;
case 204: msg = "No Content"; break;
case 205: msg = "Reset Content"; break;
case 206: msg = "Partial Content"; break;
case 300: msg = "Multiple Choices"; break;
case 301: msg = "Moved Permanently"; break;
case 302: msg = "Found"; break;
case 303: msg = "See Other"; break;
case 304: msg = "Not Modified"; break;
case 305: msg = "Use Proxy"; break;
case 307: msg = "Temporary Redirect"; break;
case 308: msg = "Permanent Redirect"; break;
case 400: msg = "Bad Request"; break;
case 401: msg = "Unauthorized"; break;
case 402: msg = "Payment Required"; break;
case 403: msg = "Forbidden"; break;
case 404: msg = "Not Found"; break;
case 405: msg = "Method Not Allowed"; break;
case 406: msg = "Not Acceptable"; break;
case 407: msg = "Proxy Authentication Required"; break;
case 408: msg = "Request Timeout"; break;
case 409: msg = "Conflict"; break;
case 410: msg = "Gone"; break;
case 411: msg = "Length Required"; break;
case 412: msg = "Precondition Failed"; break;
case 413: msg = "Request Entity Too Large"; break;
case 414: msg = "Request-URI Too Long"; break;
case 415: msg = "Unsupported Media Type"; break;
case 416: msg = "Requested Range Not Satisfiable"; break;
case 417: msg = "Expectation Failed"; break;
case 426: msg = "Upgrade Required"; break;
case 428: msg = "Precondition Required"; break;
case 429: msg = "Too Many Requests"; break;
case 431: msg = "Request Header Fields Too Large"; break;
case 500: msg = "Internal Server Error"; break;
case 501: msg = "Not Implemented"; break;
case 502: msg = "Bad Gateway"; break;
case 503: msg = "Service Unavailable"; break;
case 504: msg = "Gateway Timeout"; break;
case 505: msg = "HTTP Version Not Supported"; break;
default: msg = "Unknown Error"; break;
}
return msg;
}
const mio_mchar_t* mio_httpmethodtombs (mio_http_method_t type)
{
/* keep this table in the same order as mio_httpd_method_t enumerators */
static mio_mchar_t* names[] =
{
"OTHER",
"HEAD",
"GET",
"POST",
"PUT",
"DELETE",
"OPTIONS",
"TRACE",
"CONNECT"
};
return (type < 0 || type >= MIO_COUNTOF(names))? MIO_NULL: names[type];
}
struct mtab_t
{
const mio_mchar_t* name;
mio_http_method_t type;
};
static struct mtab_t mtab[] =
{
/* keep this table sorted by name for binary search */
{ "CONNECT", MIO_HTTP_CONNECT },
{ "DELETE", MIO_HTTP_DELETE },
{ "GET", MIO_HTTP_GET },
{ "HEAD", MIO_HTTP_HEAD },
{ "OPTIONS", MIO_HTTP_OPTIONS },
{ "POST", MIO_HTTP_POST },
{ "PUT", MIO_HTTP_PUT },
{ "TRACE", MIO_HTTP_TRACE }
};
mio_http_method_t mio_mbstohttpmethod (const mio_mchar_t* name)
{
/* perform binary search */
/* declaring left, right, mid to be of int is ok
* because we know mtab is small enough. */
int left = 0, right = MIO_COUNTOF(mtab) - 1, mid;
while (left <= right)
{
int n;
struct mtab_t* entry;
/*mid = (left + right) / 2;*/
mid = left + (right - left) / 2;
entry = &mtab[mid];
n = mio_mbscmp (name, entry->name);
if (n < 0)
{
/* if left, right, mid were of mio_size_t,
* you would need the following line.
if (mid == 0) break;
*/
right = mid - 1;
}
else if (n > 0) left = mid + 1;
else return entry->type;
}
return MIO_HTTP_OTHER;
}
mio_http_method_t mio_mcstrtohttpmethod (const mio_mcstr_t* name)
{
/* perform binary search */
/* declaring left, right, mid to be of int is ok
* because we know mtab is small enough. */
int left = 0, right = MIO_COUNTOF(mtab) - 1, mid;
while (left <= right)
{
int n;
struct mtab_t* entry;
/*mid = (left + right) / 2;*/
mid = left + (right - left) / 2;
entry = &mtab[mid];
n = mio_mbsxcmp (name->ptr, name->len, entry->name);
if (n < 0)
{
/* if left, right, mid were of mio_size_t,
* you would need the following line.
if (mid == 0) break;
*/
right = mid - 1;
}
else if (n > 0) left = mid + 1;
else return entry->type;
}
return MIO_HTTP_OTHER;
}
int mio_parsehttprange (const mio_mchar_t* str, mio_http_range_t* range)
{
/* NOTE: this function does not support a range set
* like bytes=1-20,30-50 */
mio_http_range_int_t from, to;
int type = MIO_HTTP_RANGE_PROPER;
if (str[0] != 'b' ||
str[1] != 'y' ||
str[2] != 't' ||
str[3] != 'e' ||
str[4] != 's' ||
str[5] != '=') return -1;
str += 6;
from = 0;
if (MIO_ISMDIGIT(*str))
{
do
{
from = from * 10 + (*str - '0');
str++;
}
while (MIO_ISMDIGIT(*str));
}
else type = MIO_HTTP_RANGE_SUFFIX;
if (*str != '-') return -1;
str++;
if (MIO_ISMDIGIT(*str))
{
to = 0;
do
{
to = to * 10 + (*str - '0');
str++;
}
while (MIO_ISMDIGIT(*str));
}
else to = MIO_TYPE_MAX(mio_http_range_int_t);
if (from > to) return -1;
range->type = type;
range->from = from;
range->to = to;
return 0;
}
typedef struct mname_t mname_t;
struct mname_t
{
const mio_mchar_t* s;
const mio_mchar_t* l;
};
static mname_t wday_name[] =
{
{ "Sun", "Sunday" },
{ "Mon", "Monday" },
{ "Tue", "Tuesday" },
{ "Wed", "Wednesday" },
{ "Thu", "Thursday" },
{ "Fri", "Friday" },
{ "Sat", "Saturday" }
};
static mname_t mon_name[] =
{
{ "Jan", "January" },
{ "Feb", "February" },
{ "Mar", "March" },
{ "Apr", "April" },
{ "May", "May" },
{ "Jun", "June" },
{ "Jul", "July" },
{ "Aug", "August" },
{ "Sep", "September" },
{ "Oct", "October" },
{ "Nov", "November" },
{ "Dec", "December" }
};
int mio_parsehttptime (const mio_mchar_t* str, mio_ntime_t* nt)
{
mio_btime_t bt;
const mio_mchar_t* word;
mio_size_t wlen, i;
/* TODO: support more formats */
MIO_MEMSET (&bt, 0, MIO_SIZEOF(bt));
/* weekday */
while (MIO_ISMSPACE(*str)) str++;
for (word = str; MIO_ISMALPHA(*str); str++);
wlen = str - word;
for (i = 0; i < MIO_COUNTOF(wday_name); i++)
{
if (mio_mbsxcmp (word, wlen, wday_name[i].s) == 0)
{
bt.wday = i;
break;
}
}
if (i >= MIO_COUNTOF(wday_name)) return -1;
/* comma - i'm just loose as i don't care if it doesn't exist */
while (MIO_ISMSPACE(*str)) str++;
if (*str == ',') str++;
/* day */
while (MIO_ISMSPACE(*str)) str++;
if (!MIO_ISMDIGIT(*str)) return -1;
do bt.mday = bt.mday * 10 + *str++ - '0'; while (MIO_ISMDIGIT(*str));
/* month */
while (MIO_ISMSPACE(*str)) str++;
for (word = str; MIO_ISMALPHA(*str); str++);
wlen = str - word;
for (i = 0; i < MIO_COUNTOF(mon_name); i++)
{
if (mio_mbsxcmp (word, wlen, mon_name[i].s) == 0)
{
bt.mon = i;
break;
}
}
if (i >= MIO_COUNTOF(mon_name)) return -1;
/* year */
while (MIO_ISMSPACE(*str)) str++;
if (!MIO_ISMDIGIT(*str)) return -1;
do bt.year = bt.year * 10 + *str++ - '0'; while (MIO_ISMDIGIT(*str));
bt.year -= MIO_BTIME_YEAR_BASE;
/* hour */
while (MIO_ISMSPACE(*str)) str++;
if (!MIO_ISMDIGIT(*str)) return -1;
do bt.hour = bt.hour * 10 + *str++ - '0'; while (MIO_ISMDIGIT(*str));
if (*str != ':') return -1;
str++;
/* min */
while (MIO_ISMSPACE(*str)) str++;
if (!MIO_ISMDIGIT(*str)) return -1;
do bt.min = bt.min * 10 + *str++ - '0'; while (MIO_ISMDIGIT(*str));
if (*str != ':') return -1;
str++;
/* sec */
while (MIO_ISMSPACE(*str)) str++;
if (!MIO_ISMDIGIT(*str)) return -1;
do bt.sec = bt.sec * 10 + *str++ - '0'; while (MIO_ISMDIGIT(*str));
/* GMT */
while (MIO_ISMSPACE(*str)) str++;
for (word = str; MIO_ISMALPHA(*str); str++);
wlen = str - word;
if (mio_mbsxcmp (word, wlen, "GMT" != 0) return -1;
while (MIO_ISMSPACE(*str)) str++;
if (*str != '\0') return -1;
return mio_timegm (&bt, nt);
}
mio_mchar_t* mio_fmthttptime (const mio_ntime_t* nt, mio_mchar_t* buf, mio_size_t bufsz)
{
mio_btime_t bt;
mio_gmtime (nt, &bt);
mio_mbsxfmt (
buf, bufsz,
"%s, %d %s %d %02d:%02d:%02d GMT",
wday_name[bt.wday].s,
bt.mday,
mon_name[bt.mon].s,
bt.year + MIO_BTIME_YEAR_BASE,
bt.hour, bt.min, bt.sec
);
return buf;
}
int mio_isperencedhttpstr (const mio_mchar_t* str)
{
const mio_mchar_t* p = str;
while (*p != '\0')
{
if (*p == '%' && *(p + 1) != '\0' && *(p + 2) != '\0')
{
int q = MIO_MXDIGITTONUM (*(p + 1));
if (q >= 0)
{
/* return true if the first valid percent-encoded sequence is found */
int w = MIO_MXDIGITTONUM (*(p + 2));
if (w >= 0) return 1;
}
}
p++;
}
return 1;
}
mio_size_t mio_perdechttpstr (const mio_mchar_t* str, mio_mchar_t* buf, mio_size_t* ndecs)
{
const mio_mchar_t* p = str;
mio_mchar_t* out = buf;
mio_size_t dec_count = 0;
while (*p != '\0')
{
if (*p == '%' && *(p + 1) != '\0' && *(p + 2) != '\0')
{
int q = MIO_MXDIGITTONUM (*(p + 1));
if (q >= 0)
{
int w = MIO_MXDIGITTONUM (*(p + 2));
if (w >= 0)
{
/* we don't care if it contains a null character */
*out++ = ((q << 4) + w);
p += 3;
dec_count++;
continue;
}
}
}
*out++ = *p++;
}
*out = '\0';
if (ndecs) *ndecs = dec_count;
return out - buf;
}
#define IS_UNRESERVED(c) \
(((c) >= 'A' && (c) <= 'Z') || \
((c) >= 'a' && (c) <= 'z') || \
((c) >= '0' && (c) <= '9') || \
(c) == '-' || (c) == '_' || \
(c) == '.' || (c) == '~')
#define TO_HEX(v) ("0123456789ABCDEF"[(v) & 15])
mio_size_t mio_perenchttpstr (int opt, const mio_mchar_t* str, mio_mchar_t* buf, mio_size_t* nencs)
{
const mio_mchar_t* p = str;
mio_mchar_t* out = buf;
mio_size_t enc_count = 0;
/* 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)
{
while (*p != '\0')
{
if (IS_UNRESERVED(*p) || *p == '/') *out++ = *p;
else
{
*out++ = '%';
*out++ = TO_HEX (*p >> 4);
*out++ = TO_HEX (*p & 15);
enc_count++;
}
p++;
}
}
else
{
while (*p != '\0')
{
if (IS_UNRESERVED(*p)) *out++ = *p;
else
{
*out++ = '%';
*out++ = TO_HEX (*p >> 4);
*out++ = TO_HEX (*p & 15);
enc_count++;
}
p++;
}
}
*out = '\0';
if (nencs) *nencs = enc_count;
return out - buf;
}
mio_mchar_t* mio_perenchttpstrdup (int opt, const mio_mchar_t* str, mio_mmgr_t* mmgr)
{
mio_mchar_t* buf;
mio_size_t len = 0;
mio_size_t count = 0;
/* count the number of characters that should be encoded */
if (opt & MIO_PERENCHTTPSTR_KEEP_SLASH)
{
for (len = 0; str[len] != '\0'; len++)
{
if (!IS_UNRESERVED(str[len]) && str[len] != '/') count++;
}
}
else
{
for (len = 0; str[len] != '\0'; len++)
{
if (!IS_UNRESERVED(str[len])) count++;
}
}
/* if there are no characters to escape, just return the original string */
if (count <= 0) return (mio_mchar_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;
/* perform actual escaping */
mio_perenchttpstr (opt, str, buf, MIO_NULL);
return buf;
}

222
mio/lib/mio-htrd.h Normal file
View File

@ -0,0 +1,222 @@
/*
Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MIO_HTRD_H_
#define _MIO_HTRD_H_
#include <mio-http.h>
#include <mio-htre.h>
typedef struct mio_htrd_t mio_htrd_t;
enum mio_htrd_errnum_t
{
MIO_HTRD_ENOERR,
MIO_HTRD_EOTHER,
MIO_HTRD_ENOIMPL,
MIO_HTRD_ESYSERR,
MIO_HTRD_EINTERN,
MIO_HTRD_ENOMEM,
MIO_HTRD_EBADRE,
MIO_HTRD_EBADHDR,
MIO_HTRD_ERECBS,
MIO_HTRD_ECONCB,
MIO_HTRD_ESUSPENDED
};
typedef enum mio_htrd_errnum_t mio_htrd_errnum_t;
/**
* The mio_htrd_option_t type defines various options to
* change the behavior of the mio_htrd_t reader.
*/
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 */
};
typedef enum mio_htrd_option_t mio_htrd_option_t;
typedef struct mio_htrd_recbs_t mio_htrd_recbs_t;
struct mio_htrd_recbs_t
{
int (*peek) (mio_htrd_t* htrd, mio_htre_t* re);
int (*poke) (mio_htrd_t* htrd, mio_htre_t* re);
};
struct mio_htrd_t
{
mio_mmgr_t* mmgr;
mio_htrd_errnum_t errnum;
int option;
int flags;
const mio_htrd_recbs_t* recbs;
struct
{
struct
{
int flags;
int crlf; /* crlf status */
mio_size_t plen; /* raw request length excluding crlf */
mio_size_t need; /* number of octets needed for contents */
struct
{
mio_size_t len;
mio_size_t count;
int phase;
} chunk;
} s; /* state */
/* buffers needed for processing a request */
struct
{
mio_htob_t raw; /* buffer to hold raw octets */
mio_htob_t tra; /* buffer for handling trailers */
} b;
} fed;
mio_htre_t re;
int clean;
};
#if defined(__cplusplus)
extern "C" {
#endif
/**
* The mio_htrd_open() function creates a htrd processor.
*/
MIO_EXPORT mio_htrd_t* mio_htrd_open (
mio_mmgr_t* mmgr, /**< memory manager */
mio_size_t xtnsize /**< extension size in bytes */
);
/**
* The mio_htrd_close() function destroys a htrd processor.
*/
MIO_EXPORT void mio_htrd_close (
mio_htrd_t* htrd
);
MIO_EXPORT int mio_htrd_init (
mio_htrd_t* htrd,
mio_mmgr_t* mmgr
);
MIO_EXPORT void mio_htrd_fini (
mio_htrd_t* htrd
);
MIO_EXPORT mio_mmgr_t* mio_htrd_getmmgr (
mio_htrd_t* htrd
);
MIO_EXPORT void* mio_htrd_getxtn (
mio_htrd_t* htrd
);
MIO_EXPORT mio_htrd_errnum_t mio_htrd_geterrnum (
mio_htrd_t* htrd
);
MIO_EXPORT void mio_htrd_clear (
mio_htrd_t* htrd
);
MIO_EXPORT int mio_htrd_getopt (
mio_htrd_t* htrd
);
MIO_EXPORT void mio_htrd_setopt (
mio_htrd_t* htrd,
int opts
);
MIO_EXPORT const mio_htrd_recbs_t* mio_htrd_getrecbs (
mio_htrd_t* htrd
);
MIO_EXPORT void mio_htrd_setrecbs (
mio_htrd_t* htrd,
const mio_htrd_recbs_t* recbs
);
/**
* The mio_htrd_feed() function accepts htrd request octets and invokes a
* callback function if it has processed a proper htrd request.
*/
MIO_EXPORT int mio_htrd_feed (
mio_htrd_t* htrd, /**< htrd */
const mio_mchar_t* req, /**< request octets */
mio_size_t len /**< number of octets */
);
/**
* The mio_htrd_halt() function indicates the end of feeeding
* if the current response should be processed until the
* connection is closed.
*/
MIO_EXPORT int mio_htrd_halt (
mio_htrd_t* htrd
);
MIO_EXPORT void mio_htrd_suspend (
mio_htrd_t* htrd
);
MIO_EXPORT void mio_htrd_resume (
mio_htrd_t* htrd
);
MIO_EXPORT void mio_htrd_dummify (
mio_htrd_t* htrd
);
MIO_EXPORT void mio_htrd_undummify (
mio_htrd_t* htrd
);
MIO_EXPORT int mio_htrd_scanqparam (
mio_htrd_t* http,
const mio_mcstr_t* cstr
);
#if defined(__cplusplus)
}
#endif
#endif

250
mio/lib/mio-htre.h Normal file
View File

@ -0,0 +1,250 @@
/*
* $Id$
*
Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MIO_HTRE_H_
#define _MIO_HTRE_H_
#include <mio-http.h>
#include <mio-htb.h>
/*
* You should not manipulate an object of the #mio_htre_t
* type directly since it's complex. Use #mio_htrd_t to
* create an object of the mio_htre_t type.
*/
/* header and contents of request/response */
typedef struct mio_htre_t mio_htre_t;
typedef struct mio_htre_hdrval_t mio_htre_hdrval_t;
enum mio_htre_state_t
{
MIO_HTRE_DISCARDED = (1 << 0), /** content has been discarded */
MIO_HTRE_COMPLETED = (1 << 1) /** complete content has been seen */
};
typedef enum mio_htre_state_t mio_htre_state_t;
typedef int (*mio_htre_concb_t) (
mio_htre_t* re,
const mio_mchar_t* ptr,
mio_size_t len,
void* ctx
);
struct mio_htre_hdrval_t
{
const mio_mchar_t* ptr;
mio_size_t len;
mio_htre_hdrval_t* next;
};
struct mio_htre_t
{
mio_mmgr_t* mmgr;
enum
{
MIO_HTRE_Q,
MIO_HTRE_S
} type;
/* version */
mio_http_version_t version;
const mio_mchar_t* verstr; /* version string include HTTP/ */
union
{
struct
{
struct
{
mio_http_method_t type;
const mio_mchar_t* name;
} method;
mio_mcstr_t path;
mio_mcstr_t param;
} q;
struct
{
struct
{
int val;
mio_mchar_t* str;
} code;
mio_mchar_t* mesg;
} s;
} u;
#define MIO_HTRE_ATTR_CHUNKED (1 << 0)
#define MIO_HTRE_ATTR_LENGTH (1 << 1)
#define MIO_HTRE_ATTR_KEEPALIVE (1 << 2)
#define MIO_HTRE_ATTR_EXPECT (1 << 3)
#define MIO_HTRE_ATTR_EXPECT100 (1 << 4)
#define MIO_HTRE_ATTR_PROXIED (1 << 5)
#define MIO_HTRE_QPATH_PERDEC (1 << 6) /* the qpath has been percent-decoded */
int flags;
/* original query path for a request.
* meaningful if MIO_HTRE_QPATH_PERDEC is set in the flags */
struct
{
mio_mchar_t* buf; /* buffer pointer */
mio_size_t capa; /* buffer capacity */
mio_mchar_t* ptr;
mio_size_t len;
} orgqpath;
/* special attributes derived from the header */
struct
{
mio_size_t content_length;
const mio_mchar_t* status; /* for cgi */
} attr;
/* header table */
mio_htb_t hdrtab;
mio_htb_t trailers;
/* content octets */
mio_mbs_t content;
/* content callback */
mio_htre_concb_t concb;
void* concb_ctx;
/* bitwise-ORed of mio_htre_state_t */
int state;
};
#define mio_htre_getversion(re) (&((re)->version))
#define mio_htre_getmajorversion(re) ((re)->version.major)
#define mio_htre_getminorversion(re) ((re)->version.minor)
#define mio_htre_getverstr(re) ((re)->verstr)
#define mio_htre_getqmethodtype(re) ((re)->u.q.method.type)
#define mio_htre_getqmethodname(re) ((re)->u.q.method.name)
#define mio_htre_getqpath(re) ((re)->u.q.path.ptr)
#define mio_htre_getqparam(re) ((re)->u.q.param.ptr)
#define mio_htre_getorgqpath(re) ((re)->orgqpath.ptr)
#define mio_htre_getscodeval(re) ((re)->u.s.code.val)
#define mio_htre_getscodestr(re) ((re)->u.s.code.str)
#define mio_htre_getsmesg(re) ((re)->u.s.mesg)
#define mio_htre_getcontent(re) (&(re)->content)
#define mio_htre_getcontentxstr(re) MIO_MBS_XSTR(&(re)->content)
#define mio_htre_getcontentcstr(re) MIO_MBS_CSTR(&(re)->content)
#define mio_htre_getcontentptr(re) MIO_MBS_PTR(&(re)->content)
#define mio_htre_getcontentlen(re) MIO_MBS_LEN(&(re)->content)
typedef int (*mio_htre_header_walker_t) (
mio_htre_t* re,
const mio_mchar_t* key,
const mio_htre_hdrval_t* val,
void* ctx
);
#if defined(__cplusplus)
extern "C" {
#endif
MIO_EXPORT int mio_htre_init (
mio_htre_t* re,
mio_mmgr_t* mmgr
);
MIO_EXPORT void mio_htre_fini (
mio_htre_t* re
);
MIO_EXPORT void mio_htre_clear (
mio_htre_t* re
);
MIO_EXPORT const mio_htre_hdrval_t* mio_htre_getheaderval (
const mio_htre_t* re,
const mio_mchar_t* key
);
MIO_EXPORT const mio_htre_hdrval_t* mio_htre_gettrailerval (
const mio_htre_t* re,
const mio_mchar_t* key
);
MIO_EXPORT int mio_htre_walkheaders (
mio_htre_t* re,
mio_htre_header_walker_t walker,
void* ctx
);
MIO_EXPORT int mio_htre_walktrailers (
mio_htre_t* re,
mio_htre_header_walker_t walker,
void* ctx
);
/**
* The mio_htre_addcontent() function adds a content semgnet pointed to by
* @a ptr of @a len bytes to the content buffer. If @a re is already completed
* or discarded, this function returns 0 without adding the segment to the
* content buffer.
* @return 1 on success, -1 on failure, 0 if adding is skipped.
*/
MIO_EXPORT int mio_htre_addcontent (
mio_htre_t* re,
const mio_mchar_t* ptr,
mio_size_t len
);
MIO_EXPORT void mio_htre_completecontent (
mio_htre_t* re
);
MIO_EXPORT void mio_htre_discardcontent (
mio_htre_t* re
);
MIO_EXPORT void mio_htre_unsetconcb (
mio_htre_t* re
);
MIO_EXPORT void mio_htre_setconcb (
mio_htre_t* re,
mio_htre_concb_t concb,
void* ctx
);
MIO_EXPORT int mio_htre_perdecqpath (
mio_htre_t* req
);
#if defined(__cplusplus)
}
#endif
#endif

249
mio/lib/mio-http.h Normal file
View File

@ -0,0 +1,249 @@
/*
Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MIO_HTTP_H_
#define _MIO_HTTP_H_
#include <mio-cmn.h>
/** \file
* This file provides basic data types and functions for the http protocol.
*/
/* octet buffer */
typedef mio_mbs_t mio_htob_t;
/* octet string */
typedef mio_mcstr_t mio_htos_t;
/**
* 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
* either #mio_foff_t or #mio_ulong_t.
*/
#if defined(MIO_SIZEOF_FOFF_T) && defined(MIO_SIZEOF_UINTMAX_T) && (MIO_SIZEOF_FOFF_T > MIO_SIZEOF_UINTMAX_T)
typedef mio_foff_t mio_http_range_int_t;
#else
typedef mio_uintmax_t mio_http_range_int_t;
#endif
enum mio_http_range_type_t
{
MIO_HTTP_RANGE_NONE,
MIO_HTTP_RANGE_PROPER,
MIO_HTTP_RANGE_SUFFIX
};
typedef enum mio_http_range_type_t mio_http_range_type_t;
/**
* The mio_http_range_t type defines a structure that can represent
* a value for the \b Range: http header.
*
* If type is #MIO_HTTP_RANGE_NONE, this range is not valid.
*
* If type is #MIO_HTTP_RANGE_SUFFIX, 'from' is meaningleass and 'to' indicates
* the number of bytes from the back.
* - -500 => last 500 bytes
*
* You should adjust a range when the size that this range belongs to is
* made known. See this code:
* \code
* range.from = total_size - range.to;
* range.to = range.to + range.from - 1;
* \endcode
*
* If type is #MIO_HTTP_RANGE_PROPER, 'from' and 'to' represents a proper range
* where the value of 0 indicates the first byte. This doesn't require any
* adjustment.
* - 0-999 => first 1000 bytes
* - 99- => from the 100th bytes to the end.
*/
struct mio_http_range_t
{
mio_http_range_type_t type; /**< type indicator */
mio_http_range_int_t from; /**< starting offset */
mio_http_range_int_t to; /**< ending offset */
};
typedef struct mio_http_range_t mio_http_range_t;
enum mio_perenchttpstr_opt_t
{
MIO_PERENCHTTPSTR_KEEP_SLASH = (1 << 0)
};
typedef enum mio_perenchttpstr_opt_t mio_perenchttpstr_opt_t;
#if defined(__cplusplus)
extern "C" {
#endif
MIO_EXPORT int mio_comparehttpversions (
const mio_http_version_t* v1,
const mio_http_version_t* v2
);
MIO_EXPORT const mio_bch_t* mio_httpstatustombs (
int code
);
MIO_EXPORT const mio_bch_t* mio_httpmethodtombs (
mio_http_method_t type
);
MIO_EXPORT mio_http_method_t mio_mbstohttpmethod (
const mio_bch_t* name
);
MIO_EXPORT mio_http_method_t mio_mcstrtohttpmethod (
const mio_mcstr_t* name
);
MIO_EXPORT int mio_parsehttprange (
const mio_bch_t* str,
mio_http_range_t* range
);
MIO_EXPORT int mio_parsehttptime (
const mio_bch_t* str,
mio_ntime_t* nt
);
MIO_EXPORT mio_bch_t* mio_fmthttptime (
const mio_ntime_t* nt,
mio_bch_t* buf,
mio_oow_t bufsz
);
/**
* The mio_isperencedhttpstr() function determines if the given string
* contains a valid percent-encoded sequence.
*/
MIO_EXPORT int mio_isperencedhttpstr (
const mio_bch_t* str
);
/**
* The mio_perdechttpstr() 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 (
const mio_bch_t* str,
mio_bch_t* buf,
mio_oow_t* ndecs
);
/**
* The mio_perenchttpstr() 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 */
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 */
const mio_bch_t* str,
mio_mmgr_t* mmgr
);
#if defined(__cplusplus)
}
#endif
#endif

View File

@ -194,8 +194,8 @@ typedef struct mio_icmphdr_t mio_icmphdr_t;
# define MIO_SCKHND_INVALID (INVALID_SOCKET)
*/
typedef mio_uintptr_t qse_sckhnd_t;
# define MIO_SCKHND_INVALID (~(qse_sck_hnd_t)0)
typedef mio_uintptr_t mio_sckhnd_t;
# define MIO_SCKHND_INVALID (~(mio_sck_hnd_t)0)
#else
typedef int mio_sckhnd_t;

View File

@ -27,11 +27,11 @@
#ifndef _MIO_H_
#define _MIO_H_
#include "mio-cmn.h"
#include <mio-cmn.h>
#include <stdarg.h>
#if defined(_WIN32)
typedef mio_uintptr_t qse_syshnd_t;
typedef mio_uintptr_t mio_syshnd_t;
#define MIO_SYSHND_INVALID (~(mio_uintptr_t)0)
#else
typedef int mio_syshnd_t;