From ae392fdfe3933b399b58a1b264117046400f1cef Mon Sep 17 00:00:00 2001 From: phani Date: Thu, 26 Dec 2019 18:52:59 -0500 Subject: [PATCH] read from stdin (http req body), write to stdout (http resp body), bug fixes in http parsing --- runtime/include/http.h | 10 ------ runtime/include/http_api.h | 51 ++++++++++++++++++++++++++ runtime/include/module.h | 2 +- runtime/include/sandbox.h | 1 + runtime/include/types.h | 2 +- runtime/src/http.c | 63 ++++++++++++++++++-------------- runtime/src/libc/uvio.c | 12 +++++++ runtime/src/runtime.c | 2 +- runtime/src/sandbox.c | 67 ++++++++++++++++++++++------------- runtime/tests/empty/main.c | 11 +++--- runtime/tests/test_empty.json | 4 +-- 11 files changed, 156 insertions(+), 69 deletions(-) create mode 100644 runtime/include/http_api.h diff --git a/runtime/include/http.h b/runtime/include/http.h index 3f0f2aa..3c66f58 100644 --- a/runtime/include/http.h +++ b/runtime/include/http.h @@ -37,14 +37,4 @@ struct http_response { uv_buf_t bufs[HTTP_HEADERS_MAX * 2 + 3]; //max headers, one line for status code, remaining for body! }; -int http_request_body_get(char **body); -int http_request_parse(void); - -int http_response_header_set(char *h, int len); -int http_response_body_set(char *body, int len); -int http_response_status_set(char *status, int len); -int http_response_uv(void); - -void http_init(void); - #endif /* SFRT_HTTP_H */ diff --git a/runtime/include/http_api.h b/runtime/include/http_api.h new file mode 100644 index 0000000..ba7c493 --- /dev/null +++ b/runtime/include/http_api.h @@ -0,0 +1,51 @@ +#ifndef SRFT_HTTP_API_H +#define SRFT_HTTP_API_H + +#include +int http_request_body_get_sb(struct sandbox *s, char **body); +int http_request_parse_sb(struct sandbox *s, size_t l); + +int http_response_header_set_sb(struct sandbox *s, char *h, int len); +int http_response_body_set_sb(struct sandbox *s, char *body, int len); +int http_response_status_set_sb(struct sandbox *s, char *status, int len); +int http_response_uv_sb(struct sandbox *s); + +void http_init(void); + +static inline int +http_request_body_get(char **b) +{ + return http_request_body_get_sb(sandbox_current(), b); +} + +static inline int +http_response_header_set(char *key, int len) +{ + return http_response_header_set_sb(sandbox_current(), key, len); +} + +static inline int +http_response_body_set(char *body, int len) +{ + return http_response_body_set_sb(sandbox_current(), body, len); +} + +static inline int +http_response_status_set(char *status, int len) +{ + return http_response_status_set_sb(sandbox_current(), status, len); +} + +static inline int +http_response_uv(void) +{ + return http_response_uv_sb(sandbox_current()); +} + +static inline int +http_request_parse(size_t l) +{ + return http_request_parse_sb(sandbox_current(), l); +} + +#endif /* SRFT_HTTP_API_H */ diff --git a/runtime/include/module.h b/runtime/include/module.h index 6eeb1cb..6764967 100644 --- a/runtime/include/module.h +++ b/runtime/include/module.h @@ -33,7 +33,7 @@ struct module { // rest of the connection is handled in sandboxing threads, with per-core(per-thread) tls data-structures. // so, using direct epoll for accepting connections. // uv_handle_t srvuv; - unsigned long max_req_sz, max_resp_sz, max_rr_sz; // req/resp from http.. + unsigned long max_req_sz, max_resp_sz, max_rr_sz; // req/resp from http, (resp size including headers!).. int nreqhdrs, nresphdrs; char reqhdrs[HTTP_HEADERS_MAX][HTTP_HEADER_MAXSZ]; char rqctype[HTTP_HEADERVAL_MAXSZ]; diff --git a/runtime/include/sandbox.h b/runtime/include/sandbox.h index e3ba7c7..82ea254 100644 --- a/runtime/include/sandbox.h +++ b/runtime/include/sandbox.h @@ -61,6 +61,7 @@ struct sandbox { struct sockaddr client; //client requesting connection! int csock; uv_tcp_t cuv; + uv_shutdown_t cuvsr; http_parser hp; struct http_request rqi; struct http_response rsi; diff --git a/runtime/include/types.h b/runtime/include/types.h index d33e681..95a4566 100644 --- a/runtime/include/types.h +++ b/runtime/include/types.h @@ -148,7 +148,7 @@ typedef enum { #define SBOX_RESP_STRSZ 32 -#define MOD_BACKLOG 100 +#define MOD_BACKLOG 10000 #define EPOLL_MAX 1024 #define MOD_REQ_RESP_DEFAULT (PAGE_SIZE) #define QUIESCENSE_TIME (1<<20) //cycles! diff --git a/runtime/src/http.c b/runtime/src/http.c index f9952a8..0169959 100644 --- a/runtime/src/http.c +++ b/runtime/src/http.c @@ -1,34 +1,44 @@ #include #include #include +#include http_parser_settings settings; static inline int http_on_msg_begin(http_parser *parser) { - struct http_request *r = parser->data; +#ifndef STANDALONE + struct sandbox *s = parser->data; + struct http_request *r = &s->rqi; r->message_begin = 1; r->last_was_value = 1; //should always start with a header.. +#endif return 0; } static inline int http_on_msg_end(http_parser *parser) { - struct http_request *r = parser->data; +#ifndef STANDALONE + struct sandbox *s = parser->data; + struct http_request *r = &s->rqi; r->message_end = 1; +#endif return 0; } static inline int http_on_header_end(http_parser *parser) { - struct http_request *r = parser->data; +#ifndef STANDALONE + struct sandbox *s = parser->data; + struct http_request *r = &s->rqi; r->header_end = 1; +#endif return 0; } @@ -36,8 +46,8 @@ static inline int http_on_url(http_parser* parser, const char *at, size_t length) { #ifndef STANDALONE - struct sandbox *s = sandbox_current(); - struct http_request *r = parser->data; + struct sandbox *s = parser->data; + struct http_request *r = &s->rqi; assert(strncmp(s->mod->name, (at + 1), length - 1) == 0); #endif @@ -47,7 +57,8 @@ http_on_url(http_parser* parser, const char *at, size_t length) static inline int http_on_header_field(http_parser* parser, const char *at, size_t length) { - struct http_request *r = parser->data; + struct sandbox *s = parser->data; + struct http_request *r = &s->rqi; if (r->last_was_value) r->nheaders ++; assert(r->nheaders <= HTTP_HEADERS_MAX); @@ -62,7 +73,8 @@ http_on_header_field(http_parser* parser, const char *at, size_t length) static inline int http_on_header_value(http_parser* parser, const char *at, size_t length) { - struct http_request *r = parser->data; + struct sandbox *s = parser->data; + struct http_request *r = &s->rqi; r->last_was_value = 1; assert(r->nheaders <= HTTP_HEADERS_MAX); @@ -77,22 +89,23 @@ static inline int http_on_body(http_parser* parser, const char *at, size_t length) { #ifndef STANDALONE - struct http_request *r = parser->data; - struct sandbox *c = sandbox_current(); + struct sandbox *s = parser->data; + struct http_request *r = &s->rqi; - assert(length <= c->mod->max_req_sz); - r->body = (char *)at; - r->bodylen = length; + assert(r->bodylen + length <= s->mod->max_req_sz); + if (!r->body) r->body = (char *)at; + else assert(r->body + r->bodylen == at); + + r->bodylen += length; #endif return 0; } int -http_request_body_get(char **b) +http_request_body_get_sb(struct sandbox *s, char **b) { #ifndef STANDALONE - struct sandbox *s = sandbox_current(); struct http_request *r = &s->rqi; *b = r->body; @@ -103,11 +116,10 @@ http_request_body_get(char **b) } int -http_response_header_set(char *key, int len) +http_response_header_set_sb(struct sandbox *c, char *key, int len) { #ifndef STANDALONE // by now, req_resp_data should only be containing response! - struct sandbox *c = sandbox_current(); struct http_response *r = &c->rsi; assert(r->nheaders < HTTP_HEADERS_MAX); @@ -119,13 +131,13 @@ http_response_header_set(char *key, int len) return 0; } -int http_response_body_set(char *body, int len) +int +http_response_body_set_sb(struct sandbox *c, char *body, int len) { #ifndef STANDALONE - struct sandbox *c = sandbox_current(); struct http_response *r = &c->rsi; - assert(len < c->mod->max_resp_sz); + assert(len <= c->mod->max_resp_sz); r->body = body; r->bodylen = len; #endif @@ -133,10 +145,10 @@ int http_response_body_set(char *body, int len) return 0; } -int http_response_status_set(char *status, int len) +int +http_response_status_set_sb(struct sandbox *c, char *status, int len) { #ifndef STANDALONE - struct sandbox *c = sandbox_current(); struct http_response *r = &c->rsi; r->status = status; @@ -146,11 +158,11 @@ int http_response_status_set(char *status, int len) return 0; } -int http_response_uv(void) +int +http_response_uv_sb(struct sandbox *c) { int nb = 0; #ifndef STANDALONE - struct sandbox *c = sandbox_current(); struct http_response *r = &c->rsi; @@ -173,11 +185,10 @@ int http_response_uv(void) } int -http_request_parse(void) +http_request_parse_sb(struct sandbox *s, size_t l) { #ifndef STANDALONE - struct sandbox *s = sandbox_current(); - http_parser_execute(&s->hp, &settings, s->req_resp_data, s->rr_data_len); + http_parser_execute(&s->hp, &settings, s->req_resp_data + s->rr_data_len, l); #endif return 0; } diff --git a/runtime/src/libc/uvio.c b/runtime/src/libc/uvio.c index aa4d314..3bef9c1 100644 --- a/runtime/src/libc/uvio.c +++ b/runtime/src/libc/uvio.c @@ -100,8 +100,20 @@ i32 wasm_write(i32 fd, i32 buf_offset, i32 buf_size) { if (fd == 1 || fd == 2) { +#ifdef STANDALONE char* buf = get_memory_ptr_void(buf_offset, buf_size); return write(fd, buf, buf_size); +#else + char* buf = get_memory_ptr_void(buf_offset, buf_size); + struct sandbox *s = sandbox_current(); + int l = s->mod->max_resp_sz - s->rr_data_len; + l = l > buf_size ? buf_size : l; + if (l == 0) return 0; + memcpy(s->req_resp_data + s->rr_data_len, buf, l); + s->rr_data_len += l; + + return l; +#endif } int f = io_handle_fd(fd); // TODO: read on other file types diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index 8efe587..20c9a6b 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include struct deque_sandbox *glb_dq; pthread_mutex_t glbq_mtx = PTHREAD_MUTEX_INITIALIZER; diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index a2b4912..0d1ba31 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -5,6 +5,7 @@ #include #include #include +#include static inline struct sandbox * sandbox_memory_map(struct module *m) @@ -45,6 +46,7 @@ sandbox_args_setup(i32 argc) { struct sandbox *curr = sandbox_current(); char *args = sandbox_args(); + if (!args) return; // whatever gregor has, to be able to pass args to a module! curr->args_offset = sandbox_lmbound; @@ -71,44 +73,53 @@ sb_read_callback(uv_stream_t *s, ssize_t nr, const uv_buf_t *b) { struct sandbox *c = s->data; - if (nr > 0) c->rr_data_len += nr; + if (nr > 0) { + if (http_request_parse_sb(c, nr) != 0) return; + c->rr_data_len += nr; + struct http_request *rh = &c->rqi; + if (!rh->message_end) return; + } + uv_read_stop(s); sandbox_wakeup(c); } static inline void -sb_write_callback(uv_write_t *w, int status) +sb_close_callback(uv_handle_t *s) { - struct sandbox *c = w->data; - + struct sandbox *c = s->data; sandbox_wakeup(c); } static inline void -sb_alloc_callback(uv_handle_t *h, size_t suggested, uv_buf_t *buf) +sb_shutdown_callback(uv_shutdown_t *req, int status) { - struct sandbox *c = h->data; - -#ifndef STANDALONE - buf->base = (c->req_resp_data + c->rr_data_len); - buf->len = (c->mod->max_rr_sz - c->rr_data_len); -#endif + struct sandbox *c = req->data; + sandbox_wakeup(c); } static inline void -sb_close_callback(uv_handle_t *s) +sb_write_callback(uv_write_t *w, int status) { - struct sandbox *c = s->data; - + struct sandbox *c = w->data; + if (status < 0) { + c->cuvsr.data = c; + uv_shutdown(&c->cuvsr, (uv_stream_t *)&c->cuv, sb_shutdown_callback); + return; + } sandbox_wakeup(c); } static inline void -sb_shutdown_callback(uv_shutdown_t *req, int status) +sb_alloc_callback(uv_handle_t *h, size_t suggested, uv_buf_t *buf) { - struct sandbox *c = req->data; + struct sandbox *c = h->data; - sandbox_wakeup(c); +#ifndef STANDALONE + size_t l = (c->mod->max_rr_sz - c->rr_data_len); + buf->base = (c->req_resp_data + c->rr_data_len); + buf->len = l > suggested ? suggested : l; +#endif } static inline int @@ -121,16 +132,27 @@ sandbox_client_request_get(void) #ifndef USE_UVIO int r = 0; r = recv(curr->csock, (curr->req_resp_data), curr->mod->max_req_sz, 0); - if (r < 0) { + if (r <= 0) { perror("recv"); return r; } - curr->rr_data_len = r; + while (r > 0) { + if (http_request_parse(r) != 0) return -1; + curr->rr_data_len += r; + struct http_request *rh = &curr->rqi; + if (rh->message_end) break; + + r = recv(curr->csock, (curr->req_resp_data + r), curr->mod->max_req_sz - r, 0); + if (r < 0) { + perror("recv"); + return r; + } + } #else int r = uv_read_start((uv_stream_t *)&curr->cuv, sb_alloc_callback, sb_read_callback); sandbox_block(); + if (curr->rr_data_len == 0) return 0; #endif - if (http_request_parse() != 0) return -1; return 1; #else @@ -227,7 +249,7 @@ sandbox_entry(void) #ifndef STANDALONE http_parser_init(&curr->hp, HTTP_REQUEST); - curr->hp.data = &curr->rqi; + curr->hp.data = curr; #ifdef USE_UVIO int r = uv_tcp_init(runtime_uvio(), (uv_tcp_t *)&curr->cuv); assert(r == 0); @@ -251,9 +273,6 @@ sandbox_entry(void) #ifndef STANDALONE #ifdef USE_UVIO - uv_shutdown_t sr = { .data = curr, }; - r = uv_shutdown(&sr, (uv_stream_t *)&curr->cuv, sb_shutdown_callback); - sandbox_block(); uv_close((uv_handle_t *)&curr->cuv, sb_close_callback); sandbox_block(); #else diff --git a/runtime/tests/empty/main.c b/runtime/tests/empty/main.c index 7a57e3f..1f0f0db 100644 --- a/runtime/tests/empty/main.c +++ b/runtime/tests/empty/main.c @@ -2,12 +2,15 @@ #include #include +#define MAX_BUF (1024*1024) //1m + int main(int argc, char **argv) { - printf("hello\n"); -// char d[16] = { 0 }; -// int r = read(0, d, 15); -// printf("hello [%s]\n", d); + char *d = malloc(MAX_BUF + 1); + int r = read(0, d, MAX_BUF); + if (r <= 0) printf("%s\n", r == 0 ? "empty" : "error"); + else write(1, d, MAX_BUF); + return 0; } diff --git a/runtime/tests/test_empty.json b/runtime/tests/test_empty.json index 018f57f..ef12dbc 100644 --- a/runtime/tests/test_empty.json +++ b/runtime/tests/test_empty.json @@ -6,8 +6,8 @@ "argsize" : 1, "http-req-headers" : [ ], "http-req-content-type" : "text/plain", - "http-req-size": 102400, + "http-req-size": 1048576, "http-resp-headers" : [ ], - "http-resp-size" : 10240, + "http-resp-size" : 1048776, "http-resp-content-type" : "text/plain" }