Add engine tests
This commit is contained in:
@@ -1,2 +1,11 @@
|
||||
misc
|
||||
coverage_report
|
||||
|
||||
# Coverage stuff
|
||||
*.info
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.exe
|
||||
|
||||
test.out
|
||||
test.exe
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
.PHONY: all report
|
||||
|
||||
#LFLAGS = -lws2_32
|
||||
LFLAGS = -lssl -lcrypto -ggdb
|
||||
OSTAG = LINUX
|
||||
#OSTAG = WINDOWS
|
||||
|
||||
EXT_WINDOWS = .exe
|
||||
EXT_LINUX = .out
|
||||
|
||||
LFLAGS_WINDOWS = -lws2_32
|
||||
LFLAGS_LINUX = -lssl -lcrypto -ggdb
|
||||
|
||||
LFLAGS = ${LFLAGS_${OSTAG}}
|
||||
EXT = ${EXT_${OSTAG}}
|
||||
|
||||
all:
|
||||
#gcc -o test tests/test.c tests/test_branch_coverage.c http.c -fprofile-arcs -ftest-coverage
|
||||
gcc -o test$(EXT) tests/test.c tests/test_branch_coverage_parse.c tests/test_branch_coverage_engine.c tests/test_fuzz_engine.c tinyhttp.c -fprofile-arcs -ftest-coverage $(LFLAGS)
|
||||
|
||||
report:
|
||||
lcov --capture --directory . --output-file coverage.info --rc lcov_branch_coverage=1
|
||||
genhtml coverage.info --output-directory coverage_report --rc lcov_branch_coverage=1 --rc genhtml_branch_coverage=1
|
||||
|
||||
clean:
|
||||
rm *.gcda *.gcno coverage.info test test.exe
|
||||
rm *.gcda *.gcno coverage.info test$(EXT_WINDOWS) test$(EXT_LINUX)
|
||||
|
||||
+73
-4
@@ -1,9 +1,76 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../http.h"
|
||||
#include "test.h"
|
||||
|
||||
#define TEST(X) {if (!(X)) __builtin_trap(); }
|
||||
static const char *statestr(HTTP_EngineState state)
|
||||
{
|
||||
switch (state) {
|
||||
case HTTP_ENGINE_STATE_NONE : return "NONE";
|
||||
case HTTP_ENGINE_STATE_CLIENT_PREP_URL : return "CLIENT_PREP_URL";
|
||||
case HTTP_ENGINE_STATE_CLIENT_PREP_HEADER : return "CLIENT_PREP_HEADER";
|
||||
case HTTP_ENGINE_STATE_CLIENT_PREP_BODY_BUF: return "CLIENT_PREP_BODY_BUF";
|
||||
case HTTP_ENGINE_STATE_CLIENT_PREP_BODY_ACK: return "CLIENT_PREP_BODY_ACK";
|
||||
case HTTP_ENGINE_STATE_CLIENT_PREP_ERROR : return "CLIENT_PREP_ERROR";
|
||||
case HTTP_ENGINE_STATE_CLIENT_SEND_BUF : return "CLIENT_SEND_BUF";
|
||||
case HTTP_ENGINE_STATE_CLIENT_SEND_ACK : return "CLIENT_SEND_ACK";
|
||||
case HTTP_ENGINE_STATE_CLIENT_RECV_BUF : return "CLIENT_RECV_BUF";
|
||||
case HTTP_ENGINE_STATE_CLIENT_RECV_ACK : return "CLIENT_RECV_ACK";
|
||||
case HTTP_ENGINE_STATE_CLIENT_READY : return "CLIENT_READY";
|
||||
case HTTP_ENGINE_STATE_CLIENT_CLOSED : return "CLIENT_CLOSED";
|
||||
case HTTP_ENGINE_STATE_SERVER_RECV_BUF : return "SERVER_RECV_BUF";
|
||||
case HTTP_ENGINE_STATE_SERVER_RECV_ACK : return "SERVER_RECV_ACK";
|
||||
case HTTP_ENGINE_STATE_SERVER_PREP_STATUS : return "SERVER_PREP_STATUS";
|
||||
case HTTP_ENGINE_STATE_SERVER_PREP_HEADER : return "SERVER_PREP_HEADER";
|
||||
case HTTP_ENGINE_STATE_SERVER_PREP_BODY_BUF: return "SERVER_PREP_BODY_BUF";
|
||||
case HTTP_ENGINE_STATE_SERVER_PREP_BODY_ACK: return "SERVER_PREP_BODY_ACK";
|
||||
case HTTP_ENGINE_STATE_SERVER_PREP_ERROR : return "SERVER_PREP_ERROR";
|
||||
case HTTP_ENGINE_STATE_SERVER_SEND_BUF : return "SERVER_SEND_BUF";
|
||||
case HTTP_ENGINE_STATE_SERVER_SEND_ACK : return "SERVER_SEND_ACK";
|
||||
case HTTP_ENGINE_STATE_SERVER_CLOSED : return "SERVER_CLOSED";
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
void test_branch_coverage(void);
|
||||
void testeq_engstate(HTTP_EngineState l, HTTP_EngineState r, HTTP_String uneval_l, HTTP_String uneval_r, const char *file, int line)
|
||||
{
|
||||
if (l != r) {
|
||||
printf("Test failed at %s:%d\n", file, line);
|
||||
printf(" TEST_EQ(%.*s, %.*s) -> TEST_EQ(%s, %s)\n",
|
||||
(int) uneval_l.len, uneval_l.ptr,
|
||||
(int) uneval_r.len, uneval_r.ptr,
|
||||
statestr(l), statestr(r));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void testeq_int(int l, int r, HTTP_String uneval_l, HTTP_String uneval_r, const char *file, int line)
|
||||
{
|
||||
if (l != r) {
|
||||
printf("Test failed at %s:%d\n", file, line);
|
||||
printf(" TEST_EQ(%.*s, %.*s) -> TEST_EQ(%d, %d)\n",
|
||||
(int) uneval_l.len, uneval_l.ptr,
|
||||
(int) uneval_r.len, uneval_r.ptr,
|
||||
l, r);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void testeq_str(HTTP_String l, HTTP_String r, HTTP_String uneval_l, HTTP_String uneval_r, const char *file, int line)
|
||||
{
|
||||
if (!http_streq(l, r)) {
|
||||
printf("Test failed at %s:%d\n", file, line);
|
||||
printf(" TEST_EQ(\"%.*s\", \"%.*s\") -> TEST_EQ(%.*s, %.*s)\n",
|
||||
(int) uneval_l.len, uneval_l.ptr,
|
||||
(int) uneval_r.len, uneval_r.ptr,
|
||||
(int) l.len, l.ptr,
|
||||
(int) r.len, r.ptr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void test_branch_coverage_parse(void);
|
||||
void test_branch_coverage_engine(void);
|
||||
void test_fuzz_engine(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@@ -16,7 +83,9 @@ int main(void)
|
||||
TEST(ret == 0);
|
||||
}
|
||||
|
||||
test_branch_coverage();
|
||||
//test_branch_coverage_parse();
|
||||
test_branch_coverage_engine();
|
||||
//test_fuzz_engine();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <stdio.h>
|
||||
#include "../tinyhttp.h"
|
||||
|
||||
#define S HTTP_STR
|
||||
|
||||
#define COUNT(X) (int) (sizeof(X)/sizeof((X)[0]))
|
||||
#define TEST(X) {if (!(X)) { fprintf(stderr, "Failed test at %s:%d\n", __FILE__, __LINE__); __builtin_trap(); }}
|
||||
|
||||
void testeq_engstate(HTTP_EngineState l, HTTP_EngineState r, HTTP_String uneval_l, HTTP_String uneval_r, const char *file, int line);
|
||||
void testeq_int(int l, int r, HTTP_String uneval_l, HTTP_String uneval_r, const char *file, int line);
|
||||
void testeq_str(HTTP_String l, HTTP_String r, HTTP_String uneval_l, HTTP_String uneval_r, const char *file, int line);
|
||||
#define TEST_EQ(X, Y) _Generic((X), HTTP_String: testeq_str, int: testeq_int, HTTP_EngineState: testeq_engstate)((X), (Y), S(#X), S(#Y), __FILE__, __LINE__)
|
||||
@@ -0,0 +1,138 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "test.h"
|
||||
|
||||
static void *memfunc(HTTP_MemoryFuncTag tag,
|
||||
void *ptr, int len, void *data)
|
||||
{
|
||||
(void) data;
|
||||
switch (tag) {
|
||||
|
||||
case HTTP_MEMFUNC_MALLOC:
|
||||
return malloc(len);
|
||||
|
||||
case HTTP_MEMFUNC_FREE:
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void test_engine_server(void)
|
||||
{
|
||||
HTTP_Engine eng;
|
||||
|
||||
{
|
||||
int client = 0;
|
||||
memset(&eng, 0, sizeof(eng));
|
||||
http_engine_init(&eng, client, memfunc, NULL);
|
||||
TEST_EQ((int) http_engine_state(&eng), HTTP_ENGINE_STATE_SERVER_RECV_BUF);
|
||||
http_engine_free(&eng);
|
||||
}
|
||||
|
||||
{
|
||||
int client = 1;
|
||||
memset(&eng, 0, sizeof(eng));
|
||||
http_engine_init(&eng, client, memfunc, NULL);
|
||||
TEST_EQ((int) http_engine_state(&eng), HTTP_ENGINE_STATE_CLIENT_PREP_URL);
|
||||
http_engine_free(&eng);
|
||||
}
|
||||
}
|
||||
|
||||
static int read_from_client_engine(HTTP_Engine *eng, char *dst, int cap)
|
||||
{
|
||||
TEST_EQ(http_engine_state(eng), HTTP_ENGINE_STATE_CLIENT_SEND_BUF);
|
||||
|
||||
int num = 0;
|
||||
do {
|
||||
int len;
|
||||
char *src = http_engine_sendbuf(eng, &len);
|
||||
TEST_EQ(http_engine_state(eng), HTTP_ENGINE_STATE_CLIENT_SEND_ACK);
|
||||
|
||||
TEST(src != NULL);
|
||||
TEST(cap - num >= len);
|
||||
memcpy(dst + num, src, len);
|
||||
|
||||
num += len;
|
||||
http_engine_sendack(eng, len);
|
||||
} while (http_engine_state(eng) == HTTP_ENGINE_STATEBIT_SEND_BUF);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static void send_into_client_engine(HTTP_Engine *eng, char *src, int len)
|
||||
{
|
||||
int num = 0;
|
||||
while (num < len) {
|
||||
TEST_EQ(http_engine_state(eng), HTTP_ENGINE_STATE_CLIENT_RECV_BUF);
|
||||
|
||||
int cap;
|
||||
char *dst = http_engine_recvbuf(eng, &cap);
|
||||
TEST_EQ(http_engine_state(eng), HTTP_ENGINE_STATE_CLIENT_RECV_ACK);
|
||||
TEST(dst != NULL);
|
||||
TEST(cap > 0);
|
||||
|
||||
int cpy = len - num;
|
||||
if (cpy > cap) cpy = cap;
|
||||
|
||||
memcpy(dst, src + num, cpy);
|
||||
|
||||
num += cpy;
|
||||
http_engine_recvack(eng, cpy);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_engine_client_basic_flow(void)
|
||||
{
|
||||
int client = 1;
|
||||
HTTP_Engine eng;
|
||||
http_engine_init(&eng, client, memfunc, NULL);
|
||||
TEST_EQ(http_engine_state(&eng), HTTP_ENGINE_STATE_CLIENT_PREP_URL);
|
||||
|
||||
http_engine_url(&eng, HTTP_METHOD_GET, "http://some.url.com/some/endpoint", 1);
|
||||
TEST_EQ(http_engine_state(&eng), HTTP_ENGINE_STATE_CLIENT_PREP_HEADER);
|
||||
|
||||
http_engine_header(&eng, "headerA: valueA", -1);
|
||||
TEST_EQ(http_engine_state(&eng), HTTP_ENGINE_STATE_CLIENT_PREP_HEADER);
|
||||
|
||||
http_engine_body(&eng, "Hello, world!", -1);
|
||||
TEST_EQ(http_engine_state(&eng), HTTP_ENGINE_STATE_CLIENT_PREP_BODY_BUF);
|
||||
|
||||
http_engine_done(&eng);
|
||||
TEST_EQ(http_engine_state(&eng), HTTP_ENGINE_STATE_CLIENT_SEND_BUF);
|
||||
|
||||
{
|
||||
char sendbuf[1<<10];
|
||||
int sendnum;
|
||||
sendnum = read_from_client_engine(&eng, sendbuf, (int) sizeof(sendbuf));
|
||||
|
||||
char expect[] =
|
||||
"GET /some/endpoint HTTP/1.1\r\n"
|
||||
"Host: some.url.com\r\n"
|
||||
"headerA: valueA\r\n"
|
||||
"Connection: Keep-Alive\r\n"
|
||||
"Content-Length: 13 \r\n"
|
||||
"\r\n"
|
||||
"Hello, world!";
|
||||
|
||||
TEST_EQ(sendnum, strlen(expect));
|
||||
TEST_EQ(memcmp(expect, sendbuf, strlen(expect)), 0);
|
||||
}
|
||||
|
||||
{
|
||||
char response[] =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"\r\n";
|
||||
send_into_client_engine(&eng, response, strlen(response));
|
||||
}
|
||||
|
||||
TEST_EQ(http_engine_state(&eng), HTTP_ENGINE_STATE_CLIENT_READY);
|
||||
|
||||
http_engine_free(&eng);
|
||||
}
|
||||
|
||||
void test_branch_coverage_engine(void)
|
||||
{
|
||||
test_engine_server();
|
||||
test_engine_client_basic_flow();
|
||||
}
|
||||
@@ -1,37 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../http.h"
|
||||
|
||||
#define COUNT(X) (int) (sizeof(X)/sizeof((X)[0]))
|
||||
#define TEST(X) {if (!(X)) { fprintf(stderr, "Failed test at %s:%d\n", __FILE__, __LINE__); __builtin_trap(); }}
|
||||
|
||||
#define TEST_EQ(X, Y) _Generic((X), HTTP_String: testeq_str, int: testeq_int)((X), (Y), S(#X), S(#Y), __FILE__, __LINE__)
|
||||
|
||||
static void testeq_int(int l, int r, HTTP_String uneval_l, HTTP_String uneval_r, const char *file, int line)
|
||||
{
|
||||
if (l != r) {
|
||||
printf("Test failed at %s:%d\n", file, line);
|
||||
printf(" TEST_EQ(%.*s, %.*s) -> TEST_EQ(%d, %d)\n",
|
||||
(int) uneval_l.len, uneval_l.ptr,
|
||||
(int) uneval_r.len, uneval_r.ptr,
|
||||
l, r);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void testeq_str(HTTP_String l, HTTP_String r, HTTP_String uneval_l, HTTP_String uneval_r, const char *file, int line)
|
||||
{
|
||||
if (!http_streq(l, r)) {
|
||||
printf("Test failed at %s:%d\n", file, line);
|
||||
printf(" TEST_EQ(\"%.*s\", \"%.*s\") -> TEST_EQ(%.*s, %.*s)\n",
|
||||
(int) uneval_l.len, uneval_l.ptr,
|
||||
(int) uneval_r.len, uneval_r.ptr,
|
||||
(int) l.len, l.ptr,
|
||||
(int) r.len, r.ptr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#include "test.h"
|
||||
|
||||
static void test_branch_coverage_parse_request(void)
|
||||
{
|
||||
@@ -314,8 +283,6 @@ static void test_branch_coverage_parse_response(void)
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#define S HTTP_STR
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
int cap;
|
||||
@@ -510,7 +477,7 @@ static void test_branch_coverage_parse_url(void)
|
||||
}
|
||||
}
|
||||
|
||||
void test_branch_coverage(void)
|
||||
void test_branch_coverage_parse(void)
|
||||
{
|
||||
test_branch_coverage_parse_request();
|
||||
test_branch_coverage_parse_response();
|
||||
@@ -0,0 +1,230 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include "test.h"
|
||||
|
||||
static void *memfunc(HTTP_MemoryFuncTag tag,
|
||||
void *ptr, int len, void *data)
|
||||
{
|
||||
(void) data;
|
||||
switch (tag) {
|
||||
|
||||
case HTTP_MEMFUNC_MALLOC:
|
||||
{
|
||||
void *ptr = NULL;
|
||||
|
||||
int x = rand() & 31;
|
||||
if (x == 0)
|
||||
ptr = malloc(len);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
case HTTP_MEMFUNC_FREE:
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *http_statestr(int state)
|
||||
{
|
||||
switch (state) {
|
||||
case HTTP_ENGINE_STATE_NONE : return "NONE";
|
||||
case HTTP_ENGINE_STATE_CLIENT_PREP_URL : return "CLIENT_PREP_URL";
|
||||
case HTTP_ENGINE_STATE_CLIENT_PREP_HEADER : return "CLIENT_PREP_HEADER";
|
||||
case HTTP_ENGINE_STATE_CLIENT_PREP_BODY_BUF: return "CLIENT_PREP_BODY_BUF";
|
||||
case HTTP_ENGINE_STATE_CLIENT_PREP_BODY_ACK: return "CLIENT_PREP_BODY_ACK";
|
||||
case HTTP_ENGINE_STATE_CLIENT_PREP_ERROR : return "CLIENT_PREP_ERROR";
|
||||
case HTTP_ENGINE_STATE_CLIENT_SEND_BUF : return "CLIENT_SEND_BUF";
|
||||
case HTTP_ENGINE_STATE_CLIENT_SEND_ACK : return "CLIENT_SEND_ACK";
|
||||
case HTTP_ENGINE_STATE_CLIENT_RECV_BUF : return "CLIENT_RECV_BUF";
|
||||
case HTTP_ENGINE_STATE_CLIENT_RECV_ACK : return "CLIENT_RECV_ACK";
|
||||
case HTTP_ENGINE_STATE_CLIENT_READY : return "CLIENT_READY";
|
||||
case HTTP_ENGINE_STATE_CLIENT_CLOSED : return "CLIENT_CLOSED";
|
||||
case HTTP_ENGINE_STATE_SERVER_RECV_BUF : return "SERVER_RECV_BUF";
|
||||
case HTTP_ENGINE_STATE_SERVER_RECV_ACK : return "SERVER_RECV_ACK";
|
||||
case HTTP_ENGINE_STATE_SERVER_PREP_STATUS : return "SERVER_PREP_STATUS";
|
||||
case HTTP_ENGINE_STATE_SERVER_PREP_HEADER : return "SERVER_PREP_HEADER";
|
||||
case HTTP_ENGINE_STATE_SERVER_PREP_BODY_BUF: return "SERVER_PREP_BODY_BUF";
|
||||
case HTTP_ENGINE_STATE_SERVER_PREP_BODY_ACK: return "SERVER_PREP_BODY_ACK";
|
||||
case HTTP_ENGINE_STATE_SERVER_PREP_ERROR : return "SERVER_PREP_ERROR";
|
||||
case HTTP_ENGINE_STATE_SERVER_SEND_BUF : return "SERVER_SEND_BUF";
|
||||
case HTTP_ENGINE_STATE_SERVER_SEND_ACK : return "SERVER_SEND_ACK";
|
||||
case HTTP_ENGINE_STATE_SERVER_CLOSED : return "SERVER_CLOSED";
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
static sig_atomic_t stop = 0;
|
||||
|
||||
static void handle_signal(int dummy)
|
||||
{
|
||||
stop = 1;
|
||||
}
|
||||
|
||||
void test_fuzz_engine(void)
|
||||
{
|
||||
signal(SIGINT, handle_signal);
|
||||
|
||||
char txt1[] = "";
|
||||
char txt2[] = "GET / HTTP/1.1\r\n\r\n";
|
||||
char txt3[] = "GET / HTTP/1.1\n";
|
||||
char txt4[] = "HTTP/1.1 200 OK\r\n";
|
||||
char txt5[] = "HTTP/1.1 200 OK\r\n\r\n";
|
||||
|
||||
int next_recvack = 0;
|
||||
int next_sendack = 0;
|
||||
int next_bodyack = 0;
|
||||
int curr_bodycap = 0;
|
||||
int client = 0;
|
||||
HTTP_Engine eng;
|
||||
http_engine_init(&eng, client, memfunc, NULL);
|
||||
while (!stop) {
|
||||
//printf("%s\n", http_statestr(http_engine_state(&eng)));
|
||||
switch (rand() % 21) {
|
||||
|
||||
int max;
|
||||
char *buf;
|
||||
|
||||
case 0:
|
||||
//printf("http_engine_free/http_engine_init\n");
|
||||
client = !client;
|
||||
http_engine_free(&eng);
|
||||
http_engine_init(&eng, client, memfunc, NULL);
|
||||
next_recvack = 0;
|
||||
next_sendack = 0;
|
||||
next_bodyack = 0;
|
||||
curr_bodycap = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
//printf("http_engine_recvbuf (1)\n");
|
||||
buf = http_engine_recvbuf(&eng, &max);
|
||||
memcpy(buf, txt1, strlen(txt1));
|
||||
next_recvack = strlen(txt1);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
//printf("http_engine_recvbuf (2)\n");
|
||||
buf = http_engine_recvbuf(&eng, &max);
|
||||
if (buf) {
|
||||
memcpy(buf, txt2, strlen(txt2));
|
||||
next_recvack = strlen(txt2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
//printf("http_engine_recvbuf (3)\n");
|
||||
buf = http_engine_recvbuf(&eng, &max);
|
||||
if (buf) {
|
||||
memcpy(buf, txt3, strlen(txt3));
|
||||
next_recvack = strlen(txt3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
//printf("http_engine_recvbuf (4)\n");
|
||||
buf = http_engine_recvbuf(&eng, &max);
|
||||
if (buf) {
|
||||
memcpy(buf, txt4, strlen(txt4));
|
||||
next_recvack = strlen(txt4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
//printf("http_engine_recvbuf (5)\n");
|
||||
buf = http_engine_recvbuf(&eng, &max);
|
||||
if (buf) {
|
||||
memcpy(buf, txt5, strlen(txt5));
|
||||
next_recvack = strlen(txt5);
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
//printf("http_engine_recvack\n");
|
||||
http_engine_recvack(&eng, next_recvack);
|
||||
next_recvack = 0;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
//printf("http_engine_sendbuf\n");
|
||||
buf = http_engine_sendbuf(&eng, &max);
|
||||
if (max)
|
||||
next_sendack = rand() % max;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
//printf("http_engine_sendack\n");
|
||||
http_engine_sendack(&eng, next_sendack);
|
||||
next_sendack = 0;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
//printf("http_engine_getreq\n");
|
||||
http_engine_getreq(&eng);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
//printf("http_engine_getres\n");
|
||||
http_engine_getres(&eng);
|
||||
break;
|
||||
|
||||
case 11:
|
||||
//printf("http_engine_url\n");
|
||||
http_engine_url(&eng, HTTP_METHOD_GET, "", 0);
|
||||
break;
|
||||
|
||||
case 12:
|
||||
//printf("http_engine_url\n");
|
||||
http_engine_url(&eng, HTTP_METHOD_GET, "http://127.0.0.1/hello", 0);
|
||||
break;
|
||||
|
||||
case 13:
|
||||
//printf("http_engine_status\n");
|
||||
http_engine_status(&eng, 200);
|
||||
break;
|
||||
|
||||
case 14:
|
||||
//printf("http_engine_header\n");
|
||||
http_engine_header(&eng, "x:y", -1);
|
||||
break;
|
||||
|
||||
case 15:
|
||||
//printf("http_engine_bodycap\n");
|
||||
http_engine_bodycap(&eng, rand() % 1000);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
//printf("http_engine_bodybuf\n");
|
||||
buf = http_engine_bodybuf(&eng, &max);
|
||||
if (buf && max) {
|
||||
max = rand() % max;
|
||||
memset(buf, 0xFF, max);
|
||||
next_bodyack = max;
|
||||
}
|
||||
break;
|
||||
|
||||
case 17:
|
||||
//printf("http_engine_bodyack\n");
|
||||
http_engine_bodyack(&eng, next_bodyack);
|
||||
next_bodyack = 0;
|
||||
break;
|
||||
|
||||
case 18:
|
||||
//printf("http_engine_done\n");
|
||||
http_engine_done(&eng);
|
||||
break;
|
||||
|
||||
case 19:
|
||||
//printf("http_engine_undo\n");
|
||||
http_engine_undo(&eng);
|
||||
break;
|
||||
|
||||
case 20:
|
||||
//printf("http_engine_close\n");
|
||||
http_engine_close(&eng);
|
||||
break;
|
||||
}
|
||||
}
|
||||
http_engine_free(&eng);
|
||||
}
|
||||
+173
-154
@@ -1,4 +1,4 @@
|
||||
#include "http.h"
|
||||
#include "tinyhttp.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
@@ -936,6 +936,14 @@ static int parse_request(Scanner *s, HTTP_Request *req)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int find_header(HTTP_Header *headers, int num_headers, HTTP_String name)
|
||||
{
|
||||
for (int i = 0; i < num_headers; i++)
|
||||
if (http_streqcase(name, headers[i].name))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_response(Scanner *s, HTTP_Response *res)
|
||||
{
|
||||
if (!contains_head(s->src + s->cur, s->len - s->cur))
|
||||
@@ -992,14 +1000,16 @@ static int parse_response(Scanner *s, HTTP_Response *res)
|
||||
return num_headers;
|
||||
res->num_headers = num_headers;
|
||||
|
||||
unsigned long long content_length;
|
||||
for (int i = 0; i < num_headers; i++)
|
||||
if (http_streqcase(res->headers[i].name, HTTP_STR("Content-Length"))) {
|
||||
if (parse_content_length(res->headers[i].value.ptr, res->headers[i].value.len, &content_length) < 0)
|
||||
return -1;
|
||||
break;
|
||||
int content_length_index = find_header(res->headers, res->num_headers, HTTP_STR("Content-Length"));
|
||||
if (content_length_index == -1) {
|
||||
res->body.ptr = NULL;
|
||||
res->body.len = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ASSERT(0);
|
||||
return -1;
|
||||
/*
|
||||
if (content_length > 1<<20) {
|
||||
// TODO
|
||||
}
|
||||
@@ -1010,7 +1020,10 @@ static int parse_response(Scanner *s, HTTP_Response *res)
|
||||
res->body.ptr = s->src + s->cur;
|
||||
res->body.len = content_length;
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
*/
|
||||
}
|
||||
|
||||
int http_parse_ipv4(char *src, int len, HTTP_IPv4 *ipv4)
|
||||
@@ -1380,6 +1393,9 @@ static void
|
||||
byte_queue_patch(HTTP_ByteQueue *queue, HTTP_ByteQueueOffset off,
|
||||
char *src, unsigned int len)
|
||||
{
|
||||
if (queue->flags & BYTE_QUEUE_ERROR)
|
||||
return;
|
||||
|
||||
// Check that the offset is in range
|
||||
ASSERT(off >= queue->curs && off - queue->curs < queue->used);
|
||||
|
||||
@@ -1394,6 +1410,9 @@ byte_queue_patch(HTTP_ByteQueue *queue, HTTP_ByteQueueOffset off,
|
||||
static void
|
||||
byte_queue_remove_from_offset(HTTP_ByteQueue *queue, HTTP_ByteQueueOffset offset)
|
||||
{
|
||||
if (queue->flags & BYTE_QUEUE_ERROR)
|
||||
return;
|
||||
|
||||
unsigned long long num = (queue->curs + queue->used) - offset;
|
||||
ASSERT(num <= queue->used);
|
||||
|
||||
@@ -1514,6 +1533,9 @@ char *http_engine_recvbuf(HTTP_Engine *eng, int *cap)
|
||||
byte_queue_write_setmincap(&eng->input, 1<<9);
|
||||
if (byte_queue_error(&eng->input)) {
|
||||
*cap = 0;
|
||||
if (eng->state & HTTP_ENGINE_STATEBIT_CLIENT)
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_CLOSED;
|
||||
else
|
||||
eng->state = HTTP_ENGINE_STATE_SERVER_CLOSED;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1521,14 +1543,6 @@ char *http_engine_recvbuf(HTTP_Engine *eng, int *cap)
|
||||
return byte_queue_write_buf(&eng->input, cap);
|
||||
}
|
||||
|
||||
static int find_header(HTTP_Request *req, HTTP_String name)
|
||||
{
|
||||
for (int i = 0; i < req->num_headers; i++)
|
||||
if (http_streqcase(name, req->headers[i].name))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
should_keep_alive(HTTP_Engine *eng)
|
||||
{
|
||||
@@ -1553,7 +1567,7 @@ should_keep_alive(HTTP_Engine *eng)
|
||||
|
||||
// TODO: This assumes "Connection" can only hold a single token,
|
||||
// but this is not true.
|
||||
int i = find_header(req, HTTP_STR("Connection"));
|
||||
int i = find_header(req->headers, req->num_headers, HTTP_STR("Connection"));
|
||||
if (i >= 0 && http_streqcase(req->headers[i].value, HTTP_STR("Close")))
|
||||
return 0;
|
||||
|
||||
@@ -1564,7 +1578,7 @@ static void process_incoming_request(HTTP_Engine *eng)
|
||||
{
|
||||
ASSERT(eng->state == HTTP_ENGINE_STATE_SERVER_RECV_ACK
|
||||
|| eng->state == HTTP_ENGINE_STATE_SERVER_SEND_ACK
|
||||
|| eng->state == HTTP_ENGINE_STATE_SERVER_PREP_BODY
|
||||
|| eng->state == HTTP_ENGINE_STATE_SERVER_PREP_BODY_BUF
|
||||
|| eng->state == HTTP_ENGINE_STATE_SERVER_PREP_ERROR);
|
||||
|
||||
char *src;
|
||||
@@ -1695,6 +1709,8 @@ void http_engine_url(HTTP_Engine *eng, HTTP_Method method, char *url, int minor)
|
||||
if (eng->state != HTTP_ENGINE_STATE_CLIENT_PREP_URL)
|
||||
return;
|
||||
|
||||
eng->response_offset = byte_queue_offset(&eng->output); // TODO: rename response_offset to something that makes sense for clients
|
||||
|
||||
int len = strlen(url);
|
||||
|
||||
HTTP_URL parsed_url;
|
||||
@@ -1704,44 +1720,33 @@ void http_engine_url(HTTP_Engine *eng, HTTP_Method method, char *url, int minor)
|
||||
return;
|
||||
}
|
||||
|
||||
char *method_str = "???";
|
||||
HTTP_String method_and_space = HTTP_STR("???");
|
||||
switch (method) {
|
||||
case HTTP_METHOD_GET : method_str = "GET"; break;
|
||||
case HTTP_METHOD_HEAD : method_str = "HEAD"; break;
|
||||
case HTTP_METHOD_POST : method_str = "POST"; break;
|
||||
case HTTP_METHOD_PUT : method_str = "PUT"; break;
|
||||
case HTTP_METHOD_DELETE : method_str = "DELETE"; break;
|
||||
case HTTP_METHOD_CONNECT: method_str = "CONNECT"; break;
|
||||
case HTTP_METHOD_OPTIONS: method_str = "OPTIONS"; break;
|
||||
case HTTP_METHOD_TRACE : method_str = "TRACE"; break;
|
||||
case HTTP_METHOD_PATCH : method_str = "PATCH"; break;
|
||||
case HTTP_METHOD_GET : method_and_space = HTTP_STR("GET "); break;
|
||||
case HTTP_METHOD_HEAD : method_and_space = HTTP_STR("HEAD "); break;
|
||||
case HTTP_METHOD_POST : method_and_space = HTTP_STR("POST "); break;
|
||||
case HTTP_METHOD_PUT : method_and_space = HTTP_STR("PUT "); break;
|
||||
case HTTP_METHOD_DELETE : method_and_space = HTTP_STR("DELETE "); break;
|
||||
case HTTP_METHOD_CONNECT: method_and_space = HTTP_STR("CONNECT "); break;
|
||||
case HTTP_METHOD_OPTIONS: method_and_space = HTTP_STR("OPTIONS "); break;
|
||||
case HTTP_METHOD_TRACE : method_and_space = HTTP_STR("TRACE "); break;
|
||||
case HTTP_METHOD_PATCH : method_and_space = HTTP_STR("PATCH "); break;
|
||||
}
|
||||
|
||||
HTTP_String path = parsed_url.path;
|
||||
if (path.len == 0)
|
||||
path = HTTP_STR("/");
|
||||
|
||||
byte_queue_write_fmt(&eng->output,
|
||||
"%s %.*s%.*s HTTP/1.%d\r\n",
|
||||
method_str,
|
||||
path.len,
|
||||
path.ptr,
|
||||
parsed_url.query.len,
|
||||
parsed_url.query.ptr,
|
||||
minor
|
||||
);
|
||||
|
||||
byte_queue_write(&eng->output, method_and_space.ptr, method_and_space.len);
|
||||
byte_queue_write(&eng->output, path.ptr, path.len);
|
||||
byte_queue_write(&eng->output, parsed_url.query.ptr, parsed_url.query.len);
|
||||
byte_queue_write(&eng->output, minor ? " HTTP/1.1\r\nHost: " : " HTTP/1.0\r\nHost: ", -1);
|
||||
byte_queue_write(&eng->output, parsed_url.authority.host.text.ptr, parsed_url.authority.host.text.len);
|
||||
if (parsed_url.authority.port > 0)
|
||||
byte_queue_write_fmt(&eng->output,
|
||||
"Host: %.*s:%d\r\n",
|
||||
parsed_url.authority.host.text.len,
|
||||
parsed_url.authority.host.text.ptr,
|
||||
parsed_url.authority.port);
|
||||
else
|
||||
byte_queue_write_fmt(&eng->output,
|
||||
"Host: %.*s\r\n",
|
||||
parsed_url.authority.host.text.len,
|
||||
parsed_url.authority.host.text.ptr);
|
||||
byte_queue_write_fmt(&eng->output, "%d", parsed_url.authority.port);
|
||||
byte_queue_write(&eng->output, "\r\n", 2);
|
||||
|
||||
eng->keepalive = 1; // TODO
|
||||
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_PREP_HEADER;
|
||||
}
|
||||
@@ -1831,6 +1836,8 @@ void http_engine_header(HTTP_Engine *eng, const char *src, int len)
|
||||
if ((eng->state & HTTP_ENGINE_STATEBIT_PREP_HEADER) == 0)
|
||||
return;
|
||||
|
||||
if (len < 0) len = strlen(src);
|
||||
|
||||
// TODO: Check that the header is valid
|
||||
|
||||
byte_queue_write(&eng->output, src, len);
|
||||
@@ -1857,14 +1864,10 @@ void http_engine_header_fmt(HTTP_Engine *eng, const char *fmt, ...)
|
||||
}
|
||||
|
||||
static void
|
||||
append_special_headers(HTTP_Engine *eng)
|
||||
complete_message_head(HTTP_Engine *eng)
|
||||
{
|
||||
ASSERT((eng->state & HTTP_ENGINE_STATEBIT_CLIENT) == 0);
|
||||
|
||||
if (eng->keepalive)
|
||||
byte_queue_write(&eng->output, "Connection: Keep-Alive\r\n", -1);
|
||||
else
|
||||
byte_queue_write(&eng->output, "Connection: Close\r\n", -1);
|
||||
if (eng->keepalive) byte_queue_write(&eng->output, "Connection: Keep-Alive\r\n", -1);
|
||||
else byte_queue_write(&eng->output, "Connection: Close\r\n", -1);
|
||||
|
||||
byte_queue_write(&eng->output, "Content-Length: ", -1);
|
||||
eng->content_length_value_offset = byte_queue_offset(&eng->output);
|
||||
@@ -1874,107 +1877,8 @@ append_special_headers(HTTP_Engine *eng)
|
||||
eng->content_length_offset = byte_queue_offset(&eng->output);
|
||||
}
|
||||
|
||||
void http_engine_body(HTTP_Engine *eng, void *src, int len)
|
||||
static void complete_message_body(HTTP_Engine *eng)
|
||||
{
|
||||
ASSERT(len >= 0);
|
||||
|
||||
http_engine_bodycap(eng, len);
|
||||
int cap;
|
||||
char *buf = http_engine_bodybuf(eng, &cap);
|
||||
if (buf) {
|
||||
memcpy(buf, src, len);
|
||||
http_engine_bodyack(eng, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void ensure_body_entered(HTTP_Engine *eng)
|
||||
{
|
||||
if (eng->state & HTTP_ENGINE_STATEBIT_CLIENT) {
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_CLIENT_PREP_HEADER) {
|
||||
byte_queue_write(&eng->output, "\r\n", 2);
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_PREP_BODY;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_SERVER_PREP_HEADER) {
|
||||
append_special_headers(eng);
|
||||
eng->state = HTTP_ENGINE_STATE_SERVER_PREP_BODY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void http_engine_bodycap(HTTP_Engine *eng, int mincap)
|
||||
{
|
||||
ensure_body_entered(eng);
|
||||
if (eng->state != HTTP_ENGINE_STATE_CLIENT_PREP_BODY &&
|
||||
eng->state != HTTP_ENGINE_STATE_SERVER_PREP_BODY)
|
||||
return;
|
||||
|
||||
byte_queue_write_setmincap(&eng->output, mincap);
|
||||
}
|
||||
|
||||
char *http_engine_bodybuf(HTTP_Engine *eng, int *cap)
|
||||
{
|
||||
ensure_body_entered(eng);
|
||||
if (eng->state != HTTP_ENGINE_STATE_CLIENT_PREP_BODY &&
|
||||
eng->state != HTTP_ENGINE_STATE_SERVER_PREP_BODY) {
|
||||
*cap = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return byte_queue_write_buf(&eng->output, cap);
|
||||
}
|
||||
|
||||
void http_engine_bodyack(HTTP_Engine *eng, int num)
|
||||
{
|
||||
if (eng->state != HTTP_ENGINE_STATE_CLIENT_PREP_BODY &&
|
||||
eng->state != HTTP_ENGINE_STATE_SERVER_PREP_BODY)
|
||||
return;
|
||||
byte_queue_write_ack(&eng->output, num);
|
||||
}
|
||||
|
||||
void http_engine_done(HTTP_Engine *eng)
|
||||
{
|
||||
if ((eng->state & HTTP_ENGINE_STATEBIT_PREP) == 0)
|
||||
return;
|
||||
|
||||
if (eng->state & HTTP_ENGINE_STATEBIT_CLIENT) {
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_CLIENT_PREP_URL) {
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_CLOSED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_CLIENT_PREP_HEADER) {
|
||||
byte_queue_write(&eng->output, "\r\n", 2);
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_PREP_BODY;
|
||||
}
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_CLIENT_PREP_BODY) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_CLIENT_PREP_ERROR) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
if (byte_queue_error(&eng->output)) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_SEND_BUF;
|
||||
|
||||
} else {
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_SERVER_PREP_HEADER) {
|
||||
append_special_headers(eng);
|
||||
eng->state = HTTP_ENGINE_STATE_SERVER_PREP_BODY;
|
||||
}
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_SERVER_PREP_BODY) {
|
||||
|
||||
unsigned int content_length = byte_queue_size_from_offset(&eng->output, eng->content_length_offset);
|
||||
|
||||
if (content_length > UINT32_MAX) {
|
||||
@@ -1999,7 +1903,121 @@ void http_engine_done(HTTP_Engine *eng)
|
||||
i++;
|
||||
|
||||
byte_queue_patch(&eng->output, eng->content_length_value_offset, tmp + i, 10 - i);
|
||||
}
|
||||
|
||||
void http_engine_body(HTTP_Engine *eng, void *src, int len)
|
||||
{
|
||||
if (len < 0) len = strlen(src);
|
||||
|
||||
http_engine_bodycap(eng, len);
|
||||
int cap;
|
||||
char *buf = http_engine_bodybuf(eng, &cap);
|
||||
if (buf) {
|
||||
memcpy(buf, src, len);
|
||||
http_engine_bodyack(eng, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void ensure_body_entered(HTTP_Engine *eng)
|
||||
{
|
||||
if (eng->state & HTTP_ENGINE_STATEBIT_CLIENT) {
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_CLIENT_PREP_HEADER) {
|
||||
complete_message_head(eng);
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_PREP_BODY_BUF;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_SERVER_PREP_HEADER) {
|
||||
complete_message_head(eng);
|
||||
eng->state = HTTP_ENGINE_STATE_SERVER_PREP_BODY_BUF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void http_engine_bodycap(HTTP_Engine *eng, int mincap)
|
||||
{
|
||||
ensure_body_entered(eng);
|
||||
if (eng->state != HTTP_ENGINE_STATE_CLIENT_PREP_BODY_BUF &&
|
||||
eng->state != HTTP_ENGINE_STATE_SERVER_PREP_BODY_BUF)
|
||||
return;
|
||||
|
||||
byte_queue_write_setmincap(&eng->output, mincap);
|
||||
}
|
||||
|
||||
char *http_engine_bodybuf(HTTP_Engine *eng, int *cap)
|
||||
{
|
||||
ensure_body_entered(eng);
|
||||
if (eng->state != HTTP_ENGINE_STATE_CLIENT_PREP_BODY_BUF &&
|
||||
eng->state != HTTP_ENGINE_STATE_SERVER_PREP_BODY_BUF) {
|
||||
*cap = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (eng->state & HTTP_ENGINE_STATEBIT_CLIENT)
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_PREP_BODY_ACK;
|
||||
else
|
||||
eng->state = HTTP_ENGINE_STATE_SERVER_PREP_BODY_ACK;
|
||||
|
||||
return byte_queue_write_buf(&eng->output, cap);
|
||||
}
|
||||
|
||||
void http_engine_bodyack(HTTP_Engine *eng, int num)
|
||||
{
|
||||
if (eng->state != HTTP_ENGINE_STATE_CLIENT_PREP_BODY_ACK &&
|
||||
eng->state != HTTP_ENGINE_STATE_SERVER_PREP_BODY_ACK)
|
||||
return;
|
||||
|
||||
byte_queue_write_ack(&eng->output, num);
|
||||
|
||||
if (eng->state & HTTP_ENGINE_STATEBIT_CLIENT)
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_PREP_BODY_BUF;
|
||||
else
|
||||
eng->state = HTTP_ENGINE_STATE_SERVER_PREP_BODY_BUF;
|
||||
}
|
||||
|
||||
void http_engine_done(HTTP_Engine *eng)
|
||||
{
|
||||
if ((eng->state & HTTP_ENGINE_STATEBIT_PREP) == 0)
|
||||
return;
|
||||
|
||||
if (eng->state & HTTP_ENGINE_STATEBIT_CLIENT) {
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_CLIENT_PREP_URL) {
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_CLOSED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_CLIENT_PREP_HEADER) {
|
||||
complete_message_head(eng);
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_PREP_BODY_BUF;
|
||||
}
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_CLIENT_PREP_BODY_BUF)
|
||||
complete_message_body(eng);
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_CLIENT_PREP_ERROR) {
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_CLOSED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (byte_queue_error(&eng->output)) {
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_CLOSED;
|
||||
return;
|
||||
}
|
||||
|
||||
eng->state = HTTP_ENGINE_STATE_CLIENT_SEND_BUF;
|
||||
|
||||
} else {
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_SERVER_PREP_HEADER) {
|
||||
complete_message_head(eng);
|
||||
eng->state = HTTP_ENGINE_STATE_SERVER_PREP_BODY_BUF;
|
||||
}
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_SERVER_PREP_BODY_BUF)
|
||||
complete_message_body(eng);
|
||||
|
||||
if (eng->state == HTTP_ENGINE_STATE_SERVER_PREP_ERROR) {
|
||||
byte_queue_remove_from_offset(&eng->output, eng->response_offset);
|
||||
@@ -2027,6 +2045,7 @@ void http_engine_undo(HTTP_Engine *eng)
|
||||
if ((eng->state & HTTP_ENGINE_STATEBIT_PREP) == 0)
|
||||
return;
|
||||
|
||||
byte_queue_write_ack(&eng->output, 0);
|
||||
byte_queue_remove_from_offset(&eng->output, eng->response_offset);
|
||||
|
||||
if (eng->state & HTTP_ENGINE_STATEBIT_CLIENT)
|
||||
|
||||
+10
-7
@@ -179,17 +179,19 @@ typedef unsigned long long HTTP_ByteQueueOffset;
|
||||
#define HTTP_ENGINE_STATEBIT_RESPONSE (1 << 7)
|
||||
#define HTTP_ENGINE_STATEBIT_PREP (1 << 8)
|
||||
#define HTTP_ENGINE_STATEBIT_PREP_HEADER (1 << 9)
|
||||
#define HTTP_ENGINE_STATEBIT_PREP_BODY (1 << 10)
|
||||
#define HTTP_ENGINE_STATEBIT_PREP_ERROR (1 << 11)
|
||||
#define HTTP_ENGINE_STATEBIT_PREP_URL (1 << 12)
|
||||
#define HTTP_ENGINE_STATEBIT_PREP_STATUS (1 << 13)
|
||||
#define HTTP_ENGINE_STATEBIT_CLOSING (1 << 14)
|
||||
#define HTTP_ENGINE_STATEBIT_PREP_BODY_BUF (1 << 10)
|
||||
#define HTTP_ENGINE_STATEBIT_PREP_BODY_ACK (1 << 11)
|
||||
#define HTTP_ENGINE_STATEBIT_PREP_ERROR (1 << 12)
|
||||
#define HTTP_ENGINE_STATEBIT_PREP_URL (1 << 13)
|
||||
#define HTTP_ENGINE_STATEBIT_PREP_STATUS (1 << 14)
|
||||
#define HTTP_ENGINE_STATEBIT_CLOSING (1 << 15)
|
||||
|
||||
typedef enum {
|
||||
HTTP_ENGINE_STATE_NONE = 0,
|
||||
HTTP_ENGINE_STATE_CLIENT_PREP_URL = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_PREP | HTTP_ENGINE_STATEBIT_PREP_URL,
|
||||
HTTP_ENGINE_STATE_CLIENT_PREP_HEADER = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_PREP | HTTP_ENGINE_STATEBIT_PREP_HEADER,
|
||||
HTTP_ENGINE_STATE_CLIENT_PREP_BODY = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_PREP | HTTP_ENGINE_STATEBIT_PREP_BODY,
|
||||
HTTP_ENGINE_STATE_CLIENT_PREP_BODY_BUF = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_PREP | HTTP_ENGINE_STATEBIT_PREP_BODY_BUF,
|
||||
HTTP_ENGINE_STATE_CLIENT_PREP_BODY_ACK = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_PREP | HTTP_ENGINE_STATEBIT_PREP_BODY_ACK,
|
||||
HTTP_ENGINE_STATE_CLIENT_PREP_ERROR = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_PREP | HTTP_ENGINE_STATEBIT_PREP_ERROR,
|
||||
HTTP_ENGINE_STATE_CLIENT_SEND_BUF = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_SEND_BUF,
|
||||
HTTP_ENGINE_STATE_CLIENT_SEND_ACK = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_SEND_ACK,
|
||||
@@ -201,7 +203,8 @@ typedef enum {
|
||||
HTTP_ENGINE_STATE_SERVER_RECV_ACK = HTTP_ENGINE_STATEBIT_RECV_ACK,
|
||||
HTTP_ENGINE_STATE_SERVER_PREP_STATUS = HTTP_ENGINE_STATEBIT_REQUEST | HTTP_ENGINE_STATEBIT_PREP | HTTP_ENGINE_STATEBIT_PREP_STATUS,
|
||||
HTTP_ENGINE_STATE_SERVER_PREP_HEADER = HTTP_ENGINE_STATEBIT_REQUEST | HTTP_ENGINE_STATEBIT_PREP | HTTP_ENGINE_STATEBIT_PREP_HEADER,
|
||||
HTTP_ENGINE_STATE_SERVER_PREP_BODY = HTTP_ENGINE_STATEBIT_REQUEST | HTTP_ENGINE_STATEBIT_PREP | HTTP_ENGINE_STATEBIT_PREP_BODY,
|
||||
HTTP_ENGINE_STATE_SERVER_PREP_BODY_BUF = HTTP_ENGINE_STATEBIT_REQUEST | HTTP_ENGINE_STATEBIT_PREP | HTTP_ENGINE_STATEBIT_PREP_BODY_BUF,
|
||||
HTTP_ENGINE_STATE_SERVER_PREP_BODY_ACK = HTTP_ENGINE_STATEBIT_REQUEST | HTTP_ENGINE_STATEBIT_PREP | HTTP_ENGINE_STATEBIT_PREP_BODY_ACK,
|
||||
HTTP_ENGINE_STATE_SERVER_PREP_ERROR = HTTP_ENGINE_STATEBIT_REQUEST | HTTP_ENGINE_STATEBIT_PREP | HTTP_ENGINE_STATEBIT_PREP_ERROR,
|
||||
HTTP_ENGINE_STATE_SERVER_SEND_BUF = HTTP_ENGINE_STATEBIT_SEND_BUF,
|
||||
HTTP_ENGINE_STATE_SERVER_SEND_ACK = HTTP_ENGINE_STATEBIT_SEND_ACK,
|
||||
|
||||
Reference in New Issue
Block a user