reorganized the qse_http_t structure
This commit is contained in:
parent
5b4845db55
commit
4491055c84
@ -9,6 +9,7 @@
|
|||||||
#include <qse/macros.h>
|
#include <qse/macros.h>
|
||||||
#include <qse/cmn/htb.h>
|
#include <qse/cmn/htb.h>
|
||||||
|
|
||||||
|
typedef struct qse_http_t qse_http_t;
|
||||||
|
|
||||||
typedef struct qse_http_octb_t qse_http_octb_t;
|
typedef struct qse_http_octb_t qse_http_octb_t;
|
||||||
|
|
||||||
@ -19,25 +20,81 @@ struct qse_http_octb_t
|
|||||||
qse_byte_t* data;
|
qse_byte_t* data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
enum qse_http_errnum_t
|
enum qse_http_errnum_t
|
||||||
{
|
{
|
||||||
QSE_HTTP_ENOERR,
|
QSE_HTTP_ENOERR,
|
||||||
QSE_HTTP_ENOMEM,
|
QSE_HTTP_ENOMEM,
|
||||||
QSE_HTTP_EBADREQ,
|
QSE_HTTP_EBADREQ,
|
||||||
QSE_HTTP_EBADHDR,
|
QSE_HTTP_EBADHDR,
|
||||||
QSE_HTTP_ETRAENC /* bad transfer-encoding */
|
QSE_HTTP_EREQCBS
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum qse_http_errnum_t qse_http_errnum_t;
|
typedef enum qse_http_errnum_t qse_http_errnum_t;
|
||||||
|
|
||||||
typedef struct qse_http_t qse_http_t;
|
|
||||||
|
typedef struct qse_http_req_t qse_http_req_t;
|
||||||
|
|
||||||
|
struct qse_http_req_t
|
||||||
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
QSE_HTTP_REQ_GET,
|
||||||
|
QSE_HTTP_REQ_HEAD,
|
||||||
|
QSE_HTTP_REQ_POST
|
||||||
|
} method;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
qse_byte_t* ptr;
|
||||||
|
qse_size_t len;
|
||||||
|
} host;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
qse_byte_t* ptr;
|
||||||
|
qse_size_t len;
|
||||||
|
} path;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
qse_byte_t* ptr;
|
||||||
|
qse_size_t len;
|
||||||
|
} args;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
short major;
|
||||||
|
short minor;
|
||||||
|
} version;
|
||||||
|
|
||||||
|
/* header table */
|
||||||
|
qse_htb_t hdrtab;
|
||||||
|
|
||||||
|
/* special attributes derived from the header */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int chunked;
|
||||||
|
int content_length;
|
||||||
|
int connection_close;
|
||||||
|
} attr;
|
||||||
|
|
||||||
|
qse_http_octb_t con;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct qse_http_reqcbs_t qse_http_reqcbs_t;
|
||||||
|
|
||||||
|
struct qse_http_reqcbs_t
|
||||||
|
{
|
||||||
|
int (*request) (qse_http_t* http, qse_http_req_t* req);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct qse_http_t
|
struct qse_http_t
|
||||||
{
|
{
|
||||||
QSE_DEFINE_COMMON_FIELDS (http)
|
QSE_DEFINE_COMMON_FIELDS (http)
|
||||||
qse_http_errnum_t errnum;
|
qse_http_errnum_t errnum;
|
||||||
|
|
||||||
|
const qse_http_reqcbs_t* reqcbs;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@ -53,99 +110,27 @@ struct qse_http_t
|
|||||||
qse_size_t count;
|
qse_size_t count;
|
||||||
int phase;
|
int phase;
|
||||||
} chunk;
|
} chunk;
|
||||||
} state;
|
} s; /* state */
|
||||||
|
|
||||||
qse_http_octb_t raw;
|
|
||||||
qse_http_octb_t con;
|
|
||||||
qse_http_octb_t tra;
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
QSE_HTTP_REQ_GET,
|
|
||||||
QSE_HTTP_REQ_HEAD,
|
|
||||||
QSE_HTTP_REQ_POST
|
|
||||||
} method;
|
|
||||||
|
|
||||||
|
/* buffers needed to for processing a request */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
qse_byte_t* ptr;
|
qse_http_octb_t raw;
|
||||||
qse_size_t len;
|
qse_http_octb_t tra;
|
||||||
} host;
|
} b;
|
||||||
|
|
||||||
struct
|
/* points to the head of the combined header list */
|
||||||
{
|
void* chl;
|
||||||
qse_byte_t* ptr;
|
} reqx;
|
||||||
qse_size_t len;
|
|
||||||
} path;
|
|
||||||
|
|
||||||
struct
|
qse_http_req_t req;
|
||||||
{
|
|
||||||
qse_byte_t* ptr;
|
|
||||||
qse_size_t len;
|
|
||||||
} args;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
short major;
|
|
||||||
short minor;
|
|
||||||
} version;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
qse_htb_t tab;
|
|
||||||
void* combined;
|
|
||||||
} hdr;
|
|
||||||
|
|
||||||
/* special attributes derived from the header */
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
int chunked;
|
|
||||||
int content_length;
|
|
||||||
int connection_close;
|
|
||||||
} attr;
|
|
||||||
} req;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* returns the type of http method */
|
|
||||||
typedef struct qse_http_req_t qse_http_req_t;
|
|
||||||
typedef struct qse_http_hdr_t qse_http_hdr_t;
|
|
||||||
|
|
||||||
struct qse_http_req_t
|
|
||||||
{
|
|
||||||
qse_char_t* method;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
qse_char_t* ptr;
|
|
||||||
qse_size_t len;
|
|
||||||
} path;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
qse_char_t* ptr;
|
|
||||||
qse_size_t len;
|
|
||||||
} args;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
char major;
|
|
||||||
char minor;
|
|
||||||
} vers;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct qse_http_hdr_t
|
|
||||||
{
|
|
||||||
qse_cstr_t name;
|
|
||||||
qse_cstr_t value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
qse_char_t* qse_parsehttpreq (qse_char_t* buf, qse_http_req_t* req);
|
|
||||||
qse_char_t* qse_parsehttphdr (qse_char_t* buf, qse_http_hdr_t* hdr);
|
|
||||||
|
|
||||||
QSE_DEFINE_COMMON_FUNCTIONS (http)
|
QSE_DEFINE_COMMON_FUNCTIONS (http)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -176,6 +161,25 @@ void qse_http_clear (
|
|||||||
qse_http_t* http
|
qse_http_t* http
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const qse_http_reqcbs_t* qse_http_getreqcbs (
|
||||||
|
qse_http_t* http
|
||||||
|
);
|
||||||
|
|
||||||
|
void qse_http_setreqcbs (
|
||||||
|
qse_http_t* http,
|
||||||
|
const qse_http_reqcbs_t* reqcbs
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The qse_http_feed() function accepts http request octets and invokes a
|
||||||
|
* callback function if it has processed a proper http request.
|
||||||
|
*/
|
||||||
|
int qse_http_feed (
|
||||||
|
qse_http_t* http, /**< http */
|
||||||
|
const qse_byte_t* req, /**< request octets */
|
||||||
|
qse_size_t len /**< number of octets */
|
||||||
|
);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,190 +26,6 @@ QSE_IMPLEMENT_COMMON_FUNCTIONS (http)
|
|||||||
|
|
||||||
static const qse_byte_t NUL = '\0';
|
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');
|
|
||||||
}
|
|
||||||
|
|
||||||
#define is_http_ctl(c) QSE_ISCNTRL(c)
|
|
||||||
|
|
||||||
static QSE_INLINE int is_http_separator (qse_char_t c)
|
|
||||||
{
|
|
||||||
return c == QSE_T('(') ||
|
|
||||||
c == QSE_T(')') ||
|
|
||||||
c == QSE_T('<') ||
|
|
||||||
c == QSE_T('>') ||
|
|
||||||
c == QSE_T('@') ||
|
|
||||||
c == QSE_T(',') ||
|
|
||||||
c == QSE_T(';') ||
|
|
||||||
c == QSE_T(':') ||
|
|
||||||
c == QSE_T('\\') ||
|
|
||||||
c == QSE_T('\"') ||
|
|
||||||
c == QSE_T('/') ||
|
|
||||||
c == QSE_T('[') ||
|
|
||||||
c == QSE_T(']') ||
|
|
||||||
c == QSE_T('?') ||
|
|
||||||
c == QSE_T('=') ||
|
|
||||||
c == QSE_T('{') ||
|
|
||||||
c == QSE_T('}') ||
|
|
||||||
c == QSE_T('\t') ||
|
|
||||||
c == QSE_T(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
static QSE_INLINE int is_http_token (qse_char_t c)
|
|
||||||
{
|
|
||||||
return QSE_ISPRINT(c) && !is_http_ctl(c) && !is_http_separator(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
static QSE_INLINE int dig_to_num (qse_char_t c)
|
|
||||||
{
|
|
||||||
if (c >= QSE_T('0') && c <= QSE_T('9')) return c - QSE_T('0');
|
|
||||||
if (c >= QSE_T('A') && c <= QSE_T('Z')) return c - QSE_T('A') + 10;
|
|
||||||
if (c >= QSE_T('a') && c <= QSE_T('z')) return c - QSE_T('a') + 10;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
qse_char_t* qse_parsehttpreq (qse_char_t* octb, qse_http_req_t* req)
|
|
||||||
{
|
|
||||||
qse_char_t* p = octb, * x;
|
|
||||||
|
|
||||||
/* ignore leading spaces */
|
|
||||||
while (is_http_space(*p)) p++;
|
|
||||||
|
|
||||||
/* the method should start with an alphabet */
|
|
||||||
if (!QSE_ISALPHA(*p)) return QSE_NULL;
|
|
||||||
|
|
||||||
/* scan the method */
|
|
||||||
req->method = p; while (QSE_ISALPHA(*p)) p++;
|
|
||||||
|
|
||||||
/* the method should be followed by a space */
|
|
||||||
if (!is_http_space(*p)) return QSE_NULL;
|
|
||||||
|
|
||||||
/* null-terminate the method */
|
|
||||||
*p++ = QSE_T('\0');
|
|
||||||
|
|
||||||
/* skip spaces */
|
|
||||||
while (is_http_space(*p)) p++;
|
|
||||||
|
|
||||||
/* scan the url */
|
|
||||||
req->path.ptr = p;
|
|
||||||
req->args.ptr = QSE_NULL;
|
|
||||||
|
|
||||||
x = p;
|
|
||||||
while (QSE_ISPRINT(*p) && !QSE_ISSPACE(*p))
|
|
||||||
{
|
|
||||||
if (*p == QSE_T('%') && QSE_ISXDIGIT(*(p+1)) && QSE_ISXDIGIT(*(p+2)))
|
|
||||||
{
|
|
||||||
*x++ = (dig_to_num(*(p+1)) << 4) + dig_to_num(*(p+2));
|
|
||||||
p += 3;
|
|
||||||
}
|
|
||||||
else if (*p == QSE_T('?') && req->args.ptr == QSE_NULL)
|
|
||||||
{
|
|
||||||
/* ? must be explicit to be a argument instroducer.
|
|
||||||
* %3f is just a literal. */
|
|
||||||
req->path.len = x - req->path.ptr;
|
|
||||||
*x++ = QSE_T('\0');
|
|
||||||
req->args.ptr = x;
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
else *x++ = *p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the url should be followed by a space */
|
|
||||||
if (!is_http_space(*p)) return QSE_NULL;
|
|
||||||
|
|
||||||
/* null-terminate the url and store the length */
|
|
||||||
if (req->args.ptr != QSE_NULL)
|
|
||||||
req->args.len = x - req->args.ptr;
|
|
||||||
else
|
|
||||||
req->path.len = x - req->path.ptr;
|
|
||||||
*x++ = QSE_T('\0');
|
|
||||||
|
|
||||||
/* path should start with a slash */
|
|
||||||
if (req->path.len <= 0 || req->path.ptr[0] != QSE_T('/')) return QSE_NULL;
|
|
||||||
|
|
||||||
/* skip spaces */
|
|
||||||
do { p++; } while (is_http_space(*p));
|
|
||||||
|
|
||||||
/* check http version */
|
|
||||||
if ((p[0] == QSE_T('H') || p[0] == QSE_T('h')) &&
|
|
||||||
(p[1] == QSE_T('T') || p[1] == QSE_T('t')) &&
|
|
||||||
(p[2] == QSE_T('T') || p[2] == QSE_T('t')) &&
|
|
||||||
(p[3] == QSE_T('P') || p[3] == QSE_T('p')) &&
|
|
||||||
p[4] == QSE_T('/') && p[6] == QSE_T('.'))
|
|
||||||
{
|
|
||||||
if (!QSE_ISDIGIT(p[5])) return QSE_NULL;
|
|
||||||
if (!QSE_ISDIGIT(p[7])) return QSE_NULL;
|
|
||||||
req->vers.major = p[5] - QSE_T('0');
|
|
||||||
req->vers.minor = p[7] - QSE_T('0');
|
|
||||||
p += 8;
|
|
||||||
}
|
|
||||||
else return QSE_NULL;
|
|
||||||
|
|
||||||
while (QSE_ISSPACE(*p))
|
|
||||||
{
|
|
||||||
if (*p++ == QSE_T('\n')) goto ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* not terminating with a new line.
|
|
||||||
* maybe garbage after the request line */
|
|
||||||
if (*p != QSE_T('\0')) return QSE_NULL;
|
|
||||||
|
|
||||||
ok:
|
|
||||||
/* returns the next position */
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
qse_char_t* qse_parsehttphdr (qse_char_t* octb, qse_http_hdr_t* hdr)
|
|
||||||
{
|
|
||||||
qse_char_t* p = octb, * last;
|
|
||||||
|
|
||||||
/* ignore leading spaces including CR and NL */
|
|
||||||
while (QSE_ISSPACE(*p)) p++;
|
|
||||||
|
|
||||||
if (*p == QSE_T('\0'))
|
|
||||||
{
|
|
||||||
/* no more header line */
|
|
||||||
QSE_MEMSET (hdr, 0, QSE_SIZEOF(*hdr));
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_http_token(*p)) return QSE_NULL;
|
|
||||||
|
|
||||||
hdr->name.ptr = p;
|
|
||||||
do { p++; } while (is_http_token(*p));
|
|
||||||
|
|
||||||
last = p;
|
|
||||||
hdr->name.len = last - hdr->name.ptr;
|
|
||||||
|
|
||||||
while (is_http_space(*p)) p++;
|
|
||||||
if (*p != QSE_T(':')) return QSE_NULL;
|
|
||||||
|
|
||||||
*last = QSE_T('\0');
|
|
||||||
|
|
||||||
do { p++; } while (is_http_space(*p));
|
|
||||||
|
|
||||||
hdr->value.ptr = last = p;
|
|
||||||
while (QSE_ISPRINT(*p))
|
|
||||||
{
|
|
||||||
if (!QSE_ISSPACE(*p++)) last = p;
|
|
||||||
}
|
|
||||||
hdr->value.len = last - hdr->value.ptr;
|
|
||||||
|
|
||||||
while (QSE_ISSPACE(*p))
|
|
||||||
{
|
|
||||||
if (*p++ == QSE_T('\n')) goto ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* not terminating with a new line.
|
|
||||||
* maybe garbage after the header line */
|
|
||||||
if (*p != QSE_T('\0')) return QSE_NULL;
|
|
||||||
|
|
||||||
ok:
|
|
||||||
*last = QSE_T('\0');
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QSE_INLINE int is_whspace_octet (qse_byte_t c)
|
static QSE_INLINE int is_whspace_octet (qse_byte_t c)
|
||||||
{
|
{
|
||||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
|
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
|
||||||
@ -338,7 +154,7 @@ struct hdr_cmb_t
|
|||||||
|
|
||||||
static QSE_INLINE void clear_combined_headers (qse_http_t* http)
|
static QSE_INLINE void clear_combined_headers (qse_http_t* http)
|
||||||
{
|
{
|
||||||
struct hdr_cmb_t* cmb = (struct hdr_cmb_t*)http->req.hdr.combined;
|
struct hdr_cmb_t* cmb = (struct hdr_cmb_t*)http->reqx.chl;
|
||||||
|
|
||||||
while (cmb)
|
while (cmb)
|
||||||
{
|
{
|
||||||
@ -347,23 +163,23 @@ static QSE_INLINE void clear_combined_headers (qse_http_t* http)
|
|||||||
cmb = next;
|
cmb = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
http->req.hdr.combined = QSE_NULL;
|
http->reqx.chl = QSE_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSE_INLINE void clear_request (qse_http_t* http)
|
static QSE_INLINE void clear_request (qse_http_t* http)
|
||||||
{
|
{
|
||||||
/* clear necessary part of the request before
|
/* clear necessary part of the request before
|
||||||
* reading the next request */
|
* 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_MEMSET (&http->req.attr, 0, QSE_SIZEOF(http->req.attr));
|
||||||
|
|
||||||
qse_htb_clear (&http->req.hdr.tab);
|
qse_htb_clear (&http->req.hdrtab);
|
||||||
|
|
||||||
clear_combined_headers (http);
|
clear_combined_headers (http);
|
||||||
|
|
||||||
clear_buffer (http, &http->req.tra);
|
|
||||||
clear_buffer (http, &http->req.con);
|
clear_buffer (http, &http->req.con);
|
||||||
clear_buffer (http, &http->req.raw);
|
clear_buffer (http, &http->reqx.b.tra);
|
||||||
|
clear_buffer (http, &http->reqx.b.raw);
|
||||||
|
|
||||||
|
QSE_MEMSET (&http->reqx.s, 0, QSE_SIZEOF(http->reqx.s));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define QSE_HTTP_STATE_REQ 1
|
#define QSE_HTTP_STATE_REQ 1
|
||||||
@ -411,15 +227,15 @@ qse_http_t* qse_http_init (qse_http_t* http, qse_mmgr_t* mmgr)
|
|||||||
QSE_MEMSET (http, 0, QSE_SIZEOF(*http));
|
QSE_MEMSET (http, 0, QSE_SIZEOF(*http));
|
||||||
http->mmgr = mmgr;
|
http->mmgr = mmgr;
|
||||||
|
|
||||||
init_buffer (http, &http->req.raw);
|
init_buffer (http, &http->reqx.b.raw);
|
||||||
|
init_buffer (http, &http->reqx.b.tra);
|
||||||
init_buffer (http, &http->req.con);
|
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)
|
if (qse_htb_init (&http->req.hdrtab, mmgr, 60, 70, 1, 1) == QSE_NULL)
|
||||||
{
|
{
|
||||||
fini_buffer (http, &http->req.tra);
|
|
||||||
fini_buffer (http, &http->req.con);
|
fini_buffer (http, &http->req.con);
|
||||||
fini_buffer (http, &http->req.raw);
|
fini_buffer (http, &http->reqx.b.tra);
|
||||||
|
fini_buffer (http, &http->reqx.b.raw);
|
||||||
return QSE_NULL;
|
return QSE_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,11 +244,11 @@ qse_http_t* qse_http_init (qse_http_t* http, qse_mmgr_t* mmgr)
|
|||||||
|
|
||||||
void qse_http_fini (qse_http_t* http)
|
void qse_http_fini (qse_http_t* http)
|
||||||
{
|
{
|
||||||
qse_htb_fini (&http->req.hdr.tab);
|
qse_htb_fini (&http->req.hdrtab);
|
||||||
clear_combined_headers (http);
|
clear_combined_headers (http);
|
||||||
fini_buffer (http, &http->req.tra);
|
|
||||||
fini_buffer (http, &http->req.con);
|
fini_buffer (http, &http->req.con);
|
||||||
fini_buffer (http, &http->req.raw);
|
fini_buffer (http, &http->reqx.b.tra);
|
||||||
|
fini_buffer (http, &http->reqx.b.raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
static qse_byte_t* parse_reqline (qse_http_t* http, qse_byte_t* line)
|
static qse_byte_t* parse_reqline (qse_http_t* http, qse_byte_t* line)
|
||||||
@ -577,6 +393,16 @@ void qse_http_clear (qse_http_t* http)
|
|||||||
clear_request (http);
|
clear_request (http);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const qse_http_reqcbs_t* qse_http_getreqcbs (qse_http_t* http)
|
||||||
|
{
|
||||||
|
return http->reqcbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qse_http_setreqcbs (qse_http_t* http, const qse_http_reqcbs_t* reqcbs)
|
||||||
|
{
|
||||||
|
http->reqcbs = reqcbs;
|
||||||
|
}
|
||||||
|
|
||||||
#define octet_tolower(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) | 0x20) : (c))
|
#define octet_tolower(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) | 0x20) : (c))
|
||||||
#define octet_toupper(c) (((c) >= 'a' && (c) <= 'z') ? ((c) & ~0x20) : (c))
|
#define octet_toupper(c) (((c) >= 'a' && (c) <= 'z') ? ((c) & ~0x20) : (c))
|
||||||
|
|
||||||
@ -832,8 +658,8 @@ Not easy to unlink when using a singly linked list...
|
|||||||
Change it to doubly linked for this?
|
Change it to doubly linked for this?
|
||||||
|
|
||||||
/* let's destroy the old buffer at least */
|
/* let's destroy the old buffer at least */
|
||||||
if (!(ptr >= tx->http->req.raw.data && ptr <
|
if (!(ptr >= tx->http->reqx.b.raw.data && ptr <
|
||||||
&tx->http->req.raw.data[tx->http->req.raw.size]))
|
&tx->http->reqx.b.raw.data[tx->http->reqx.b.raw.size]))
|
||||||
{
|
{
|
||||||
/* NOTE the range check in 'if' assumes that raw.data is never
|
/* NOTE the range check in 'if' assumes that raw.data is never
|
||||||
* relocated for resizing */
|
* relocated for resizing */
|
||||||
@ -850,8 +676,8 @@ Change it to doubly linked for this?
|
|||||||
pair->vlen = len;
|
pair->vlen = len;
|
||||||
|
|
||||||
/* link the new combined value block */
|
/* link the new combined value block */
|
||||||
cmb->next = tx->http->req.hdr.combined;
|
cmb->next = tx->http->reqx.chl;
|
||||||
tx->http->req.hdr.combined = cmb;
|
tx->http->reqx.chl = cmb;
|
||||||
|
|
||||||
if (capture_key_header (tx->http, pair) <= -1) return QSE_NULL;
|
if (capture_key_header (tx->http, pair) <= -1) return QSE_NULL;
|
||||||
|
|
||||||
@ -935,7 +761,7 @@ qse_byte_t* parse_header_fields (qse_http_t* http, qse_byte_t* line)
|
|||||||
|
|
||||||
http->errnum = QSE_HTTP_ENOERR;
|
http->errnum = QSE_HTTP_ENOERR;
|
||||||
if (qse_htb_cbsert (
|
if (qse_htb_cbsert (
|
||||||
&http->req.hdr.tab, name.ptr, name.len,
|
&http->req.hdrtab, name.ptr, name.len,
|
||||||
hdr_cbserter, &ctx) == QSE_NULL)
|
hdr_cbserter, &ctx) == QSE_NULL)
|
||||||
{
|
{
|
||||||
if (http->errnum == QSE_HTTP_ENOERR)
|
if (http->errnum == QSE_HTTP_ENOERR)
|
||||||
@ -964,12 +790,12 @@ static QSE_INLINE int parse_request (
|
|||||||
qse_byte_t* p;
|
qse_byte_t* p;
|
||||||
|
|
||||||
/* add the actual request */
|
/* add the actual request */
|
||||||
if (push_to_buffer (http, &http->req.raw, req, rlen) <= -1) return -1;
|
if (push_to_buffer (http, &http->reqx.b.raw, req, rlen) <= -1) return -1;
|
||||||
|
|
||||||
/* add the terminating null for easier parsing */
|
/* 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->reqx.b.raw, &NUL, 1) <= -1) return -1;
|
||||||
|
|
||||||
p = http->req.raw.data;
|
p = http->reqx.b.raw.data;
|
||||||
|
|
||||||
while (is_whspace_octet(*p)) p++;
|
while (is_whspace_octet(*p)) p++;
|
||||||
QSE_ASSERT (*p != '\0');
|
QSE_ASSERT (*p != '\0');
|
||||||
@ -1007,10 +833,10 @@ static const qse_byte_t* getchunklen (qse_http_t* http, const qse_byte_t* ptr, q
|
|||||||
const qse_byte_t* end = ptr + len;
|
const qse_byte_t* end = ptr + len;
|
||||||
|
|
||||||
/* this function must be called in the GET_CHUNK_LEN context */
|
/* this function must be called in the GET_CHUNK_LEN context */
|
||||||
QSE_ASSERT (http->req.state.chunk.phase == GET_CHUNK_LEN);
|
QSE_ASSERT (http->reqx.s.chunk.phase == GET_CHUNK_LEN);
|
||||||
|
|
||||||
//qse_printf (QSE_T("CALLING getchunklen [%d]\n"), *ptr);
|
//qse_printf (QSE_T("CALLING getchunklen [%d]\n"), *ptr);
|
||||||
if (http->req.state.chunk.count <= 0)
|
if (http->reqx.s.chunk.count <= 0)
|
||||||
{
|
{
|
||||||
/* skip leading spaces if the first character of
|
/* skip leading spaces if the first character of
|
||||||
* the chunk length has not been read yet */
|
* the chunk length has not been read yet */
|
||||||
@ -1022,8 +848,8 @@ static const qse_byte_t* getchunklen (qse_http_t* http, const qse_byte_t* ptr, q
|
|||||||
int n = xdigit_to_num (*ptr);
|
int n = xdigit_to_num (*ptr);
|
||||||
if (n <= -1) break;
|
if (n <= -1) break;
|
||||||
|
|
||||||
http->req.state.chunk.len = http->req.state.chunk.len * 16 + n;
|
http->reqx.s.chunk.len = http->reqx.s.chunk.len * 16 + n;
|
||||||
http->req.state.chunk.count++;
|
http->reqx.s.chunk.count++;
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1036,27 +862,27 @@ static const qse_byte_t* getchunklen (qse_http_t* http, const qse_byte_t* ptr, q
|
|||||||
{
|
{
|
||||||
/* the chunk length line ended properly */
|
/* the chunk length line ended properly */
|
||||||
|
|
||||||
if (http->req.state.chunk.count <= 0)
|
if (http->reqx.s.chunk.count <= 0)
|
||||||
{
|
{
|
||||||
/* empty line - no more chunk */
|
/* empty line - no more chunk */
|
||||||
//qse_printf (QSE_T("empty line chunk done....\n"));
|
//qse_printf (QSE_T("empty line chunk done....\n"));
|
||||||
http->req.state.chunk.phase = GET_CHUNK_DONE;
|
http->reqx.s.chunk.phase = GET_CHUNK_DONE;
|
||||||
}
|
}
|
||||||
else if (http->req.state.chunk.len <= 0)
|
else if (http->reqx.s.chunk.len <= 0)
|
||||||
{
|
{
|
||||||
/* length explicity specified to 0
|
/* length explicity specified to 0
|
||||||
get trailing headers .... */
|
get trailing headers .... */
|
||||||
http->req.state.chunk.phase = GET_CHUNK_TRAILERS;
|
http->reqx.s.chunk.phase = GET_CHUNK_TRAILERS;
|
||||||
//qse_printf (QSE_T("SWITCH TO GET_CHUNK_TRAILERS....\n"));
|
//qse_printf (QSE_T("SWITCH TO GET_CHUNK_TRAILERS....\n"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ready to read the chunk data... */
|
/* ready to read the chunk data... */
|
||||||
http->req.state.chunk.phase = GET_CHUNK_DATA;
|
http->reqx.s.chunk.phase = GET_CHUNK_DATA;
|
||||||
//qse_printf (QSE_T("SWITCH TO GET_CHUNK_DATA....\n"));
|
//qse_printf (QSE_T("SWITCH TO GET_CHUNK_DATA....\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
http->req.state.need = http->req.state.chunk.len;
|
http->reqx.s.need = http->reqx.s.chunk.len;
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1088,26 +914,26 @@ static const qse_byte_t* get_trailing_headers (
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case '\n':
|
case '\n':
|
||||||
if (http->req.state.crlf <= 1)
|
if (http->reqx.s.crlf <= 1)
|
||||||
{
|
{
|
||||||
http->req.state.crlf = 2;
|
http->reqx.s.crlf = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qse_byte_t* p;
|
qse_byte_t* p;
|
||||||
|
|
||||||
QSE_ASSERT (http->req.state.crlf <= 3);
|
QSE_ASSERT (http->reqx.s.crlf <= 3);
|
||||||
http->req.state.crlf = 0;
|
http->reqx.s.crlf = 0;
|
||||||
|
|
||||||
if (push_to_buffer (
|
if (push_to_buffer (
|
||||||
http, &http->req.tra, req, ptr - req) <= -1)
|
http, &http->reqx.b.tra, req, ptr - req) <= -1)
|
||||||
return QSE_NULL;
|
return QSE_NULL;
|
||||||
if (push_to_buffer (
|
if (push_to_buffer (
|
||||||
http, &http->req.tra, &NUL, 1) <= -1)
|
http, &http->reqx.b.tra, &NUL, 1) <= -1)
|
||||||
return QSE_NULL;
|
return QSE_NULL;
|
||||||
|
|
||||||
p = http->req.tra.data;
|
p = http->reqx.b.tra.data;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -1122,23 +948,24 @@ static const qse_byte_t* get_trailing_headers (
|
|||||||
}
|
}
|
||||||
while (1);
|
while (1);
|
||||||
|
|
||||||
http->req.state.chunk.phase = GET_CHUNK_DONE;
|
http->reqx.s.chunk.phase = GET_CHUNK_DONE;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
case '\r':
|
case '\r':
|
||||||
if (http->req.state.crlf == 0 || http->req.state.crlf == 2)
|
if (http->reqx.s.crlf == 0 || http->reqx.s.crlf == 2)
|
||||||
http->req.state.crlf++;
|
http->reqx.s.crlf++;
|
||||||
else http->req.state.crlf = 1;
|
else http->reqx.s.crlf = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* mark that neither CR nor LF was seen */
|
/* mark that neither CR nor LF was seen */
|
||||||
http->req.state.crlf = 0;
|
http->reqx.s.crlf = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (push_to_buffer (http, &http->req.tra, req, ptr - req) <= -1) return QSE_NULL;
|
if (push_to_buffer (http, &http->reqx.b.tra, req, ptr - req) <= -1)
|
||||||
|
return QSE_NULL;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
return ptr;
|
return ptr;
|
||||||
@ -1152,14 +979,14 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* req, qse_size_t len)
|
|||||||
const qse_byte_t* ptr = req;
|
const qse_byte_t* ptr = req;
|
||||||
|
|
||||||
/* does this goto drop code maintainability? */
|
/* does this goto drop code maintainability? */
|
||||||
if (http->req.state.need > 0) goto content_resume;
|
if (http->reqx.s.need > 0) goto content_resume;
|
||||||
switch (http->req.state.chunk.phase)
|
switch (http->reqx.s.chunk.phase)
|
||||||
{
|
{
|
||||||
case GET_CHUNK_LEN:
|
case GET_CHUNK_LEN:
|
||||||
goto dechunk_resume;
|
goto dechunk_resume;
|
||||||
|
|
||||||
case GET_CHUNK_DATA:
|
case GET_CHUNK_DATA:
|
||||||
/* this won't be reached as http->req.state.need
|
/* this won't be reached as http->reqx.s.need
|
||||||
* is greater than 0 if GET_CHUNK_DATA is true */
|
* is greater than 0 if GET_CHUNK_DATA is true */
|
||||||
goto content_resume;
|
goto content_resume;
|
||||||
|
|
||||||
@ -1174,7 +1001,7 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* req, qse_size_t len)
|
|||||||
{
|
{
|
||||||
register qse_byte_t b = *ptr++;
|
register qse_byte_t b = *ptr++;
|
||||||
|
|
||||||
if (http->req.state.plen <= 0 && is_whspace_octet(b))
|
if (http->reqx.s.plen <= 0 && is_whspace_octet(b))
|
||||||
{
|
{
|
||||||
/* let's drop leading whitespaces across multiple
|
/* let's drop leading whitespaces across multiple
|
||||||
* lines */
|
* lines */
|
||||||
@ -1185,38 +1012,38 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* req, qse_size_t len)
|
|||||||
switch (b)
|
switch (b)
|
||||||
{
|
{
|
||||||
case '\0':
|
case '\0':
|
||||||
/* guarantee that the request does not contain a null
|
/* guarantee that the request does not contain
|
||||||
* character */
|
* a null character */
|
||||||
http->errnum = QSE_HTTP_EBADREQ;
|
http->errnum = QSE_HTTP_EBADREQ;
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case '\n':
|
case '\n':
|
||||||
if (http->req.state.crlf <= 1)
|
if (http->reqx.s.crlf <= 1)
|
||||||
{
|
{
|
||||||
/* http->req.state.crlf == 0
|
/* http->reqx.s.crlf == 0
|
||||||
* => CR was not seen
|
* => CR was not seen
|
||||||
* http->req.state.crlf == 1
|
* http->reqx.s.crlf == 1
|
||||||
* => CR was seen
|
* => CR was seen
|
||||||
* whatever the current case is,
|
* whatever the current case is,
|
||||||
* mark the first LF is seen here.
|
* mark the first LF is seen here.
|
||||||
*/
|
*/
|
||||||
http->req.state.crlf = 2;
|
http->reqx.s.crlf = 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* http->req.state.crlf == 2
|
/* http->reqx.s.crlf == 2
|
||||||
* => no 2nd CR before LF
|
* => no 2nd CR before LF
|
||||||
* http->req.state.crlf == 3
|
* http->reqx.s.crlf == 3
|
||||||
* => 2nd CR before LF
|
* => 2nd CR before LF
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* we got a complete request. */
|
/* we got a complete request. */
|
||||||
QSE_ASSERT (http->req.state.crlf <= 3);
|
QSE_ASSERT (http->reqx.s.crlf <= 3);
|
||||||
|
|
||||||
/* reset the crlf state */
|
/* reset the crlf state */
|
||||||
http->req.state.crlf = 0;
|
http->reqx.s.crlf = 0;
|
||||||
/* reset the raw request length */
|
/* reset the raw request length */
|
||||||
http->req.state.plen = 0;
|
http->reqx.s.plen = 0;
|
||||||
|
|
||||||
if (parse_request (http, req, ptr - req) <= -1)
|
if (parse_request (http, req, ptr - req) <= -1)
|
||||||
return -1;
|
return -1;
|
||||||
@ -1227,27 +1054,27 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* req, qse_size_t len)
|
|||||||
QSE_ASSERT (http->req.attr.content_length <= 0);
|
QSE_ASSERT (http->req.attr.content_length <= 0);
|
||||||
|
|
||||||
dechunk_start:
|
dechunk_start:
|
||||||
http->req.state.chunk.phase = GET_CHUNK_LEN;
|
http->reqx.s.chunk.phase = GET_CHUNK_LEN;
|
||||||
http->req.state.chunk.len = 0;
|
http->reqx.s.chunk.len = 0;
|
||||||
http->req.state.chunk.count = 0;
|
http->reqx.s.chunk.count = 0;
|
||||||
|
|
||||||
dechunk_resume:
|
dechunk_resume:
|
||||||
ptr = getchunklen (http, ptr, end - ptr);
|
ptr = getchunklen (http, ptr, end - ptr);
|
||||||
if (ptr == QSE_NULL) return -1;
|
if (ptr == QSE_NULL) return -1;
|
||||||
|
|
||||||
if (http->req.state.chunk.phase == GET_CHUNK_LEN)
|
if (http->reqx.s.chunk.phase == GET_CHUNK_LEN)
|
||||||
{
|
{
|
||||||
/* still in the GET_CHUNK_LEN state.
|
/* still in the GET_CHUNK_LEN state.
|
||||||
* the length has been partially read. */
|
* the length has been partially read. */
|
||||||
goto feedme_more;
|
goto feedme_more;
|
||||||
}
|
}
|
||||||
else if (http->req.state.chunk.phase == GET_CHUNK_TRAILERS)
|
else if (http->reqx.s.chunk.phase == GET_CHUNK_TRAILERS)
|
||||||
{
|
{
|
||||||
dechunk_get_trailers:
|
dechunk_get_trailers:
|
||||||
ptr = get_trailing_headers (http, ptr, end);
|
ptr = get_trailing_headers (http, ptr, end);
|
||||||
if (ptr == QSE_NULL) return -1;
|
if (ptr == QSE_NULL) return -1;
|
||||||
|
|
||||||
if (http->req.state.chunk.phase == GET_CHUNK_TRAILERS)
|
if (http->reqx.s.chunk.phase == GET_CHUNK_TRAILERS)
|
||||||
{
|
{
|
||||||
/* still in the same state.
|
/* still in the same state.
|
||||||
* the trailers have not been processed fully */
|
* the trailers have not been processed fully */
|
||||||
@ -1258,10 +1085,10 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* req, qse_size_t len)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* we need to read as many octets as Content-Length */
|
/* we need to read as many octets as Content-Length */
|
||||||
http->req.state.need = http->req.attr.content_length;
|
http->reqx.s.need = http->req.attr.content_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (http->req.state.need > 0)
|
if (http->reqx.s.need > 0)
|
||||||
{
|
{
|
||||||
/* content-length or chunked data length specified */
|
/* content-length or chunked data length specified */
|
||||||
|
|
||||||
@ -1270,11 +1097,11 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* req, qse_size_t len)
|
|||||||
content_resume:
|
content_resume:
|
||||||
avail = end - ptr;
|
avail = end - ptr;
|
||||||
|
|
||||||
if (avail < http->req.state.need)
|
if (avail < http->reqx.s.need)
|
||||||
{
|
{
|
||||||
/* the data is not as large as needed */
|
/* the data is not as large as needed */
|
||||||
if (push_to_buffer (http, &http->req.con, ptr, avail) <= -1) return -1;
|
if (push_to_buffer (http, &http->req.con, ptr, avail) <= -1) return -1;
|
||||||
http->req.state.need -= avail;
|
http->reqx.s.need -= avail;
|
||||||
/* we didn't get a complete content yet */
|
/* we didn't get a complete content yet */
|
||||||
goto feedme_more;
|
goto feedme_more;
|
||||||
}
|
}
|
||||||
@ -1283,16 +1110,16 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* req, qse_size_t len)
|
|||||||
/* we got all or more than needed */
|
/* we got all or more than needed */
|
||||||
if (push_to_buffer (
|
if (push_to_buffer (
|
||||||
http, &http->req.con, ptr,
|
http, &http->req.con, ptr,
|
||||||
http->req.state.need) <= -1) return -1;
|
http->reqx.s.need) <= -1) return -1;
|
||||||
ptr += http->req.state.need;
|
ptr += http->reqx.s.need;
|
||||||
http->req.state.need = 0;
|
http->reqx.s.need = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (http->req.state.chunk.phase == GET_CHUNK_DATA)
|
if (http->reqx.s.chunk.phase == GET_CHUNK_DATA)
|
||||||
{
|
{
|
||||||
QSE_ASSERT (http->req.state.need == 0);
|
QSE_ASSERT (http->reqx.s.need == 0);
|
||||||
http->req.state.chunk.phase = GET_CHUNK_CRLF;
|
http->reqx.s.chunk.phase = GET_CHUNK_CRLF;
|
||||||
|
|
||||||
dechunk_crlf:
|
dechunk_crlf:
|
||||||
while (ptr < end && is_space_octet(*ptr)) ptr++;
|
while (ptr < end && is_space_octet(*ptr)) ptr++;
|
||||||
@ -1313,9 +1140,9 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* req, qse_size_t len)
|
|||||||
* need to be reset when a jump is made
|
* need to be reset when a jump is made
|
||||||
* to dechunk_resume upon the next call
|
* to dechunk_resume upon the next call
|
||||||
*/
|
*/
|
||||||
http->req.state.chunk.phase = GET_CHUNK_LEN;
|
http->reqx.s.chunk.phase = GET_CHUNK_LEN;
|
||||||
http->req.state.chunk.len = 0;
|
http->reqx.s.chunk.len = 0;
|
||||||
http->req.state.chunk.count = 0;
|
http->reqx.s.chunk.count = 0;
|
||||||
|
|
||||||
goto feedme_more;
|
goto feedme_more;
|
||||||
}
|
}
|
||||||
@ -1333,12 +1160,28 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* req, qse_size_t len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_htb_walk (&http->req.hdr.tab, walk, QSE_NULL);
|
|
||||||
|
QSE_ASSERTX (http->reqcbs != QSE_NULL,
|
||||||
|
"Set the request callback before feeding data");
|
||||||
|
http->errnum = QSE_HTTP_ENOERR;
|
||||||
|
if (http->reqcbs->request (http, &http->req) <= -1)
|
||||||
|
{
|
||||||
|
if (http->errnum == QSE_HTTP_ENOERR)
|
||||||
|
http->errnum = QSE_HTTP_EREQCBS;
|
||||||
|
|
||||||
|
/* need to clear request on error?
|
||||||
|
clear_request (http); */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
qse_htb_walk (&http->req.hdrtab, walk, QSE_NULL);
|
||||||
if (http->req.con.size > 0)
|
if (http->req.con.size > 0)
|
||||||
{
|
{
|
||||||
qse_printf (QSE_T("content = [%.*S]\n"), (int)http->req.con.size, http->req.con.data);
|
qse_printf (QSE_T("content = [%.*S]\n"), (int)http->req.con.size, http->req.con.data);
|
||||||
}
|
}
|
||||||
/* TODO: do the main job here... before the raw buffer is cleared out... */
|
/* TODO: do the main job here... before the raw buffer is cleared out... */
|
||||||
|
#endif
|
||||||
|
|
||||||
clear_request (http);
|
clear_request (http);
|
||||||
|
|
||||||
@ -1349,28 +1192,27 @@ if (http->req.con.size > 0)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '\r':
|
case '\r':
|
||||||
if (http->req.state.crlf == 0 || http->req.state.crlf == 2)
|
if (http->reqx.s.crlf == 0 || http->reqx.s.crlf == 2)
|
||||||
http->req.state.crlf++;
|
http->reqx.s.crlf++;
|
||||||
else http->req.state.crlf = 1;
|
else http->reqx.s.crlf = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* increment length of a request in raw
|
/* increment length of a request in raw
|
||||||
* excluding crlf */
|
* excluding crlf */
|
||||||
http->req.state.plen++;
|
http->reqx.s.plen++;
|
||||||
/* mark that neither CR nor LF was seen */
|
/* mark that neither CR nor LF was seen */
|
||||||
http->req.state.crlf = 0;
|
http->reqx.s.crlf = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptr > req)
|
if (ptr > req)
|
||||||
{
|
{
|
||||||
/* enbuffer the incomplete request */
|
/* enbuffer the incomplete request */
|
||||||
if (push_to_buffer (http, &http->req.raw, req, ptr - req) <= -1) return -1;
|
if (push_to_buffer (http, &http->reqx.b.raw, req, ptr - req) <= -1) return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
feedme_more:
|
feedme_more:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user