added some files for future work
This commit is contained in:
		@ -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;
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user