enabled qse_http_feed() to get trailing headers after 0
This commit is contained in:
parent
84376d6d92
commit
5b4845db55
@ -186,7 +186,7 @@ ALIASES =
|
||||
# For instance, some of the names that are used will be different. The list
|
||||
# of all members will be omitted, etc.
|
||||
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
|
||||
# sources only. Doxygen will then generate output that is more tailored for
|
||||
@ -1397,12 +1397,12 @@ CLASS_GRAPH = YES
|
||||
# indirect implementation dependencies (inheritance, containment, and
|
||||
# class references variables) of the class with other documented classes.
|
||||
|
||||
COLLABORATION_GRAPH = YES
|
||||
COLLABORATION_GRAPH = NO
|
||||
|
||||
# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
|
||||
# will generate a graph for groups, showing the direct groups dependencies
|
||||
|
||||
GROUP_GRAPHS = YES
|
||||
GROUP_GRAPHS = NO
|
||||
|
||||
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
|
||||
# collaboration diagrams in a style similar to the OMG's Unified Modeling
|
||||
|
@ -1,4 +1,4 @@
|
||||
/** @page awk AWK
|
||||
/** @defgroup awk AWK
|
||||
|
||||
@section awk_intro INTRODUCTION
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/** @page cut TEXT CUTTER
|
||||
/** @defgroup cut TEXT CUTTER
|
||||
|
||||
Text Cutting Utility
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
/** @page sed STREAM EDITOR
|
||||
/** @defgroup sed Stream Editor
|
||||
|
||||
@section sed_contents CONTENTS
|
||||
- \ref sed_intro
|
||||
|
@ -37,7 +37,8 @@
|
||||
*/
|
||||
|
||||
/** @struct qse_cut_t
|
||||
* The qes_cut_t type defines a text cutter.
|
||||
* The qse_cut_t type defines a text cutter. The details are hidden as it is
|
||||
* a large complex structure vulnerable to unintended changes.
|
||||
*/
|
||||
typedef struct qse_cut_t qse_cut_t;
|
||||
|
||||
@ -110,7 +111,7 @@ typedef enum qse_cut_io_cmd_t qse_cut_io_cmd_t;
|
||||
*/
|
||||
struct qse_cut_io_arg_t
|
||||
{
|
||||
void* handle; /**< I/O handle */
|
||||
void* handle; /**< I/O handle */
|
||||
};
|
||||
typedef struct qse_cut_io_arg_t qse_cut_io_arg_t;
|
||||
|
||||
@ -133,12 +134,12 @@ extern "C" {
|
||||
QSE_DEFINE_COMMON_FUNCTIONS (cut)
|
||||
|
||||
/**
|
||||
* The qse_cut_open() function creates a text cutter object.
|
||||
* @return A pointer to a text cutter on success, QSE_NULL on failure
|
||||
* The qse_cut_open() function creates a text cutter.
|
||||
* @return A pointer to a text cutter on success, #QSE_NULL on failure
|
||||
*/
|
||||
qse_cut_t* qse_cut_open (
|
||||
qse_mmgr_t* mmgr, /**< a memory manager */
|
||||
qse_size_t xtn /**< the size of extension in bytes */
|
||||
qse_mmgr_t* mmgr, /**< memory manager */
|
||||
qse_size_t xtnsize /**< extension size in bytes */
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: Sed.hpp 321 2009-12-21 12:44:33Z hyunghwan.chung $
|
||||
* $Id: Sed.hpp 373 2010-11-26 15:00:57Z hyunghwan.chung $
|
||||
*
|
||||
Copyright 2006-2009 Chung, Hyung-Hwan.
|
||||
This file is part of QSE.
|
||||
@ -24,6 +24,18 @@
|
||||
#include <qse/cmn/Mmged.hpp>
|
||||
#include <qse/sed/sed.h>
|
||||
|
||||
/**
|
||||
* @defgroup sed_cxx C++
|
||||
* @ingroup sed
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sed_cxx_core Core interface
|
||||
* @ingroup sed_cxx
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* Stream Editor
|
||||
*/
|
||||
@ -310,4 +322,7 @@ private:
|
||||
QSE_END_NAMESPACE(QSE)
|
||||
/////////////////////////////////
|
||||
|
||||
/* @} */
|
||||
/* @} */
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: sed.h 344 2010-08-17 13:15:14Z hyunghwan.chung $
|
||||
* $Id: sed.h 373 2010-11-26 15:00:57Z hyunghwan.chung $
|
||||
*
|
||||
Copyright 2006-2009 Chung, Hyung-Hwan.
|
||||
This file is part of QSE.
|
||||
@ -24,6 +24,25 @@
|
||||
#include <qse/types.h>
|
||||
#include <qse/macros.h>
|
||||
|
||||
/**
|
||||
* @defgroup sed_c C
|
||||
* @ingroup sed
|
||||
* @{
|
||||
* hello
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sed_c_core Core interface
|
||||
* @ingroup sed_c
|
||||
* @{
|
||||
* The sed library provides data types and functions for creating a custom
|
||||
* stream editor commonly available on platforms. It is a non-interactive
|
||||
* text editing tool that reads text from an input stream, stores it to
|
||||
* pattern space, manipulates the pattern space by applying a set of editing
|
||||
* commands, and writes the pattern space to an output stream. Typically,
|
||||
* the input and output streams are a console or a file.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* A stream editor performs text transformation on a text stream.
|
||||
*
|
||||
@ -423,4 +442,7 @@ void qse_sed_setlinnum (
|
||||
}
|
||||
#endif
|
||||
|
||||
/* @} */
|
||||
/* @} */
|
||||
|
||||
#endif
|
||||
|
@ -21,10 +21,20 @@
|
||||
#ifndef _QSE_SED_STD_H_
|
||||
#define _QSE_SED_STD_H_
|
||||
|
||||
/**
|
||||
* @defgroup sed_c_std Helper functions
|
||||
* @ingroup sed_c
|
||||
* @{
|
||||
* If you don't care about the details of memory management and I/O,
|
||||
* you can choose to use the helper functions provided here. It is
|
||||
* a higher-level interface that is easier to use as it implements
|
||||
* default handlers for I/O and memory management.
|
||||
*/
|
||||
|
||||
#include <qse/sed/sed.h>
|
||||
|
||||
/** @file
|
||||
* This file provides easier-to-use versions of selected API functions
|
||||
* This file provides easier-to-use interface
|
||||
* by implementing default handlers for I/O and memory management.
|
||||
*
|
||||
* @example sed01.c
|
||||
@ -38,8 +48,9 @@ extern "C" {
|
||||
|
||||
/**
|
||||
* The qse_sed_openstd() function creates a stream editor with the default
|
||||
* memory manager and initialized it for other qse_sed_xxxxstd functions.
|
||||
* @return pointer to a stream editor on success, QSE_NULL on failure.
|
||||
* memory manager and initializes it. Use qse_getxtnstd(), not qse_getxtn()
|
||||
* to get the pointer to the extension area.
|
||||
* @return pointer to a stream editor on success, #QSE_NULL on failure.
|
||||
*/
|
||||
qse_sed_t* qse_sed_openstd (
|
||||
qse_size_t xtnsize /**< extension size in bytes */
|
||||
@ -48,8 +59,9 @@ qse_sed_t* qse_sed_openstd (
|
||||
/**
|
||||
* The qse_sed_openstdwithmmgr() function creates a stream editor with a
|
||||
* user-defined memory manager. It is equivalent to qse_sed_openstd(),
|
||||
* except that you can specify your own memory manager.
|
||||
* @return pointer to a stream editor on success, QSE_NULL on failure.
|
||||
* except that you can specify your own memory manager.Use qse_getxtnstd(),
|
||||
* not qse_getxtn() to get the pointer to the extension area.
|
||||
* @return pointer to a stream editor on success, #QSE_NULL on failure.
|
||||
*/
|
||||
qse_sed_t* qse_sed_openstdwithmmgr (
|
||||
qse_mmgr_t* mmgr, /**< memory manager */
|
||||
@ -62,7 +74,7 @@ qse_sed_t* qse_sed_openstdwithmmgr (
|
||||
* created with qse_sed_openstd() and qse_sed_openstdwithmmgr().
|
||||
*/
|
||||
void* qse_sed_getxtnstd (
|
||||
qse_sed_t* sed
|
||||
qse_sed_t* sed /**< stream editor */
|
||||
);
|
||||
|
||||
/**
|
||||
@ -71,26 +83,27 @@ void* qse_sed_getxtnstd (
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int qse_sed_compstd (
|
||||
qse_sed_t* sed,
|
||||
const qse_char_t* str
|
||||
qse_sed_t* sed, /**< stream editor */
|
||||
const qse_char_t* str /**< null-terminated script */
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_sed_execstd() function executes the compiled script
|
||||
* over an input file @a infile and an output file @a outfile.
|
||||
* If @a infile is QSE_NULL, the standard console input is used.
|
||||
* If @a outfile is QSE_NULL, the standard console output is used.
|
||||
* If @a infile is #QSE_NULL, the standard console input is used.
|
||||
* If @a outfile is #QSE_NULL, the standard console output is used.
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int qse_sed_execstd (
|
||||
qse_sed_t* sed,
|
||||
const qse_char_t* infile,
|
||||
const qse_char_t* outfile
|
||||
qse_sed_t* sed, /**< stream editor */
|
||||
const qse_char_t* infile, /**< input file */
|
||||
const qse_char_t* outfile /**< output file */
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* @} */
|
||||
|
||||
#endif
|
||||
|
@ -57,6 +57,7 @@ struct qse_http_t
|
||||
|
||||
qse_http_octb_t raw;
|
||||
qse_http_octb_t con;
|
||||
qse_http_octb_t tra;
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -76,32 +76,31 @@ struct qse_cut_t
|
||||
qse_char_t buf[2048];
|
||||
qse_size_t len;
|
||||
int eof;
|
||||
} out;
|
||||
} out;
|
||||
|
||||
/** data needed for input streams */
|
||||
struct
|
||||
{
|
||||
qse_cut_io_fun_t fun; /**< an input handler */
|
||||
qse_cut_io_arg_t arg; /**< input handling data */
|
||||
{
|
||||
qse_cut_io_fun_t fun; /**< an input handler */
|
||||
qse_cut_io_arg_t arg; /**< input handling data */
|
||||
|
||||
qse_char_t xbuf[1]; /**< a read-ahead buffer */
|
||||
int xbuf_len; /**< data length in the buffer */
|
||||
qse_char_t xbuf[1]; /**< a read-ahead buffer */
|
||||
int xbuf_len; /**< data length in the buffer */
|
||||
|
||||
qse_char_t buf[2048]; /**< input buffer */
|
||||
qse_size_t len; /**< data length in the buffer */
|
||||
qse_size_t pos; /**< current position in the buffer */
|
||||
int eof; /**< EOF indicator */
|
||||
qse_char_t buf[2048]; /**< input buffer */
|
||||
qse_size_t len; /**< data length in the buffer */
|
||||
qse_size_t pos; /**< current position in the buffer */
|
||||
int eof; /**< EOF indicator */
|
||||
|
||||
qse_str_t line; /**< pattern space */
|
||||
qse_size_t num; /**< current line number */
|
||||
qse_str_t line; /**< pattern space */
|
||||
qse_size_t num; /**< current line number */
|
||||
|
||||
qse_size_t nflds; /**< the number of fields */
|
||||
qse_size_t cflds; /**< capacity of flds field */
|
||||
qse_cstr_t sflds[128]; /**< static field buffer */
|
||||
qse_cstr_t* flds;
|
||||
int delimited;
|
||||
} in;
|
||||
|
||||
} in;
|
||||
} e;
|
||||
};
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
QSE_IMPLEMENT_COMMON_FUNCTIONS (http)
|
||||
|
||||
static const qse_byte_t NUL = '\0';
|
||||
|
||||
static QSE_INLINE int is_http_space (qse_char_t c)
|
||||
{
|
||||
return QSE_ISSPACE(c) && c != QSE_T('\r') && c != QSE_T('\n');
|
||||
@ -354,8 +356,12 @@ static QSE_INLINE void clear_request (qse_http_t* http)
|
||||
* reading the next request */
|
||||
QSE_MEMSET (&http->req.state, 0, QSE_SIZEOF(http->req.state));
|
||||
QSE_MEMSET (&http->req.attr, 0, QSE_SIZEOF(http->req.attr));
|
||||
|
||||
qse_htb_clear (&http->req.hdr.tab);
|
||||
|
||||
clear_combined_headers (http);
|
||||
|
||||
clear_buffer (http, &http->req.tra);
|
||||
clear_buffer (http, &http->req.con);
|
||||
clear_buffer (http, &http->req.raw);
|
||||
}
|
||||
@ -407,9 +413,12 @@ qse_http_t* qse_http_init (qse_http_t* http, qse_mmgr_t* mmgr)
|
||||
|
||||
init_buffer (http, &http->req.raw);
|
||||
init_buffer (http, &http->req.con);
|
||||
init_buffer (http, &http->req.tra);
|
||||
|
||||
if (qse_htb_init (&http->req.hdr.tab, mmgr, 60, 70, 1, 1) == QSE_NULL)
|
||||
{
|
||||
fini_buffer (http, &http->req.tra);
|
||||
fini_buffer (http, &http->req.con);
|
||||
fini_buffer (http, &http->req.raw);
|
||||
return QSE_NULL;
|
||||
}
|
||||
@ -421,6 +430,7 @@ void qse_http_fini (qse_http_t* http)
|
||||
{
|
||||
qse_htb_fini (&http->req.hdr.tab);
|
||||
clear_combined_headers (http);
|
||||
fini_buffer (http, &http->req.tra);
|
||||
fini_buffer (http, &http->req.con);
|
||||
fini_buffer (http, &http->req.raw);
|
||||
}
|
||||
@ -951,14 +961,13 @@ qse_printf (QSE_T("HEADER OK %d[%S] %d[%S]\n"), (int)pair->klen, pair->kptr, (i
|
||||
static QSE_INLINE int parse_request (
|
||||
qse_http_t* http, const qse_byte_t* req, qse_size_t rlen)
|
||||
{
|
||||
static const qse_byte_t nul = '\0';
|
||||
qse_byte_t* p;
|
||||
|
||||
/* add the actual request */
|
||||
if (push_to_buffer (http, &http->req.raw, req, rlen) <= -1) return -1;
|
||||
|
||||
/* add the terminating null for easier parsing */
|
||||
if (push_to_buffer (http, &http->req.raw, &nul, 1) <= -1) return -1;
|
||||
if (push_to_buffer (http, &http->req.raw, &NUL, 1) <= -1) return -1;
|
||||
|
||||
p = http->req.raw.data;
|
||||
|
||||
@ -1037,8 +1046,8 @@ static const qse_byte_t* getchunklen (qse_http_t* http, const qse_byte_t* ptr, q
|
||||
{
|
||||
/* length explicity specified to 0
|
||||
get trailing headers .... */
|
||||
/*TODO: => http->req.state.chunk.phase = GET_CHUNK_TRAILERS;*/
|
||||
http->req.state.chunk.phase = GET_CHUNK_DATA;
|
||||
http->req.state.chunk.phase = GET_CHUNK_TRAILERS;
|
||||
//qse_printf (QSE_T("SWITCH TO GET_CHUNK_TRAILERS....\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1061,11 +1070,86 @@ static const qse_byte_t* getchunklen (qse_http_t* http, const qse_byte_t* ptr, q
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* feed the percent encoded string */
|
||||
int qse_http_feed (qse_http_t* http, const qse_byte_t* ptr, qse_size_t len)
|
||||
static const qse_byte_t* get_trailing_headers (
|
||||
qse_http_t* http, const qse_byte_t* req, const qse_byte_t* end)
|
||||
{
|
||||
const qse_byte_t* end = ptr + len;
|
||||
const qse_byte_t* req = ptr;
|
||||
const qse_byte_t* ptr = req;
|
||||
|
||||
while (ptr < end)
|
||||
{
|
||||
register qse_byte_t b = *ptr++;
|
||||
|
||||
switch (b)
|
||||
{
|
||||
case '\0':
|
||||
/* guarantee that the request does not contain a null
|
||||
* character */
|
||||
http->errnum = QSE_HTTP_EBADREQ;
|
||||
return -1;
|
||||
|
||||
case '\n':
|
||||
if (http->req.state.crlf <= 1)
|
||||
{
|
||||
http->req.state.crlf = 2;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_byte_t* p;
|
||||
|
||||
QSE_ASSERT (http->req.state.crlf <= 3);
|
||||
http->req.state.crlf = 0;
|
||||
|
||||
if (push_to_buffer (
|
||||
http, &http->req.tra, req, ptr - req) <= -1)
|
||||
return QSE_NULL;
|
||||
if (push_to_buffer (
|
||||
http, &http->req.tra, &NUL, 1) <= -1)
|
||||
return QSE_NULL;
|
||||
|
||||
p = http->req.tra.data;
|
||||
|
||||
do
|
||||
{
|
||||
while (is_whspace_octet(*p)) p++;
|
||||
if (*p == '\0') break;
|
||||
|
||||
/* TODO: return error if protocol is 0.9.
|
||||
* HTTP/0.9 must not get headers... */
|
||||
|
||||
p = parse_header_fields (http, p);
|
||||
if (p == QSE_NULL) return QSE_NULL;
|
||||
}
|
||||
while (1);
|
||||
|
||||
http->req.state.chunk.phase = GET_CHUNK_DONE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
case '\r':
|
||||
if (http->req.state.crlf == 0 || http->req.state.crlf == 2)
|
||||
http->req.state.crlf++;
|
||||
else http->req.state.crlf = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* mark that neither CR nor LF was seen */
|
||||
http->req.state.crlf = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (push_to_buffer (http, &http->req.tra, req, ptr - req) <= -1) return QSE_NULL;
|
||||
|
||||
done:
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
/* feed the percent encoded string */
|
||||
int qse_http_feed (qse_http_t* http, const qse_byte_t* req, qse_size_t len)
|
||||
{
|
||||
const qse_byte_t* end = req + len;
|
||||
const qse_byte_t* ptr = req;
|
||||
|
||||
/* does this goto drop code maintainability? */
|
||||
if (http->req.state.need > 0) goto content_resume;
|
||||
@ -1082,10 +1166,8 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* ptr, qse_size_t len)
|
||||
case GET_CHUNK_CRLF:
|
||||
goto dechunk_crlf;
|
||||
|
||||
/*
|
||||
case GET_CHUNK_TRAILERS:
|
||||
goto ....
|
||||
*/
|
||||
goto dechunk_get_trailers;
|
||||
}
|
||||
|
||||
while (ptr < end)
|
||||
@ -1100,128 +1182,156 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* ptr, qse_size_t len)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b == '\n')
|
||||
switch (b)
|
||||
{
|
||||
if (http->req.state.crlf <= 1)
|
||||
{
|
||||
/* http->req.state.crlf == 0, CR was not seen
|
||||
* http->req.state.crlf == 1, CR was seen
|
||||
* whatever the current case is, mark the
|
||||
* first LF is seen here.
|
||||
*/
|
||||
http->req.state.crlf = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* http->req.state.crlf == 2, no 2nd CR before LF
|
||||
* http->req.state.crlf == 3, 2nd CR before LF
|
||||
*/
|
||||
case '\0':
|
||||
/* guarantee that the request does not contain a null
|
||||
* character */
|
||||
http->errnum = QSE_HTTP_EBADREQ;
|
||||
return -1;
|
||||
|
||||
/* we got a complete request. */
|
||||
QSE_ASSERT (http->req.state.crlf <= 3);
|
||||
|
||||
/* reset the crlf state */
|
||||
http->req.state.crlf = 0;
|
||||
/* reset the raw request length */
|
||||
http->req.state.plen = 0;
|
||||
|
||||
if (parse_request (http, req, ptr - req) <= -1)
|
||||
return -1;
|
||||
|
||||
if (http->req.attr.chunked)
|
||||
case '\n':
|
||||
if (http->req.state.crlf <= 1)
|
||||
{
|
||||
/* transfer-encoding: chunked */
|
||||
QSE_ASSERT (http->req.attr.content_length <= 0);
|
||||
|
||||
dechunk_start:
|
||||
http->req.state.chunk.phase = GET_CHUNK_LEN;
|
||||
http->req.state.chunk.len = 0;
|
||||
http->req.state.chunk.count = 0;
|
||||
|
||||
dechunk_resume:
|
||||
ptr = getchunklen (http, ptr, end - ptr);
|
||||
if (ptr == QSE_NULL) return -1;
|
||||
|
||||
if (http->req.state.chunk.phase == GET_CHUNK_LEN)
|
||||
{
|
||||
/* still in the GET_CHUNK_LEN state.
|
||||
* the length has been partially read. */
|
||||
goto feedme_more;
|
||||
}
|
||||
/* http->req.state.crlf == 0
|
||||
* => CR was not seen
|
||||
* http->req.state.crlf == 1
|
||||
* => CR was seen
|
||||
* whatever the current case is,
|
||||
* mark the first LF is seen here.
|
||||
*/
|
||||
http->req.state.crlf = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we need to read as many octets as Content-Length */
|
||||
http->req.state.need = http->req.attr.content_length;
|
||||
}
|
||||
|
||||
if (http->req.state.need > 0)
|
||||
{
|
||||
/* content-length or chunked data length specified */
|
||||
|
||||
qse_size_t avail;
|
||||
|
||||
content_resume:
|
||||
avail = end - ptr;
|
||||
|
||||
if (avail < http->req.state.need)
|
||||
/* http->req.state.crlf == 2
|
||||
* => no 2nd CR before LF
|
||||
* http->req.state.crlf == 3
|
||||
* => 2nd CR before LF
|
||||
*/
|
||||
|
||||
/* we got a complete request. */
|
||||
QSE_ASSERT (http->req.state.crlf <= 3);
|
||||
|
||||
/* reset the crlf state */
|
||||
http->req.state.crlf = 0;
|
||||
/* reset the raw request length */
|
||||
http->req.state.plen = 0;
|
||||
|
||||
if (parse_request (http, req, ptr - req) <= -1)
|
||||
return -1;
|
||||
|
||||
if (http->req.attr.chunked)
|
||||
{
|
||||
/* the data is not as large as needed */
|
||||
if (push_to_buffer (http, &http->req.con, ptr, avail) <= -1) return -1;
|
||||
http->req.state.need -= avail;
|
||||
/* we didn't get a complete content yet */
|
||||
goto feedme_more;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we are given all needed or more than needed */
|
||||
if (push_to_buffer (http, &http->req.con, ptr, http->req.state.need) <= -1) return -1;
|
||||
ptr += http->req.state.need;
|
||||
http->req.state.need = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (http->req.state.chunk.phase == GET_CHUNK_DATA)
|
||||
{
|
||||
QSE_ASSERT (http->req.state.need == 0);
|
||||
http->req.state.chunk.phase = GET_CHUNK_CRLF;
|
||||
|
||||
dechunk_crlf:
|
||||
while (ptr < end && is_space_octet(*ptr)) ptr++;
|
||||
if (ptr < end)
|
||||
{
|
||||
if (*ptr == '\n')
|
||||
/* transfer-encoding: chunked */
|
||||
QSE_ASSERT (http->req.attr.content_length <= 0);
|
||||
|
||||
dechunk_start:
|
||||
http->req.state.chunk.phase = GET_CHUNK_LEN;
|
||||
http->req.state.chunk.len = 0;
|
||||
http->req.state.chunk.count = 0;
|
||||
|
||||
dechunk_resume:
|
||||
ptr = getchunklen (http, ptr, end - ptr);
|
||||
if (ptr == QSE_NULL) return -1;
|
||||
|
||||
if (http->req.state.chunk.phase == GET_CHUNK_LEN)
|
||||
{
|
||||
/* end of chunk data. */
|
||||
ptr++;
|
||||
|
||||
/* more octets still available.
|
||||
* let it decode the next chunk */
|
||||
if (ptr < end) goto dechunk_start;
|
||||
|
||||
/* no more octets available after chunk data.
|
||||
* the chunk state variables need to be
|
||||
* reset when a jump is made to dechunk_resume
|
||||
* upon the next call */
|
||||
http->req.state.chunk.phase = GET_CHUNK_LEN;
|
||||
http->req.state.chunk.len = 0;
|
||||
http->req.state.chunk.count = 0;
|
||||
|
||||
/* still in the GET_CHUNK_LEN state.
|
||||
* the length has been partially read. */
|
||||
goto feedme_more;
|
||||
}
|
||||
else
|
||||
else if (http->req.state.chunk.phase == GET_CHUNK_TRAILERS)
|
||||
{
|
||||
/* redundant character ... */
|
||||
http->errnum = QSE_HTTP_EBADREQ;
|
||||
return -1;
|
||||
dechunk_get_trailers:
|
||||
ptr = get_trailing_headers (http, ptr, end);
|
||||
if (ptr == QSE_NULL) return -1;
|
||||
|
||||
if (http->req.state.chunk.phase == GET_CHUNK_TRAILERS)
|
||||
{
|
||||
/* still in the same state.
|
||||
* the trailers have not been processed fully */
|
||||
goto feedme_more;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* data not enough */
|
||||
goto feedme_more;
|
||||
/* we need to read as many octets as Content-Length */
|
||||
http->req.state.need = http->req.attr.content_length;
|
||||
}
|
||||
|
||||
if (http->req.state.need > 0)
|
||||
{
|
||||
/* content-length or chunked data length specified */
|
||||
|
||||
qse_size_t avail;
|
||||
|
||||
content_resume:
|
||||
avail = end - ptr;
|
||||
|
||||
if (avail < http->req.state.need)
|
||||
{
|
||||
/* the data is not as large as needed */
|
||||
if (push_to_buffer (http, &http->req.con, ptr, avail) <= -1) return -1;
|
||||
http->req.state.need -= avail;
|
||||
/* we didn't get a complete content yet */
|
||||
goto feedme_more;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we got all or more than needed */
|
||||
if (push_to_buffer (
|
||||
http, &http->req.con, ptr,
|
||||
http->req.state.need) <= -1) return -1;
|
||||
ptr += http->req.state.need;
|
||||
http->req.state.need = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (http->req.state.chunk.phase == GET_CHUNK_DATA)
|
||||
{
|
||||
QSE_ASSERT (http->req.state.need == 0);
|
||||
http->req.state.chunk.phase = GET_CHUNK_CRLF;
|
||||
|
||||
dechunk_crlf:
|
||||
while (ptr < end && is_space_octet(*ptr)) ptr++;
|
||||
if (ptr < end)
|
||||
{
|
||||
if (*ptr == '\n')
|
||||
{
|
||||
/* end of chunk data. */
|
||||
ptr++;
|
||||
|
||||
/* more octets still available.
|
||||
* let it decode the next chunk
|
||||
*/
|
||||
if (ptr < end) goto dechunk_start;
|
||||
|
||||
/* no more octets available after
|
||||
* chunk data. the chunk state variables
|
||||
* need to be reset when a jump is made
|
||||
* to dechunk_resume upon the next call
|
||||
*/
|
||||
http->req.state.chunk.phase = GET_CHUNK_LEN;
|
||||
http->req.state.chunk.len = 0;
|
||||
http->req.state.chunk.count = 0;
|
||||
|
||||
goto feedme_more;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* redundant character ... */
|
||||
http->errnum = QSE_HTTP_EBADREQ;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* data not enough */
|
||||
goto feedme_more;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qse_htb_walk (&http->req.hdr.tab, walk, QSE_NULL);
|
||||
if (http->req.con.size > 0)
|
||||
@ -1230,32 +1340,26 @@ if (http->req.con.size > 0)
|
||||
}
|
||||
/* TODO: do the main job here... before the raw buffer is cleared out... */
|
||||
|
||||
clear_request (http);
|
||||
clear_request (http);
|
||||
|
||||
/* let ptr point to the next character to LF or the optional contents */
|
||||
req = ptr;
|
||||
}
|
||||
}
|
||||
else if (b == '\r')
|
||||
{
|
||||
if (http->req.state.crlf == 0 || http->req.state.crlf == 2)
|
||||
http->req.state.crlf++;
|
||||
else http->req.state.crlf = 1;
|
||||
}
|
||||
else if (b == '\0')
|
||||
{
|
||||
/* guarantee that the request does not contain a null
|
||||
* character */
|
||||
http->errnum = QSE_HTTP_EBADREQ;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* increment length of a request in raw
|
||||
* excluding crlf */
|
||||
http->req.state.plen++;
|
||||
/* mark that neither CR nor LF was seen */
|
||||
http->req.state.crlf = 0;
|
||||
/* let ptr point to the next character to LF or
|
||||
* the optional contents */
|
||||
req = ptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
if (http->req.state.crlf == 0 || http->req.state.crlf == 2)
|
||||
http->req.state.crlf++;
|
||||
else http->req.state.crlf = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* increment length of a request in raw
|
||||
* excluding crlf */
|
||||
http->req.state.plen++;
|
||||
/* mark that neither CR nor LF was seen */
|
||||
http->req.state.crlf = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1267,5 +1371,6 @@ if (http->req.con.size > 0)
|
||||
|
||||
feedme_more:
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user