added some files for future work
This commit is contained in:
parent
252c801544
commit
1a8cb3610b
@ -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
|
||||
|
@ -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
1735
mio/lib/htrd.c
Normal file
File diff suppressed because it is too large
Load Diff
320
mio/lib/htre.c
Normal file
320
mio/lib/htre.c
Normal 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
534
mio/lib/http.c
Normal 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
222
mio/lib/mio-htrd.h
Normal 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
250
mio/lib/mio-htre.h
Normal 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
249
mio/lib/mio-http.h
Normal 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
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user