diff --git a/3p/WL.c b/3p/WL.c index 54dda36..aa98915 100644 --- a/3p/WL.c +++ b/3p/WL.c @@ -69,12 +69,14 @@ static bool is_hex_digit(char c) return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } +#if 0 static char to_lower(char c) { if (c >= 'A' && c <= 'Z') return c - 'A' + 'a'; return c; } +#endif static int hex_digit_to_int(char c) { @@ -97,6 +99,7 @@ static bool streq(String a, String b) return true; } +#if 0 static bool streqcase(String a, String b) { if (a.len != b.len) @@ -106,7 +109,7 @@ static bool streqcase(String a, String b) return false; return true; } - +#endif #define REPORT(err, fmt, ...) report((err), __FILE__, __LINE__, fmt, ## __VA_ARGS__) static void report(Error *err, char *file, int line, char *fmt, ...) @@ -159,6 +162,7 @@ static bool grow_alloc(WL_Arena *a, char *p, int new_len) return true; } +#if 0 static String copystr(String s, WL_Arena *a) { char *p = alloc(a, s.len, 1); @@ -167,6 +171,7 @@ static String copystr(String s, WL_Arena *a) memcpy(p, s.ptr, s.len); return (String) { p, s.len }; } +#endif ///////////////////////////////////////////////////////////////////////// // WRITER @@ -189,14 +194,14 @@ static void write_raw_mem(Writer *w, void *ptr, int len) } static void write_raw_u8 (Writer *w, uint8_t x) { write_raw_mem(w, &x, SIZEOF(x)); } -static void write_raw_u16(Writer *w, uint16_t x) { write_raw_mem(w, &x, SIZEOF(x)); } +//static void write_raw_u16(Writer *w, uint16_t x) { write_raw_mem(w, &x, SIZEOF(x)); } static void write_raw_u32(Writer *w, uint32_t x) { write_raw_mem(w, &x, SIZEOF(x)); } -static void write_raw_u64(Writer *w, uint64_t x) { write_raw_mem(w, &x, SIZEOF(x)); } -static void write_raw_s8 (Writer *w, int8_t x) { write_raw_mem(w, &x, SIZEOF(x)); } -static void write_raw_s16(Writer *w, int16_t x) { write_raw_mem(w, &x, SIZEOF(x)); } -static void write_raw_s32(Writer *w, int32_t x) { write_raw_mem(w, &x, SIZEOF(x)); } +//static void write_raw_u64(Writer *w, uint64_t x) { write_raw_mem(w, &x, SIZEOF(x)); } +//static void write_raw_s8 (Writer *w, int8_t x) { write_raw_mem(w, &x, SIZEOF(x)); } +//static void write_raw_s16(Writer *w, int16_t x) { write_raw_mem(w, &x, SIZEOF(x)); } +//static void write_raw_s32(Writer *w, int32_t x) { write_raw_mem(w, &x, SIZEOF(x)); } static void write_raw_s64(Writer *w, int64_t x) { write_raw_mem(w, &x, SIZEOF(x)); } -static void write_raw_f32(Writer *w, float x) { write_raw_mem(w, &x, SIZEOF(x)); } +//static void write_raw_f32(Writer *w, float x) { write_raw_mem(w, &x, SIZEOF(x)); } static void write_raw_f64(Writer *w, double x) { write_raw_mem(w, &x, SIZEOF(x)); } static void write_text(Writer *w, String str) @@ -413,6 +418,7 @@ static bool consume_str(Scanner *s, String x) return true; } +#if 0 static void write_token(Writer *w, Token token) { switch (token.type) { @@ -467,6 +473,7 @@ static void write_token(Writer *w, Token token) } } +#endif static void parser_report(Parser *p, char *fmt, ...) { @@ -2018,6 +2025,14 @@ static void write_node(Writer *w, Node *node) write_text(w, S(")")); break; + case NODE_OPER_SHOVEL: + write_text(w, S("(")); + write_node(w, node->left); + write_text(w, S("<<")); + write_node(w, node->right); + write_text(w, S(")")); + break; + case NODE_VALUE_INT: write_text_s64(w, node->ival); break; @@ -2717,9 +2732,6 @@ static void walk_expr_node(Codegen *cg, Node *node, bool one) case NODE_OPER_SHOVEL: { - Node *dst = node->left; - Node *src = node->right; - walk_expr_node(cg, node->left, true); cg_push_scope(cg, SCOPE_ASSIGNMENT); @@ -4783,7 +4795,7 @@ static String rt_read_str(WL_Runtime *rt) ASSERT(rt->state == RUNTIME_LOOP); uint32_t off = rt_read_u32(rt); uint32_t len = rt_read_u32(rt); - ASSERT(off + len <= rt->data.len); + ASSERT(off + len <= (uint32_t) rt->data.len); return (String) { rt->data.ptr + off, len }; } @@ -5325,6 +5337,7 @@ WL_EvalResult wl_runtime_eval(WL_Runtime *rt) switch (rt->state) { + case RUNTIME_BEGIN: case RUNTIME_LOOP: UNREACHABLE; diff --git a/3p/chttp.c b/3p/chttp.c index 3fd0280..b98405a 100644 --- a/3p/chttp.c +++ b/3p/chttp.c @@ -4,6 +4,7 @@ // src/sec.h //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/sec.h" #ifndef SEC_INCLUDED #define SEC_INCLUDED @@ -64,6 +65,7 @@ void secure_context_free(SecureContext *sec); // src/socket_raw.h //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/socket_raw.h" #ifndef SOCKET_RAW_INCLUDED #define SOCKET_RAW_INCLUDED @@ -104,6 +106,7 @@ RAW_SOCKET listen_socket(HTTP_String addr, uint16_t port, bool reuse_addr, int b // src/socket.h //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/socket.h" #ifndef SOCKET_INCLUDED #define SOCKET_INCLUDED @@ -184,6 +187,7 @@ void* socket_get_user_data(Socket *sock); // src/socket_pool.h //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/socket_pool.h" #ifndef SOCKET_POOL_INCLUDED #define SOCKET_POOL_INCLUDED @@ -241,12 +245,15 @@ int socket_pool_read(SocketPool *pool, SocketHandle handle, char *dst, int len); int socket_pool_write(SocketPool *pool, SocketHandle handle, char *src, int len); +bool socket_pool_secure(SocketPool *pool, SocketHandle handle); + #endif // SOCKET_POOL_INCLUDED //////////////////////////////////////////////////////////////////////////////////////// // src/basic.c //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/basic.c" #include #include @@ -355,6 +362,7 @@ void print_bytes(HTTP_String prefix, HTTP_String src) // src/parse.c //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/parse.c" #include #include #include @@ -1012,7 +1020,7 @@ static int parse_request_target(Scanner *s, HTTP_URL *url) return -1; } -bool consume_str_(Scanner *scan, HTTP_String token) +bool consume_str(Scanner *scan, HTTP_String token) { HTTP_ASSERT(token.len > 0); @@ -1035,7 +1043,7 @@ static int is_header_body(char c) static int parse_headers(Scanner *s, HTTP_Header *headers, int max_headers) { int num_headers = 0; - while (!consume_str_(s, HTTP_STR("\r\n"))) { + while (!consume_str(s, HTTP_STR("\r\n"))) { // RFC 9112: // field-line = field-name ":" OWS field-value OWS @@ -1069,7 +1077,7 @@ static int parse_headers(Scanner *s, HTTP_Header *headers, int max_headers) if (num_headers < max_headers) headers[num_headers++] = (HTTP_Header) { name, body }; - if (!consume_str_(s, HTTP_STR("\r\n"))) { + if (!consume_str(s, HTTP_STR("\r\n"))) { return -1; } } @@ -1101,10 +1109,10 @@ parse_transfer_encoding(HTTP_String src, TransferEncodingOption *dst, int max) TransferEncodingOption opt; if (0) {} - else if (consume_str_(&s, HTTP_STR("chunked"))) opt = TRANSFER_ENCODING_OPTION_CHUNKED; - else if (consume_str_(&s, HTTP_STR("compress"))) opt = TRANSFER_ENCODING_OPTION_COMPRESS; - else if (consume_str_(&s, HTTP_STR("deflate"))) opt = TRANSFER_ENCODING_OPTION_DEFLATE; - else if (consume_str_(&s, HTTP_STR("gzip"))) opt = TRANSFER_ENCODING_OPTION_GZIP; + else if (consume_str(&s, HTTP_STR("chunked"))) opt = TRANSFER_ENCODING_OPTION_CHUNKED; + else if (consume_str(&s, HTTP_STR("compress"))) opt = TRANSFER_ENCODING_OPTION_COMPRESS; + else if (consume_str(&s, HTTP_STR("deflate"))) opt = TRANSFER_ENCODING_OPTION_DEFLATE; + else if (consume_str(&s, HTTP_STR("gzip"))) opt = TRANSFER_ENCODING_OPTION_GZIP; else return -1; // Invalid option if (num == max) @@ -1360,16 +1368,18 @@ static int parse_request(Scanner *s, HTTP_Request *req) if (!contains_head(s->src + s->cur, s->len - s->cur)) return 0; + req->secure = false; + if (0) {} - else if (consume_str_(s, HTTP_STR("GET "))) req->method = HTTP_METHOD_GET; - else if (consume_str_(s, HTTP_STR("POST "))) req->method = HTTP_METHOD_POST; - else if (consume_str_(s, HTTP_STR("PUT "))) req->method = HTTP_METHOD_PUT; - else if (consume_str_(s, HTTP_STR("HEAD "))) req->method = HTTP_METHOD_HEAD; - else if (consume_str_(s, HTTP_STR("DELETE "))) req->method = HTTP_METHOD_DELETE; - else if (consume_str_(s, HTTP_STR("CONNECT "))) req->method = HTTP_METHOD_CONNECT; - else if (consume_str_(s, HTTP_STR("OPTIONS "))) req->method = HTTP_METHOD_OPTIONS; - else if (consume_str_(s, HTTP_STR("TRACE "))) req->method = HTTP_METHOD_TRACE; - else if (consume_str_(s, HTTP_STR("PATCH "))) req->method = HTTP_METHOD_PATCH; + else if (consume_str(s, HTTP_STR("GET "))) req->method = HTTP_METHOD_GET; + else if (consume_str(s, HTTP_STR("POST "))) req->method = HTTP_METHOD_POST; + else if (consume_str(s, HTTP_STR("PUT "))) req->method = HTTP_METHOD_PUT; + else if (consume_str(s, HTTP_STR("HEAD "))) req->method = HTTP_METHOD_HEAD; + else if (consume_str(s, HTTP_STR("DELETE "))) req->method = HTTP_METHOD_DELETE; + else if (consume_str(s, HTTP_STR("CONNECT "))) req->method = HTTP_METHOD_CONNECT; + else if (consume_str(s, HTTP_STR("OPTIONS "))) req->method = HTTP_METHOD_OPTIONS; + else if (consume_str(s, HTTP_STR("TRACE "))) req->method = HTTP_METHOD_TRACE; + else if (consume_str(s, HTTP_STR("PATCH "))) req->method = HTTP_METHOD_PATCH; else return -1; { @@ -1387,9 +1397,9 @@ static int parse_request(Scanner *s, HTTP_Request *req) s->cur = s2.cur; } - if (consume_str_(s, HTTP_STR(" HTTP/1.1\r\n"))) { + if (consume_str(s, HTTP_STR(" HTTP/1.1\r\n"))) { req->minor = 1; - } else if (consume_str_(s, HTTP_STR(" HTTP/1.0\r\n")) || consume_str_(s, HTTP_STR(" HTTP/1\r\n"))) { + } else if (consume_str(s, HTTP_STR(" HTTP/1.0\r\n")) || consume_str(s, HTTP_STR(" HTTP/1\r\n"))) { req->minor = 0; } else { return -1; @@ -1420,9 +1430,9 @@ static int parse_response(Scanner *s, HTTP_Response *res) if (!contains_head(s->src + s->cur, s->len - s->cur)) return 0; - if (consume_str_(s, HTTP_STR("HTTP/1.1 "))) { + if (consume_str(s, HTTP_STR("HTTP/1.1 "))) { res->minor = 1; - } else if (consume_str_(s, HTTP_STR("HTTP/1.0 ")) || consume_str_(s, HTTP_STR("HTTP/1 "))) { + } else if (consume_str(s, HTTP_STR("HTTP/1.0 ")) || consume_str(s, HTTP_STR("HTTP/1 "))) { res->minor = 0; } else { return -1; @@ -1493,10 +1503,8 @@ int http_parse_request(char *src, int len, HTTP_Request *req) { Scanner s = {src, len, 0}; int ret = parse_request(&s, req); - if (ret == 1) { - req->raw = (HTTP_String) { src, s.cur }; + if (ret == 1) return s.cur; - } return ret; } @@ -1513,6 +1521,7 @@ int http_parse_response(char *src, int len, HTTP_Response *res) // src/engine.c //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/engine.c" #include #include #include @@ -2506,6 +2515,7 @@ void http_engine_undo(HTTP_Engine *eng) // src/cert.c //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/cert.c" #include #include #include @@ -2680,6 +2690,7 @@ int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN, // src/sec.c //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/sec.c" #ifndef HTTP_AMALGAMATION #include "sec.h" #endif @@ -2905,6 +2916,7 @@ int secure_context_add_cert(SecureContext *sec, // src/socket_raw.c //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/socket_raw.c" #include #ifdef _WIN32 @@ -3016,6 +3028,7 @@ RAW_SOCKET listen_socket(HTTP_String addr, uint16_t port, bool reuse_addr, int b // src/socket.c //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/socket.c" #include // snprintf #include #include @@ -3811,6 +3824,7 @@ void *socket_get_user_data(Socket *sock) // src/socket_pool.c //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/socket_pool.c" #include #include @@ -4164,10 +4178,16 @@ int socket_pool_write(SocketPool *pool, SocketHandle handle, char *src, int len) return socket_write(&pool->socks[handle], src, len); } +bool socket_pool_secure(SocketPool *pool, SocketHandle handle) +{ + return socket_secure(&pool->socks[handle]); +} + //////////////////////////////////////////////////////////////////////////////////////// // src/client.c //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/client.c" #include #include #include @@ -4626,6 +4646,7 @@ HTTP_Response *http_post(HTTP_String url, HTTP_String *headers, int num_headers, // src/server.c //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/server.c" #include #include #include @@ -4648,8 +4669,6 @@ typedef struct { struct HTTP_Server { - bool trace; - SocketPool *socket_pool; int num_conns; @@ -4672,8 +4691,6 @@ HTTP_Server *http_server_init_ex(HTTP_String addr, uint16_t port, if (server == NULL) return NULL; - server->trace = false; - int backlog = 32; bool reuse_addr = true; SocketPool *socket_pool = socket_pool_init(addr, port, secure_port, MAX_CONNS, reuse_addr, backlog, cert_file, key_file); @@ -4710,11 +4727,6 @@ void http_server_free(HTTP_Server *server) free(server); } -void http_server_set_trace(HTTP_Server *server, bool trace) -{ - server->trace = trace; -} - int http_server_add_website(HTTP_Server *server, HTTP_String domain, HTTP_String cert_file, HTTP_String key_file) { return socket_pool_add_cert(server->socket_pool, domain, cert_file, key_file); @@ -4784,8 +4796,6 @@ int http_server_wait(HTTP_Server *server, HTTP_Request **req, HTTP_ResponseBuild buf = http_engine_recvbuf(&conn->engine, &len); if (buf) { int ret = socket_pool_read(server->socket_pool, conn->sock, buf, len); - if (server->trace) - print_bytes(HTTP_STR(">> "), (HTTP_String) { buf, ret }); http_engine_recvack(&conn->engine, ret); } break; @@ -4794,8 +4804,6 @@ int http_server_wait(HTTP_Server *server, HTTP_Request **req, HTTP_ResponseBuild buf = http_engine_sendbuf(&conn->engine, &len); if (buf) { int ret = socket_pool_write(server->socket_pool, conn->sock, buf, len); - if (server->trace) - print_bytes(HTTP_STR("<< "), (HTTP_String) { buf, ret }); http_engine_sendack(&conn->engine, ret); } break; @@ -4837,6 +4845,8 @@ int http_server_wait(HTTP_Server *server, HTTP_Request **req, HTTP_ResponseBuild server->ready_count--; *req = http_engine_getreq(&server->conns[index].engine); + (*req)->secure = socket_pool_secure(server->socket_pool, server->conns[index].sock); + *builder = (HTTP_ResponseBuilder) { server, index, server->conns[index].gen }; return 0; } @@ -4949,6 +4959,7 @@ void http_response_builder_done(HTTP_ResponseBuilder res) // src/router.c //////////////////////////////////////////////////////////////////////////////////////// +#line 1 "src/router.c" #include #include #include diff --git a/3p/chttp.h b/3p/chttp.h index 5179e8f..fb6bfb9 100644 --- a/3p/chttp.h +++ b/3p/chttp.h @@ -162,13 +162,13 @@ typedef struct { } HTTP_Header; typedef struct { + bool secure; HTTP_Method method; HTTP_URL url; int minor; int num_headers; HTTP_Header headers[HTTP_MAX_HEADERS]; HTTP_String body; - HTTP_String raw; } HTTP_Request; typedef struct { @@ -483,7 +483,6 @@ HTTP_Server *http_server_init_ex(HTTP_String addr, uint16_t port, void http_server_free (HTTP_Server *server); int http_server_wait (HTTP_Server *server, HTTP_Request **req, HTTP_ResponseBuilder *handle); -void http_server_set_trace (HTTP_Server *server, bool trace); int http_server_add_website (HTTP_Server *server, HTTP_String domain, HTTP_String cert_file, HTTP_String key_file); void http_response_builder_status (HTTP_ResponseBuilder res, int status); void http_response_builder_header (HTTP_ResponseBuilder res, HTTP_String str); diff --git a/TODO b/TODO index 55f67fa..819790a 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,2 @@ -only allow signup, login ecc over HTTPS session expiration -mark cookies as secure -consider SameSite=Stricts \ No newline at end of file +consider SameSite=Stricts diff --git a/src/main.c b/src/main.c index 03d4bf0..93ab0e2 100644 --- a/src/main.c +++ b/src/main.c @@ -392,15 +392,19 @@ int main(void) TemplateCache *tpcache = template_cache_init(4); SQLiteCache *dbcache = sqlite_cache_init(db, 5); - HTTP_String addr = HTTP_STR("127.0.0.1"); uint16_t port = 8080; + // If set, allows logins and signups over HTTP, which is highly insecure. + // This allows compiling the application without TLS when developing. + bool allow_insecure_login = true; + + if (allow_insecure_login) + printf("WARNING: allow_insecure_login is true\n"); + HTTP_Server *server = http_server_init(addr, port); if (server == NULL) return -1; - http_server_set_trace(server, false); - int pool_cap = 1<<20; char *pool = malloc(pool_cap); @@ -419,8 +423,6 @@ int main(void) WL_Arena arena = { pool, pool_cap, 0 }; - printf("%.*s\n", req->raw.len, req->raw.ptr); // TODO - int user_id; HTTP_String sess; HTTP_String csrf; @@ -435,6 +437,17 @@ int main(void) HTTP_String path = req->url.path; if (http_streq(path, HTTP_STR("/api/login"))) { + if (!req->secure && !allow_insecure_login) { + http_response_builder_status(builder, 200); + http_response_builder_body(builder, HTML_STR(( +
+ Connection is not secure +
+ ))); + http_response_builder_done(builder); + continue; + } + if (req->method != HTTP_METHOD_POST) { http_response_builder_status(builder, 200); http_response_builder_body(builder, HTML_STR(( @@ -502,9 +515,8 @@ int main(void) continue; } - // TODO: set cookie as secure char cookie[1<<9]; - int cookie_len = snprintf(cookie, sizeof(cookie), "Set-Cookie: sess_token=%.*s; Path=/; HttpOnly", sess.len, sess.ptr); + int cookie_len = snprintf(cookie, sizeof(cookie), "Set-Cookie: sess_token=%.*s; Path=/; HttpOnly; Secure", sess.len, sess.ptr); if (cookie_len < 0 || cookie_len >= (int) sizeof(cookie)) { http_response_builder_status(builder, 200); http_response_builder_body(builder, HTML_STR(( @@ -528,6 +540,17 @@ int main(void) } else if (http_streq(path, HTTP_STR("/api/signup"))) { + if (!req->secure && !allow_insecure_login) { + http_response_builder_status(builder, 200); + http_response_builder_body(builder, HTML_STR(( +
+ Connection is not secure +
+ ))); + http_response_builder_done(builder); + continue; + } + if (req->method != HTTP_METHOD_POST) { http_response_builder_status(builder, 200); http_response_builder_body(builder, HTML_STR(( @@ -605,9 +628,8 @@ int main(void) continue; } - // TODO: set cookie as secure char cookie[1<<9]; - int cookie_len = snprintf(cookie, sizeof(cookie), "Set-Cookie: sess_token=%.*s; Path=/; HttpOnly", sess.len, sess.ptr); + int cookie_len = snprintf(cookie, sizeof(cookie), "Set-Cookie: sess_token=%.*s; Path=/; HttpOnly; Secure", sess.len, sess.ptr); if (cookie_len < 0 || cookie_len >= (int) sizeof(cookie)) { http_response_builder_status(builder, 200); http_response_builder_body(builder, HTML_STR(( @@ -634,9 +656,8 @@ int main(void) if (user_id != -1) delete_session(session_storage, sess); - // TODO: set cookie as secure http_response_builder_status(builder, 303); // TODO: Whats the correct code here? - http_response_builder_header(builder, HTTP_STR("Set-Cookie: sess_token=; Path=/; HttpOnly")); + http_response_builder_header(builder, HTTP_STR("Set-Cookie: sess_token=; Path=/; HttpOnly; Secure")); http_response_builder_header(builder, HTTP_STR("Location: /index")); http_response_builder_done(builder);