2020-03-03 13:47:51 +00:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
#include <hio-htre.h>
|
|
|
|
#include <hio-http.h>
|
|
|
|
#include "hio-prv.h"
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
static void free_hdrval (hio_htb_t* htb, void* vptr, hio_oow_t vlen)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_htre_hdrval_t* val;
|
|
|
|
hio_htre_hdrval_t* tmp;
|
2020-03-03 13:47:51 +00:00
|
|
|
|
|
|
|
val = vptr;
|
|
|
|
while (val)
|
|
|
|
{
|
|
|
|
tmp = val;
|
|
|
|
val = val->next;
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_freemem (htb->hio, tmp);
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
int hio_htre_init (hio_htre_t* re, hio_t* hio)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
static hio_htb_style_t style =
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
HIO_HTB_COPIER_DEFAULT,
|
|
|
|
HIO_HTB_COPIER_DEFAULT
|
2020-03-03 13:47:51 +00:00
|
|
|
},
|
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
HIO_HTB_FREEER_DEFAULT,
|
2020-03-03 13:47:51 +00:00
|
|
|
free_hdrval
|
|
|
|
},
|
2021-07-22 07:30:20 +00:00
|
|
|
HIO_HTB_COMPER_DEFAULT,
|
|
|
|
HIO_HTB_KEEPER_DEFAULT,
|
|
|
|
HIO_HTB_SIZER_DEFAULT,
|
|
|
|
HIO_HTB_HASHER_DEFAULT
|
2020-03-03 13:47:51 +00:00
|
|
|
};
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
HIO_MEMSET (re, 0, HIO_SIZEOF(*re));
|
|
|
|
re->hio = hio;
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
if (hio_htb_init(&re->hdrtab, hio, 60, 70, 1, 1) <= -1) return -1;
|
|
|
|
if (hio_htb_init(&re->trailers, hio, 20, 70, 1, 1) <= -1) return -1;
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_htb_setstyle (&re->hdrtab, &style);
|
|
|
|
hio_htb_setstyle (&re->trailers, &style);
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_becs_init (&re->content, hio, 0);
|
2020-03-03 13:47:51 +00:00
|
|
|
#if 0
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_becs_init (&re->iniline, hio, 0);
|
2020-03-03 13:47:51 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
void hio_htre_fini (hio_htre_t* re)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
|
|
|
#if 0
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_becs_fini (&re->iniline);
|
2020-03-03 13:47:51 +00:00
|
|
|
#endif
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_becs_fini (&re->content);
|
|
|
|
hio_htb_fini (&re->trailers);
|
|
|
|
hio_htb_fini (&re->hdrtab);
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2020-05-06 09:28:36 +00:00
|
|
|
if (re->orgqpath.buf)
|
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_freemem (re->hio, re->orgqpath.buf);
|
|
|
|
re->orgqpath.buf = HIO_NULL;
|
2020-05-06 09:28:36 +00:00
|
|
|
re->orgqpath.capa = 0;
|
2021-07-22 07:30:20 +00:00
|
|
|
re->orgqpath.ptr = HIO_NULL;
|
2020-05-06 09:55:35 +00:00
|
|
|
re->orgqpath.len = 0;
|
2020-05-06 09:28:36 +00:00
|
|
|
}
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
void hio_htre_clear (hio_htre_t* re)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
if (!(re->state & HIO_HTRE_COMPLETED) &&
|
|
|
|
!(re->state & HIO_HTRE_DISCARDED))
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
|
|
|
if (re->concb)
|
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
re->concb (re, HIO_NULL, 0, re->concb_ctx); /* indicate end of content */
|
|
|
|
hio_htre_unsetconcb (re);
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
re->state = 0;
|
|
|
|
re->flags = 0;
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
re->orgqpath.ptr = HIO_NULL;
|
2020-05-06 09:55:35 +00:00
|
|
|
re->orgqpath.len = 0;
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
HIO_MEMSET (&re->version, 0, HIO_SIZEOF(re->version));
|
|
|
|
HIO_MEMSET (&re->attr, 0, HIO_SIZEOF(re->attr));
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_htb_clear (&re->hdrtab);
|
|
|
|
hio_htb_clear (&re->trailers);
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_becs_clear (&re->content);
|
2020-03-03 13:47:51 +00:00
|
|
|
#if 0
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_becs_clear (&re->iniline);
|
2020-03-03 13:47:51 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
const hio_htre_hdrval_t* hio_htre_getheaderval (const hio_htre_t* re, const hio_bch_t* name)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_htb_pair_t* pair;
|
|
|
|
pair = hio_htb_search(&re->hdrtab, name, hio_count_bcstr(name));
|
|
|
|
if (pair == HIO_NULL) return HIO_NULL;
|
|
|
|
return HIO_HTB_VPTR(pair);
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
const hio_htre_hdrval_t* hio_htre_gettrailerval (const hio_htre_t* re, const hio_bch_t* name)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_htb_pair_t* pair;
|
|
|
|
pair = hio_htb_search(&re->trailers, name, hio_count_bcstr(name));
|
|
|
|
if (pair == HIO_NULL) return HIO_NULL;
|
|
|
|
return HIO_HTB_VPTR(pair);
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct header_walker_ctx_t
|
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_htre_t* re;
|
|
|
|
hio_htre_header_walker_t walker;
|
2020-03-03 13:47:51 +00:00
|
|
|
void* ctx;
|
|
|
|
int ret;
|
|
|
|
};
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
static hio_htb_walk_t walk_headers (hio_htb_t* htb, hio_htb_pair_t* pair, void* ctx)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
|
|
|
struct header_walker_ctx_t* hwctx = (struct header_walker_ctx_t*)ctx;
|
2021-07-22 07:30:20 +00:00
|
|
|
if (hwctx->walker (hwctx->re, HIO_HTB_KPTR(pair), HIO_HTB_VPTR(pair), hwctx->ctx) <= -1)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
|
|
|
hwctx->ret = -1;
|
2021-07-22 07:30:20 +00:00
|
|
|
return HIO_HTB_WALK_STOP;
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
2021-07-22 07:30:20 +00:00
|
|
|
return HIO_HTB_WALK_FORWARD;
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
int hio_htre_walkheaders (hio_htre_t* re, hio_htre_header_walker_t walker, void* ctx)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
|
|
|
struct header_walker_ctx_t hwctx;
|
|
|
|
hwctx.re = re;
|
|
|
|
hwctx.walker = walker;
|
|
|
|
hwctx.ctx = ctx;
|
|
|
|
hwctx.ret = 0;
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_htb_walk (&re->hdrtab, walk_headers, &hwctx);
|
2020-03-03 13:47:51 +00:00
|
|
|
return hwctx.ret;
|
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
int hio_htre_walktrailers (hio_htre_t* re, hio_htre_header_walker_t walker, void* ctx)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
|
|
|
struct header_walker_ctx_t hwctx;
|
|
|
|
hwctx.re = re;
|
|
|
|
hwctx.walker = walker;
|
|
|
|
hwctx.ctx = ctx;
|
|
|
|
hwctx.ret = 0;
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_htb_walk (&re->trailers, walk_headers, &hwctx);
|
2020-03-03 13:47:51 +00:00
|
|
|
return hwctx.ret;
|
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
int hio_htre_addcontent (hio_htre_t* re, const hio_bch_t* ptr, hio_oow_t len)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
/* see comments in hio_htre_discardcontent() */
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
if (re->state & (HIO_HTRE_COMPLETED | HIO_HTRE_DISCARDED)) return 0; /* skipped */
|
2020-03-03 13:47:51 +00:00
|
|
|
|
|
|
|
if (re->concb)
|
|
|
|
{
|
|
|
|
/* if the callback is set, the content goes to the callback. */
|
2020-04-30 16:20:31 +00:00
|
|
|
if (re->concb(re, ptr, len, re->concb_ctx) <= -1) return -1;
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* if the callback is not set, the contents goes to the internal buffer */
|
2021-07-22 07:30:20 +00:00
|
|
|
if (hio_becs_ncat(&re->content, ptr, len) == (hio_oow_t)-1) return -1;
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1; /* added successfully */
|
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
void hio_htre_completecontent (hio_htre_t* re)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
/* see comments in hio_htre_discardcontent() */
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
if (!(re->state & HIO_HTRE_COMPLETED) &&
|
|
|
|
!(re->state & HIO_HTRE_DISCARDED))
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
re->state |= HIO_HTRE_COMPLETED;
|
2020-03-03 13:47:51 +00:00
|
|
|
if (re->concb)
|
|
|
|
{
|
|
|
|
/* indicate end of content */
|
2021-07-22 07:30:20 +00:00
|
|
|
re->concb (re, HIO_NULL, 0, re->concb_ctx);
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
void hio_htre_discardcontent (hio_htre_t* re)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
|
|
|
/* 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
|
|
|
|
*/
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
if (!(re->state & HIO_HTRE_COMPLETED) && !(re->state & HIO_HTRE_DISCARDED))
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
re->state |= HIO_HTRE_DISCARDED;
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
/* hio_htre_addcontent()...
|
|
|
|
* hio_thre_setconcb()...
|
|
|
|
* hio_htre_discardcontent()... <-- POINT A.
|
2020-03-03 13:47:51 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_becs_clear (&re->content);
|
2020-03-03 13:47:51 +00:00
|
|
|
if (re->concb)
|
|
|
|
{
|
|
|
|
/* indicate end of content */
|
2021-07-22 07:30:20 +00:00
|
|
|
re->concb (re, HIO_NULL, 0, re->concb_ctx);
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
void hio_htre_unsetconcb (hio_htre_t* re)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
re->concb = HIO_NULL;
|
|
|
|
re->concb_ctx = HIO_NULL;
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
void hio_htre_setconcb (hio_htre_t* re, hio_htre_concb_t concb, void* ctx)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
|
|
|
re->concb = concb;
|
|
|
|
re->concb_ctx = ctx;
|
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
int hio_htre_perdecqpath (hio_htre_t* re)
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_oow_t dec_count;
|
2020-03-03 13:47:51 +00:00
|
|
|
|
|
|
|
/* percent decode the query path*/
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
if (re->type != HIO_HTRE_Q || (re->flags & HIO_HTRE_QPATH_PERDEC)) return -1;
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
HIO_ASSERT (re->hio, re->orgqpath.len <= 0);
|
|
|
|
HIO_ASSERT (re->hio, re->orgqpath.ptr == HIO_NULL);
|
2020-03-03 13:47:51 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
if (hio_is_perenced_http_bcstr(re->u.q.path.ptr))
|
2020-03-03 13:47:51 +00:00
|
|
|
{
|
|
|
|
/* 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)
|
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
re->orgqpath.len = hio_copy_bcstr_unlimited(re->orgqpath.buf, re->u.q.path.ptr);
|
2020-03-03 13:47:51 +00:00
|
|
|
re->orgqpath.ptr = re->orgqpath.buf;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (re->orgqpath.buf)
|
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
hio_freemem (re->hio, re->orgqpath.buf);
|
2020-03-03 13:47:51 +00:00
|
|
|
re->orgqpath.capa = 0;
|
2021-07-22 07:30:20 +00:00
|
|
|
re->orgqpath.ptr = HIO_NULL;
|
2020-05-06 09:55:35 +00:00
|
|
|
re->orgqpath.len = 0;
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
re->orgqpath.buf = hio_dupbchars(re->hio, re->u.q.path.ptr, re->u.q.path.len);
|
|
|
|
if (HIO_UNLIKELY(!re->orgqpath.buf)) return -1;
|
2020-03-03 13:47:51 +00:00
|
|
|
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. */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
re->u.q.path.len = hio_perdec_http_bcstr(re->u.q.path.ptr, re->u.q.path.ptr, &dec_count);
|
2020-03-03 13:47:51 +00:00
|
|
|
if (dec_count > 0)
|
|
|
|
{
|
2021-07-22 07:30:20 +00:00
|
|
|
/* this assertion is to ensure that hio_is_perenced_http_bstr()
|
2020-03-03 13:47:51 +00:00
|
|
|
* returned true when dec_count is greater than 0 */
|
2021-07-22 07:30:20 +00:00
|
|
|
HIO_ASSERT (re->hio, re->orgqpath.buf != HIO_NULL);
|
|
|
|
HIO_ASSERT (re->hio, re->orgqpath.ptr != HIO_NULL);
|
|
|
|
re->flags |= HIO_HTRE_QPATH_PERDEC;
|
2020-03-03 13:47:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2020-05-26 13:15:25 +00:00
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
int hio_htre_getreqcontentlen (hio_htre_t* req, hio_oow_t* len)
|
2020-05-26 13:15:25 +00:00
|
|
|
{
|
|
|
|
/* return the potential content length to expect to receive if used as a request */
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
if (req->flags & HIO_HTRE_ATTR_CHUNKED)
|
2020-05-26 13:15:25 +00:00
|
|
|
{
|
|
|
|
/* "Transfer-Encoding: chunked" take precedence over "Content-Length: XXX".
|
|
|
|
*
|
|
|
|
* [RFC7230]
|
|
|
|
* If a message is received with both a Transfer-Encoding and a
|
|
|
|
* Content-Length header field, the Transfer-Encoding overrides the
|
|
|
|
* Content-Length. */
|
|
|
|
return 1; /* unable to determine content-length in advance. unlimited */
|
|
|
|
}
|
|
|
|
|
2021-07-22 07:30:20 +00:00
|
|
|
if (req->flags & HIO_HTRE_ATTR_LENGTH)
|
2020-05-26 13:15:25 +00:00
|
|
|
{
|
|
|
|
*len = req->attr.content_length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If no Content-Length is specified in a request, it's Content-Length: 0 */
|
|
|
|
*len = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0; /* limited to the length set in *len */
|
|
|
|
}
|