Fix more errors

This commit is contained in:
2025-09-21 16:58:08 +02:00
parent 9699ccc98c
commit 4f239166c7
6 changed files with 804 additions and 775 deletions
+2 -2
View File
@@ -29,8 +29,6 @@ header = Amalgamator()
header.append_text("#ifndef CWEB_AMALGAMATION\n")
header.append_text("#define CWEB_AMALGAMATION\n")
header.append_text(desc)
header.append_file("3p/wl.h")
header.append_file("3p/chttp.h")
header.append_file("src/main.h")
header.append_text("#endif // CWEB_AMALGAMATION\n")
header.save("cweb.h")
@@ -38,6 +36,8 @@ header.save("cweb.h")
source = Amalgamator()
source.append_text("#include \"cweb.h\"\n")
source.append_text("#define HTTP_NOINCLUDE\n")
source.append_file("3p/wl.h")
source.append_file("3p/chttp.h")
source.append_file("3p/chttp.c")
source.append_file("3p/crypt_blowfish.h")
source.append_file("3p/crypt_blowfish.c")
+687 -127
View File
@@ -1,12 +1,642 @@
#include "cweb.h"
#define HTTP_NOINCLUDE
////////////////////////////////////////////////////////////////////////////////////////
// 3p/wl.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "3p/wl.h"
#include <stdint.h>
#include <stdbool.h>
typedef struct WL_Runtime WL_Runtime;
typedef struct WL_Compiler WL_Compiler;
typedef struct {
char *ptr;
int len;
} WL_String;
typedef struct {
char *ptr;
int len;
int cur;
} WL_Arena;
typedef struct {
char *ptr;
int len;
} WL_Program;
typedef enum {
WL_ADD_ERROR,
WL_ADD_AGAIN,
WL_ADD_LINK,
} WL_AddResultType;
typedef struct {
WL_AddResultType type;
WL_String path;
} WL_AddResult;
typedef enum {
WL_EVAL_NONE,
WL_EVAL_DONE,
WL_EVAL_ERROR,
WL_EVAL_OUTPUT,
WL_EVAL_SYSVAR,
WL_EVAL_SYSCALL,
} WL_EvalResultType;
typedef struct {
WL_EvalResultType type;
WL_String str;
} WL_EvalResult;
WL_Compiler* wl_compiler_init (WL_Arena *arena);
WL_AddResult wl_compiler_add (WL_Compiler *compiler, WL_String content);
int wl_compiler_link (WL_Compiler *compiler, WL_Program *program);
WL_String wl_compiler_error (WL_Compiler *compiler);
int wl_dump_ast (WL_Compiler *compiler, char *dst, int cap);
void wl_dump_program (WL_Program program);
WL_Runtime* wl_runtime_init (WL_Arena *arena, WL_Program program);
WL_EvalResult wl_runtime_eval (WL_Runtime *rt);
WL_String wl_runtime_error (WL_Runtime *rt);
void wl_runtime_dump (WL_Runtime *rt);
bool wl_streq (WL_String a, char *b, int blen);
int wl_arg_count (WL_Runtime *rt);
bool wl_arg_none (WL_Runtime *rt, int idx);
bool wl_arg_bool (WL_Runtime *rt, int idx, bool *x);
bool wl_arg_s64 (WL_Runtime *rt, int idx, int64_t *x);
bool wl_arg_f64 (WL_Runtime *rt, int idx, double *x);
bool wl_arg_str (WL_Runtime *rt, int idx, WL_String *x);
bool wl_arg_array (WL_Runtime *rt, int idx);
bool wl_arg_map (WL_Runtime *rt, int idx);
bool wl_peek_none (WL_Runtime *rt, int off);
bool wl_peek_bool (WL_Runtime *rt, int off, bool *x);
bool wl_peek_s64 (WL_Runtime *rt, int off, int64_t *x);
bool wl_peek_f64 (WL_Runtime *rt, int off, double *x);
bool wl_peek_str (WL_Runtime *rt, int off, WL_String *x);
bool wl_pop_any (WL_Runtime *rt);
bool wl_pop_none (WL_Runtime *rt);
bool wl_pop_bool (WL_Runtime *rt, bool *x);
bool wl_pop_s64 (WL_Runtime *rt, int64_t *x);
bool wl_pop_f64 (WL_Runtime *rt, double *x);
bool wl_pop_str (WL_Runtime *rt, WL_String *x);
void wl_push_none (WL_Runtime *rt);
void wl_push_true (WL_Runtime *rt);
void wl_push_false (WL_Runtime *rt);
void wl_push_s64 (WL_Runtime *rt, int64_t x);
void wl_push_f64 (WL_Runtime *rt, double x);
void wl_push_str (WL_Runtime *rt, WL_String x);
void wl_push_array (WL_Runtime *rt, int cap);
void wl_push_map (WL_Runtime *rt, int cap);
void wl_push_arg (WL_Runtime *rt, int idx);
void wl_insert (WL_Runtime *rt);
void wl_append (WL_Runtime *rt);
////////////////////////////////////////////////////////////////////////////////////////
// 3p/chttp.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "3p/chttp.h"
#ifndef HTTP_AMALGAMATION
#define HTTP_AMALGAMATION
// This file was generated automatically. Do not modify directly!
////////////////////////////////////////////////////////////////////////////////////////
// src/basic.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/basic.h"
#ifndef CHTTP_BASIC_INCLUDED
#define CHTTP_BASIC_INCLUDED
#include <stdbool.h>
// String type used throughout cHTTP.
typedef struct {
char *ptr;
int len;
} HTTP_String;
// Compare two strings and return true iff they have
// the same contents.
bool http_streq(HTTP_String s1, HTTP_String s2);
// Compre two strings case-insensitively (uppercase and
// lowercase versions of a letter are considered the same)
// and return true iff they have the same contents.
bool http_streqcase(HTTP_String s1, HTTP_String s2);
// Remove spaces and tabs from the start and the end of
// a string. This doesn't change the original string and
// the new one references the contents of the original one.
HTTP_String http_trim(HTTP_String s);
// TODO: comment
void print_bytes(HTTP_String prefix, HTTP_String src);
// Macro to simplify converting string literals to
// HTTP_String.
//
// Instead of doing this:
//
// char *s = "some string";
//
// You do this:
//
// HTTP_String s = HTTP_STR("some string")
//
// This is a bit cumbersome, but better than null-terminated
// strings, having a pointer and length variable pairs whenever
// a function operates on a string. If this wasn't a library
// I would have done for
//
// #define S(X) ...
//
// But I don't want to cause collisions with user code.
#define HTTP_STR(X) ((HTTP_String) {(X), sizeof(X)-1})
// Returns the number of items of a static array.
#define HTTP_COUNT(X) (sizeof(X) / sizeof((X)[0]))
// TODO: comment
#define HTTP_UNPACK(X) (X).len, (X).ptr
// Macro used to make invariants of the code more explicit.
//
// Say you have some function that operates on two integers
// and that by design their sum is always 100. This macro is
// useful to make that explicit:
//
// void func(int a, int b)
// {
// HTTP_ASSERT(a + b == 100);
// ...
// }
//
// Assertions are about documentation, *not* error management.
//
// In non-release builds (where NDEBUG is not defined) asserted
// expressions are evaluated and if not true, the program is halted.
// This is quite nice as they offer a way to document code in
// a way that can be checked at runtime, unlike regular comments
// like this one.
#ifdef NDEBUG
#define HTTP_ASSERT(X) ((void) 0)
#else
#define HTTP_ASSERT(X) {if (!(X)) { __builtin_trap(); }}
#endif
#endif // CHTTP_BASIC_INCLUDED
////////////////////////////////////////////////////////////////////////////////////////
// src/parse.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/parse.h"
#ifndef PARSE_INCLUDED
#define PARSE_INCLUDED
#ifndef HTTP_AMALGAMATION
#include "basic.h"
#endif
#define HTTP_MAX_HEADERS 32
typedef struct {
unsigned int data;
} HTTP_IPv4;
typedef struct {
unsigned short data[8];
} HTTP_IPv6;
typedef enum {
HTTP_HOST_MODE_VOID = 0,
HTTP_HOST_MODE_NAME,
HTTP_HOST_MODE_IPV4,
HTTP_HOST_MODE_IPV6,
} HTTP_HostMode;
typedef struct {
HTTP_HostMode mode;
HTTP_String text;
union {
HTTP_String name;
HTTP_IPv4 ipv4;
HTTP_IPv6 ipv6;
};
} HTTP_Host;
typedef struct {
HTTP_String userinfo;
HTTP_Host host;
int port;
} HTTP_Authority;
// ZII
typedef struct {
HTTP_String scheme;
HTTP_Authority authority;
HTTP_String path;
HTTP_String query;
HTTP_String fragment;
} HTTP_URL;
typedef enum {
HTTP_METHOD_GET,
HTTP_METHOD_HEAD,
HTTP_METHOD_POST,
HTTP_METHOD_PUT,
HTTP_METHOD_DELETE,
HTTP_METHOD_CONNECT,
HTTP_METHOD_OPTIONS,
HTTP_METHOD_TRACE,
HTTP_METHOD_PATCH,
} HTTP_Method;
typedef struct {
HTTP_String name;
HTTP_String value;
} 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_Request;
typedef struct {
void* context;
int minor;
int status;
HTTP_String reason;
int num_headers;
HTTP_Header headers[HTTP_MAX_HEADERS];
HTTP_String body;
} HTTP_Response;
int http_parse_ipv4 (char *src, int len, HTTP_IPv4 *ipv4);
int http_parse_ipv6 (char *src, int len, HTTP_IPv6 *ipv6);
int http_parse_url (char *src, int len, HTTP_URL *url);
int http_parse_request (char *src, int len, HTTP_Request *req);
int http_parse_response (char *src, int len, HTTP_Response *res);
int http_find_header (HTTP_Header *headers, int num_headers, HTTP_String name);
HTTP_String http_get_cookie (HTTP_Request *req, HTTP_String name);
HTTP_String http_get_param (HTTP_String body, HTTP_String str, char *mem, int cap);
int http_get_param_i (HTTP_String body, HTTP_String str);
#endif // PARSE_INCLUDED
////////////////////////////////////////////////////////////////////////////////////////
// src/engine.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/engine.h"
#ifndef HTTP_ENGINE_INCLUDED
#define HTTP_ENGINE_INCLUDED
#ifndef HTTP_AMALGAMATION
#include "parse.h"
#endif
typedef enum {
HTTP_MEMFUNC_MALLOC,
HTTP_MEMFUNC_FREE,
} HTTP_MemoryFuncTag;
typedef void*(*HTTP_MemoryFunc)(HTTP_MemoryFuncTag tag,
void *ptr, int len, void *data);
typedef struct {
HTTP_MemoryFunc memfunc;
void *memfuncdata;
unsigned long long curs;
char* data;
unsigned int head;
unsigned int size;
unsigned int used;
unsigned int limit;
char* read_target;
unsigned int read_target_size;
int flags;
} HTTP_ByteQueue;
typedef unsigned long long HTTP_ByteQueueOffset;
#define HTTP_ENGINE_STATEBIT_CLIENT (1 << 0)
#define HTTP_ENGINE_STATEBIT_CLOSED (1 << 1)
#define HTTP_ENGINE_STATEBIT_RECV_BUF (1 << 2)
#define HTTP_ENGINE_STATEBIT_RECV_ACK (1 << 3)
#define HTTP_ENGINE_STATEBIT_SEND_BUF (1 << 4)
#define HTTP_ENGINE_STATEBIT_SEND_ACK (1 << 5)
#define HTTP_ENGINE_STATEBIT_REQUEST (1 << 6)
#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_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_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,
HTTP_ENGINE_STATE_CLIENT_RECV_BUF = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_RECV_BUF,
HTTP_ENGINE_STATE_CLIENT_RECV_ACK = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_RECV_ACK,
HTTP_ENGINE_STATE_CLIENT_READY = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_RESPONSE,
HTTP_ENGINE_STATE_CLIENT_CLOSED = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_CLOSED,
HTTP_ENGINE_STATE_SERVER_RECV_BUF = HTTP_ENGINE_STATEBIT_RECV_BUF,
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_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,
HTTP_ENGINE_STATE_SERVER_CLOSED = HTTP_ENGINE_STATEBIT_CLIENT,
} HTTP_EngineState;
typedef struct {
HTTP_EngineState state;
HTTP_ByteQueue input;
HTTP_ByteQueue output;
int numexch;
int reqsize;
int closing;
int keepalive;
HTTP_ByteQueueOffset response_offset;
HTTP_ByteQueueOffset content_length_offset;
HTTP_ByteQueueOffset content_length_value_offset;
union {
HTTP_Request req;
HTTP_Response res;
} result;
} HTTP_Engine;
void http_engine_init (HTTP_Engine *eng, int client, HTTP_MemoryFunc memfunc, void *memfuncdata);
void http_engine_free (HTTP_Engine *eng);
void http_engine_close (HTTP_Engine *eng);
HTTP_EngineState http_engine_state (HTTP_Engine *eng);
const char* http_engine_statestr(HTTP_EngineState state); // TODO: remove
char* http_engine_recvbuf (HTTP_Engine *eng, int *cap);
void http_engine_recvack (HTTP_Engine *eng, int num);
char* http_engine_sendbuf (HTTP_Engine *eng, int *len);
void http_engine_sendack (HTTP_Engine *eng, int num);
HTTP_Request* http_engine_getreq (HTTP_Engine *eng);
HTTP_Response* http_engine_getres (HTTP_Engine *eng);
void http_engine_url (HTTP_Engine *eng, HTTP_Method method, HTTP_String url, int minor);
void http_engine_status (HTTP_Engine *eng, int status);
void http_engine_header (HTTP_Engine *eng, HTTP_String str);
void http_engine_body (HTTP_Engine *eng, HTTP_String str);
void http_engine_bodycap (HTTP_Engine *eng, int mincap);
char* http_engine_bodybuf (HTTP_Engine *eng, int *cap);
void http_engine_bodyack (HTTP_Engine *eng, int num);
void http_engine_done (HTTP_Engine *eng);
void http_engine_undo (HTTP_Engine *eng);
#endif // HTTP_ENGINE_INCLUDED
////////////////////////////////////////////////////////////////////////////////////////
// src/cert.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/cert.h"
#ifndef CERT_INCLUDED
#define CERT_INCLUDED
#ifndef HTTP_AMALGAMATION
#include "basic.h"
#endif
// This is an utility to create self-signed certificates
// useful when testing HTTPS servers locally. This is only
// meant to be used by people starting out with a library
// and simplifying the zero to one phase.
//
// The C, O, and CN are respectively country name, organization name,
// and common name of the certificate. For instance:
//
// C="IT"
// O="My Organization"
// CN="my_website.com"
//
// The output is a certificate file in PEM format and a private
// key file with the key used to sign the certificate.
int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN,
HTTP_String cert_file, HTTP_String key_file);
#endif // CERT_INCLUDED
////////////////////////////////////////////////////////////////////////////////////////
// src/client.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/client.h"
#ifndef CLIENT_INCLUDED
#define CLIENT_INCLUDED
#include <stdbool.h>
#ifndef HTTP_AMALGAMATION
#include "parse.h"
#endif
// Initialize the global state of cHTTP.
//
// cHTTP tries to avoid global state. What this function
// does is call the global initialization functions of
// its dependencies (OpenSSL and Winsock)
int http_global_init(void);
// Free the global state of cHTTP.
void http_global_free(void);
// Opaque type describing an "HTTP client". Any request
// that is started must always be associated to an HTTP
// client object.
typedef struct HTTP_Client HTTP_Client;
// Handle for a pending request. This should be considered
// opaque. Don't read or modify its fields!
typedef struct {
void *data0;
int data1;
int data2;
} HTTP_RequestBuilder;
// Initialize a client object. If something goes wrong,
// NULL is returned.
HTTP_Client *http_client_init(void);
// Deinitialize a client object
void http_client_free(HTTP_Client *client);
// Create a request object associated to the given client.
// On success, 0 is returned and the handle is initialized.
// On error, -1 is returned.
int http_client_get_builder(HTTP_Client *client, HTTP_RequestBuilder *builder);
void http_request_builder_user_data(HTTP_RequestBuilder builder, void *user_data);
// Enable/disable I/O tracing for the specified request.
// This must be done when the request is in the initialization
// phase.
void http_request_builder_trace(HTTP_RequestBuilder builder, bool trace);
// Set the method and URL of the specified request object.
// This must be the first thing you do after http_client_request
// is called (you may http_request_trace before, but nothing
// else!)
void http_request_builder_line(HTTP_RequestBuilder builder, HTTP_Method method, HTTP_String url);
// Append a header to the specified request. You must call
// this after http_request_line and may do so multiple times.
void http_request_builder_header(HTTP_RequestBuilder builder, HTTP_String str);
// Append some data to the request's body. You must call
// this after either http_request_line or http_request_header.
void http_request_builder_body(HTTP_RequestBuilder builder, HTTP_String str);
// Mark the initialization of the request as completed and
// perform the request.
void http_request_builder_submit(HTTP_RequestBuilder builder);
// Free resources associated to a request. This must be called
// after the request has completed.
//
// TODO: allow aborting pending requests
void http_response_free(HTTP_Response *res);
// Wait for the completion of one request associated to
// the client. The handle of the resolved request is returned
// through the handle output parameter. If you're not
// interested in which request completed (like when you
// have only one pending request), you can pass NULL.
//
// On error -1 is retutned, else 0 is returned and the
// handle is initialized.
//
// Note that calling this function when no requests are
// pending is considered an error.
int http_client_wait(HTTP_Client *client, HTTP_Response **res, void **user_data);
// TODO: comment
HTTP_Response *http_get(HTTP_String url,
HTTP_String *headers, int num_headers);
// TODO: comment
HTTP_Response *http_post(HTTP_String url,
HTTP_String *headers, int num_headers,
HTTP_String body);
#endif // CLIENT_INCLUDED
////////////////////////////////////////////////////////////////////////////////////////
// src/server.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/server.h"
#ifndef HTTP_SERVER_INCLUDED
#define HTTP_SERVER_INCLUDED
#include <stdint.h>
#ifndef HTTP_AMALGAMATION
#include "parse.h"
#endif
typedef struct {
void *data0;
int data1;
int data2;
} HTTP_ResponseBuilder;
typedef struct HTTP_Server HTTP_Server;
HTTP_Server *http_server_init(HTTP_String addr, uint16_t port);
HTTP_Server *http_server_init_ex(HTTP_String addr, uint16_t port,
uint16_t secure_port, HTTP_String cert_key, HTTP_String private_key);
void http_server_free (HTTP_Server *server);
int http_server_wait (HTTP_Server *server, HTTP_Request **req, HTTP_ResponseBuilder *handle);
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);
void http_response_builder_body (HTTP_ResponseBuilder res, HTTP_String str);
void http_response_builder_bodycap (HTTP_ResponseBuilder res, int mincap);
char* http_response_builder_bodybuf (HTTP_ResponseBuilder res, int *cap);
void http_response_builder_bodyack (HTTP_ResponseBuilder res, int num);
void http_response_builder_undo (HTTP_ResponseBuilder res);
void http_response_builder_done (HTTP_ResponseBuilder res);
#endif // HTTP_SERVER_INCLUDED
////////////////////////////////////////////////////////////////////////////////////////
// src/router.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/router.h"
#ifndef HTTP_ROUTER_INCLUDED
#define HTTP_ROUTER_INCLUDED
#ifndef HTTP_AMALGAMATION
#include "server.h"
#endif
typedef struct HTTP_Router HTTP_Router;
typedef void (*HTTP_RouterFunc)(HTTP_Request*, HTTP_ResponseBuilder, void*);;
HTTP_Router* http_router_init (void);
void http_router_free (HTTP_Router *router);
void http_router_resolve (HTTP_Router *router, HTTP_Request *req, HTTP_ResponseBuilder res);
void http_router_dir (HTTP_Router *router, HTTP_String endpoint, HTTP_String path);
void http_router_func (HTTP_Router *router, HTTP_Method method, HTTP_String endpoint, HTTP_RouterFunc func, void*);
int http_serve (char *addr, int port, HTTP_Router *router);
#endif // HTTP_ROUTER_INCLUDED
#endif // HTTP_AMALGAMATION
////////////////////////////////////////////////////////////////////////////////////////
// 3p/chttp.c
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "3p/chttp.c"
#ifndef HTTP_NOINCLUDE
#include "chttp.h"
#endif
////////////////////////////////////////////////////////////////////////////////////////
// src/sec.h
@@ -6515,102 +7145,6 @@ char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count,
return output;
}
////////////////////////////////////////////////////////////////////////////////////////
// 3p/wl.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "3p/wl.h"
#include <stdint.h>
#include <stdbool.h>
typedef struct WL_Runtime WL_Runtime;
typedef struct WL_Compiler WL_Compiler;
typedef struct {
char *ptr;
int len;
} WL_String;
typedef struct {
char *ptr;
int len;
int cur;
} WL_Arena;
typedef struct {
char *ptr;
int len;
} WL_Program;
typedef enum {
WL_ADD_ERROR,
WL_ADD_AGAIN,
WL_ADD_LINK,
} WL_AddResultType;
typedef struct {
WL_AddResultType type;
WL_String path;
} WL_AddResult;
typedef enum {
WL_EVAL_NONE,
WL_EVAL_DONE,
WL_EVAL_ERROR,
WL_EVAL_OUTPUT,
WL_EVAL_SYSVAR,
WL_EVAL_SYSCALL,
} WL_EvalResultType;
typedef struct {
WL_EvalResultType type;
WL_String str;
} WL_EvalResult;
WL_Compiler* wl_compiler_init (WL_Arena *arena);
WL_AddResult wl_compiler_add (WL_Compiler *compiler, WL_String content);
int wl_compiler_link (WL_Compiler *compiler, WL_Program *program);
WL_String wl_compiler_error (WL_Compiler *compiler);
int wl_dump_ast (WL_Compiler *compiler, char *dst, int cap);
void wl_dump_program (WL_Program program);
WL_Runtime* wl_runtime_init (WL_Arena *arena, WL_Program program);
WL_EvalResult wl_runtime_eval (WL_Runtime *rt);
WL_String wl_runtime_error (WL_Runtime *rt);
void wl_runtime_dump (WL_Runtime *rt);
bool wl_streq (WL_String a, char *b, int blen);
int wl_arg_count (WL_Runtime *rt);
bool wl_arg_none (WL_Runtime *rt, int idx);
bool wl_arg_bool (WL_Runtime *rt, int idx, bool *x);
bool wl_arg_s64 (WL_Runtime *rt, int idx, int64_t *x);
bool wl_arg_f64 (WL_Runtime *rt, int idx, double *x);
bool wl_arg_str (WL_Runtime *rt, int idx, WL_String *x);
bool wl_arg_array (WL_Runtime *rt, int idx);
bool wl_arg_map (WL_Runtime *rt, int idx);
bool wl_peek_none (WL_Runtime *rt, int off);
bool wl_peek_bool (WL_Runtime *rt, int off, bool *x);
bool wl_peek_s64 (WL_Runtime *rt, int off, int64_t *x);
bool wl_peek_f64 (WL_Runtime *rt, int off, double *x);
bool wl_peek_str (WL_Runtime *rt, int off, WL_String *x);
bool wl_pop_any (WL_Runtime *rt);
bool wl_pop_none (WL_Runtime *rt);
bool wl_pop_bool (WL_Runtime *rt, bool *x);
bool wl_pop_s64 (WL_Runtime *rt, int64_t *x);
bool wl_pop_f64 (WL_Runtime *rt, double *x);
bool wl_pop_str (WL_Runtime *rt, WL_String *x);
void wl_push_none (WL_Runtime *rt);
void wl_push_true (WL_Runtime *rt);
void wl_push_false (WL_Runtime *rt);
void wl_push_s64 (WL_Runtime *rt, int64_t x);
void wl_push_f64 (WL_Runtime *rt, double x);
void wl_push_str (WL_Runtime *rt, WL_String x);
void wl_push_array (WL_Runtime *rt, int cap);
void wl_push_map (WL_Runtime *rt, int cap);
void wl_push_arg (WL_Runtime *rt, int idx);
void wl_insert (WL_Runtime *rt);
void wl_append (WL_Runtime *rt);
////////////////////////////////////////////////////////////////////////////////////////
// 3p/wl.c
////////////////////////////////////////////////////////////////////////////////////////
@@ -12453,6 +12987,8 @@ void wl_runtime_dump(WL_Runtime *rt)
#line 1 "src/main.c"
#include "sqlite3.h"
#include "wl.h"
#include "chttp.h"
#include "cweb.h"
#ifdef __linux__
@@ -12509,9 +13045,27 @@ struct CWEB {
SQLiteCache *dbcache;
// Template
TemplateCache *tcpcache;
TemplateCache *tpcache;
bool allow_insecure_login;
CWEB_Request req;
};
struct CWEB_Request {
CWEB *cweb;
WL_Arena arena;
HTTP_Request *req;
HTTP_ResponseBuilder builder;
// Session
bool just_created_session;
int user_id;
CWEB_String sess;
CWEB_String csrf;
};
///////////////////////////
@@ -12722,7 +13276,7 @@ static void session_storage_free(SessionStorage *storage)
free(storage);
}
static Session *lookup_session_slot(SessionStorage *storage, HTTP_String sess, bool find_unused)
static Session *lookup_session_slot(SessionStorage *storage, CWEB_String sess, bool find_unused)
{
if (find_unused && 2 * storage->count + 2 > storage->capacity)
return NULL;
@@ -12775,7 +13329,7 @@ static Session *lookup_session_slot(SessionStorage *storage, HTTP_String sess, b
return NULL;
}
static int create_session(SessionStorage *storage, int user, HTTP_String *psess, HTTP_String *pcsrf)
static int create_session(SessionStorage *storage, int user, CWEB_String *psess, CWEB_String *pcsrf)
{
int ret;
char raw_sess[SESS_RAW_TOKEN_SIZE];
@@ -12792,21 +13346,21 @@ static int create_session(SessionStorage *storage, int user, HTTP_String *psess,
unpack_token(raw_sess, SESS_RAW_TOKEN_SIZE, sess, SESS_TOKEN_SIZE);
unpack_token(raw_csrf, CSRF_RAW_TOKEN_SIZE, csrf, CSRF_TOKEN_SIZE);
Session *found = lookup_session_slot(storage, (HTTP_String) { sess, SESS_TOKEN_SIZE }, true);
Session *found = lookup_session_slot(storage, (CWEB_String) { sess, SESS_TOKEN_SIZE }, true);
if (found == NULL) return -1;
found->user = user;
memcpy(found->sess, sess, SESS_TOKEN_SIZE);
memcpy(found->csrf, csrf, CSRF_TOKEN_SIZE);
*psess = (HTTP_String) { found->sess, SESS_TOKEN_SIZE };
*pcsrf = (HTTP_String) { found->csrf, CSRF_TOKEN_SIZE };
*psess = (CWEB_String) { found->sess, SESS_TOKEN_SIZE };
*pcsrf = (CWEB_String) { found->csrf, CSRF_TOKEN_SIZE };
storage->count++;
return 0;
}
static int delete_session(SessionStorage *storage, HTTP_String sess)
static int delete_session(SessionStorage *storage, CWEB_String sess)
{
char raw_sess[SESS_RAW_TOKEN_SIZE];
if (sess.len != SESS_TOKEN_SIZE || pack_token(sess.ptr, sess.len, raw_sess, (int) sizeof(raw_sess)) < 0)
@@ -12820,13 +13374,13 @@ static int delete_session(SessionStorage *storage, HTTP_String sess)
return 0;
}
static int find_session(SessionStorage *storage, HTTP_String sess, HTTP_String *pcsrf, int *puser)
static int find_session(SessionStorage *storage, CWEB_String sess, CWEB_String *pcsrf, int *puser)
{
Session *found = lookup_session_slot(storage, sess, false);
if (found == NULL)
return -1;
assert(found->user >= 0);
*pcsrf = (HTTP_String) { found->csrf, CSRF_TOKEN_SIZE };
*pcsrf = (CWEB_String) { found->csrf, CSRF_TOKEN_SIZE };
*puser = found->user;
return 0;
}
@@ -12947,7 +13501,7 @@ static int sqlite3utils_prepare(SQLiteCache *cache, sqlite3_stmt **pstmt, char *
}
static int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
sqlite3_stmt **pstmt, char *fmt, VArgs args)
sqlite3_stmt **pstmt, char *fmt, CWEB_VArgs args)
{
sqlite3_stmt *stmt;
int ret = sqlite3utils_prepare(cache, &stmt, fmt, strlen(fmt));
@@ -12987,7 +13541,7 @@ static int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
return SQLITE_OK;
}
int64_t cweb_database_insert_impl(CWEB *cweb, const char *fmt, VArgs args)
int64_t cweb_database_insert_impl(CWEB *cweb, const char *fmt, CWEB_VArgs args)
{
sqlite3_stmt *stmt;
int ret = sqlite3utils_prepare_and_bind_impl(cweb->dbcache, &stmt, fmt, args);
@@ -13092,7 +13646,7 @@ int cweb_next_query_row_impl(CWEB_QueryResult *res, CWEB_VArgs args)
case CWEB_VARG_TYPE_PSTR:
{
*args.ptr[i].pstr = (HTTP_String) {
*args.ptr[i].pstr = (CWEB_String) {
sqlite3_column_text(res->handle, i),
sqlite3_column_bytes(res->handle, i),
};
@@ -13127,7 +13681,7 @@ void cweb_global_free(void)
http_global_free();
}
int cweb_init(CWEB *cweb, CWEB_String addr, uint16_t port)
CWEB *web_init(CWEB_String addr, uint16_t port)
{
// If set, allows logins and signups over HTTP, which is highly insecure.
// This allows compiling the application without TLS when developing.
@@ -13136,29 +13690,38 @@ int cweb_init(CWEB *cweb, CWEB_String addr, uint16_t port)
if (allow_insecure_login)
printf("WARNING: allow_insecure_login is true\n");
CWEB *cweb = malloc(sizeof(CWEB));
if (cweb == NULL)
return -1;
cweb->pool_cap = 1<<20;
cweb->pool = malloc(cweb->pool_cap);
if (cweb->pool == NULL)
if (cweb->pool == NULL) {
free(cweb);
return -1;
}
cweb->tpcache = template_cache_init(4);
if (cweb->tpcache == NULL) {
free(cweb->pool);
free(cweb);
return -1;
}
cweb->session_storage = session_storage_init(1024);
if (cweb->session_storage == NULL) {
template_cache_free(cweb->tcpcache);
template_cache_free(cweb->tpcache);
free(cweb->pool);
free(cweb);
return -1;
}
cweb->server = http_server_init(addr, port);
cweb->server = http_server_init((HTTP_String) { addr.ptr, addr.len }, port);
if (cweb->server == NULL) {
session_storage_free(cweb->session_storage);
template_cache_free(cweb->tcpcache);
template_cache_free(cweb->tpcache);
free(cweb->pool);
free(cweb);
return -1;
}
@@ -13179,6 +13742,7 @@ void cweb_free(CWEB *cweb)
sqlite_cache_free(cweb->dbcache);
sqlite3_close(cweb->db);
}
free(cweb);
}
void cweb_version(void)
@@ -13232,25 +13796,21 @@ int cweb_enable_database(CWEB *cweb, CWEB_String file)
return 0;
}
CWEB_Request cweb_wait(CWEB *cweb)
CWEB_Request *cweb_wait(CWEB *cweb)
{
CWEB_Request req;
CWEB_Request *req = &cweb->req;
int ret = http_server_wait(cweb->server, &req.req, &req.builder);
int ret = http_server_wait(cweb->server, &req->req, &req->builder);
if (ret < 0) return -1;
req.arena = (WL_Arena) { cweb->pool, cweb->pool_cap, 0 };
req->arena = (WL_Arena) { cweb->pool, cweb->pool_cap, 0 };
int user_id;
HTTP_String sess;
HTTP_String csrf;
req.just_created_session = false;
req.sess = http_getcookie(req.req, HTTP_STR("sess_token"));
if (find_session(cweb->session_storage, sess, &csrf, &user_id) < 0) {
req.user_id = -1;
req.sess = (HTTP_String) { NULL, 0 };
req.csrf = (HTTP_String) { NULL, 0 };
req->just_created_session = false;
req->sess = http_get_cookie(req->req, HTTP_STR("sess_token"));
if (find_session(cweb->session_storage, req->sess, &req->csrf, &req->user_id) < 0) {
req->user_id = -1;
req->sess = (CWEB_String) { NULL, 0 };
req->csrf = (CWEB_String) { NULL, 0 };
}
return req;
+6 -552
View File
@@ -3,545 +3,15 @@
// This file was generated automatically. Do not modify directly!
////////////////////////////////////////////////////////////////////////////////////////
// 3p/chttp.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "3p/chttp.h"
#ifndef HTTP_AMALGAMATION
#define HTTP_AMALGAMATION
// This file was generated automatically. Do not modify directly!
////////////////////////////////////////////////////////////////////////////////////////
// src/basic.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/basic.h"
#ifndef CHTTP_BASIC_INCLUDED
#define CHTTP_BASIC_INCLUDED
#include <stdbool.h>
// String type used throughout cHTTP.
typedef struct {
char *ptr;
int len;
} HTTP_String;
// Compare two strings and return true iff they have
// the same contents.
bool http_streq(HTTP_String s1, HTTP_String s2);
// Compre two strings case-insensitively (uppercase and
// lowercase versions of a letter are considered the same)
// and return true iff they have the same contents.
bool http_streqcase(HTTP_String s1, HTTP_String s2);
// Remove spaces and tabs from the start and the end of
// a string. This doesn't change the original string and
// the new one references the contents of the original one.
HTTP_String http_trim(HTTP_String s);
// TODO: comment
void print_bytes(HTTP_String prefix, HTTP_String src);
// Macro to simplify converting string literals to
// HTTP_String.
//
// Instead of doing this:
//
// char *s = "some string";
//
// You do this:
//
// HTTP_String s = HTTP_STR("some string")
//
// This is a bit cumbersome, but better than null-terminated
// strings, having a pointer and length variable pairs whenever
// a function operates on a string. If this wasn't a library
// I would have done for
//
// #define S(X) ...
//
// But I don't want to cause collisions with user code.
#define HTTP_STR(X) ((HTTP_String) {(X), sizeof(X)-1})
// Returns the number of items of a static array.
#define HTTP_COUNT(X) (sizeof(X) / sizeof((X)[0]))
// TODO: comment
#define HTTP_UNPACK(X) (X).len, (X).ptr
// Macro used to make invariants of the code more explicit.
//
// Say you have some function that operates on two integers
// and that by design their sum is always 100. This macro is
// useful to make that explicit:
//
// void func(int a, int b)
// {
// HTTP_ASSERT(a + b == 100);
// ...
// }
//
// Assertions are about documentation, *not* error management.
//
// In non-release builds (where NDEBUG is not defined) asserted
// expressions are evaluated and if not true, the program is halted.
// This is quite nice as they offer a way to document code in
// a way that can be checked at runtime, unlike regular comments
// like this one.
#ifdef NDEBUG
#define HTTP_ASSERT(X) ((void) 0)
#else
#define HTTP_ASSERT(X) {if (!(X)) { __builtin_trap(); }}
#endif
#endif // CHTTP_BASIC_INCLUDED
////////////////////////////////////////////////////////////////////////////////////////
// src/parse.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/parse.h"
#ifndef PARSE_INCLUDED
#define PARSE_INCLUDED
#ifndef HTTP_AMALGAMATION
#include "basic.h"
#endif
#define HTTP_MAX_HEADERS 32
typedef struct {
unsigned int data;
} HTTP_IPv4;
typedef struct {
unsigned short data[8];
} HTTP_IPv6;
typedef enum {
HTTP_HOST_MODE_VOID = 0,
HTTP_HOST_MODE_NAME,
HTTP_HOST_MODE_IPV4,
HTTP_HOST_MODE_IPV6,
} HTTP_HostMode;
typedef struct {
HTTP_HostMode mode;
HTTP_String text;
union {
HTTP_String name;
HTTP_IPv4 ipv4;
HTTP_IPv6 ipv6;
};
} HTTP_Host;
typedef struct {
HTTP_String userinfo;
HTTP_Host host;
int port;
} HTTP_Authority;
// ZII
typedef struct {
HTTP_String scheme;
HTTP_Authority authority;
HTTP_String path;
HTTP_String query;
HTTP_String fragment;
} HTTP_URL;
typedef enum {
HTTP_METHOD_GET,
HTTP_METHOD_HEAD,
HTTP_METHOD_POST,
HTTP_METHOD_PUT,
HTTP_METHOD_DELETE,
HTTP_METHOD_CONNECT,
HTTP_METHOD_OPTIONS,
HTTP_METHOD_TRACE,
HTTP_METHOD_PATCH,
} HTTP_Method;
typedef struct {
HTTP_String name;
HTTP_String value;
} 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_Request;
typedef struct {
void* context;
int minor;
int status;
HTTP_String reason;
int num_headers;
HTTP_Header headers[HTTP_MAX_HEADERS];
HTTP_String body;
} HTTP_Response;
int http_parse_ipv4 (char *src, int len, HTTP_IPv4 *ipv4);
int http_parse_ipv6 (char *src, int len, HTTP_IPv6 *ipv6);
int http_parse_url (char *src, int len, HTTP_URL *url);
int http_parse_request (char *src, int len, HTTP_Request *req);
int http_parse_response (char *src, int len, HTTP_Response *res);
int http_find_header (HTTP_Header *headers, int num_headers, HTTP_String name);
HTTP_String http_get_cookie (HTTP_Request *req, HTTP_String name);
HTTP_String http_get_param (HTTP_String body, HTTP_String str, char *mem, int cap);
int http_get_param_i (HTTP_String body, HTTP_String str);
#endif // PARSE_INCLUDED
////////////////////////////////////////////////////////////////////////////////////////
// src/engine.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/engine.h"
#ifndef HTTP_ENGINE_INCLUDED
#define HTTP_ENGINE_INCLUDED
#ifndef HTTP_AMALGAMATION
#include "parse.h"
#endif
typedef enum {
HTTP_MEMFUNC_MALLOC,
HTTP_MEMFUNC_FREE,
} HTTP_MemoryFuncTag;
typedef void*(*HTTP_MemoryFunc)(HTTP_MemoryFuncTag tag,
void *ptr, int len, void *data);
typedef struct {
HTTP_MemoryFunc memfunc;
void *memfuncdata;
unsigned long long curs;
char* data;
unsigned int head;
unsigned int size;
unsigned int used;
unsigned int limit;
char* read_target;
unsigned int read_target_size;
int flags;
} HTTP_ByteQueue;
typedef unsigned long long HTTP_ByteQueueOffset;
#define HTTP_ENGINE_STATEBIT_CLIENT (1 << 0)
#define HTTP_ENGINE_STATEBIT_CLOSED (1 << 1)
#define HTTP_ENGINE_STATEBIT_RECV_BUF (1 << 2)
#define HTTP_ENGINE_STATEBIT_RECV_ACK (1 << 3)
#define HTTP_ENGINE_STATEBIT_SEND_BUF (1 << 4)
#define HTTP_ENGINE_STATEBIT_SEND_ACK (1 << 5)
#define HTTP_ENGINE_STATEBIT_REQUEST (1 << 6)
#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_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_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,
HTTP_ENGINE_STATE_CLIENT_RECV_BUF = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_RECV_BUF,
HTTP_ENGINE_STATE_CLIENT_RECV_ACK = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_RECV_ACK,
HTTP_ENGINE_STATE_CLIENT_READY = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_RESPONSE,
HTTP_ENGINE_STATE_CLIENT_CLOSED = HTTP_ENGINE_STATEBIT_CLIENT | HTTP_ENGINE_STATEBIT_CLOSED,
HTTP_ENGINE_STATE_SERVER_RECV_BUF = HTTP_ENGINE_STATEBIT_RECV_BUF,
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_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,
HTTP_ENGINE_STATE_SERVER_CLOSED = HTTP_ENGINE_STATEBIT_CLIENT,
} HTTP_EngineState;
typedef struct {
HTTP_EngineState state;
HTTP_ByteQueue input;
HTTP_ByteQueue output;
int numexch;
int reqsize;
int closing;
int keepalive;
HTTP_ByteQueueOffset response_offset;
HTTP_ByteQueueOffset content_length_offset;
HTTP_ByteQueueOffset content_length_value_offset;
union {
HTTP_Request req;
HTTP_Response res;
} result;
} HTTP_Engine;
void http_engine_init (HTTP_Engine *eng, int client, HTTP_MemoryFunc memfunc, void *memfuncdata);
void http_engine_free (HTTP_Engine *eng);
void http_engine_close (HTTP_Engine *eng);
HTTP_EngineState http_engine_state (HTTP_Engine *eng);
const char* http_engine_statestr(HTTP_EngineState state); // TODO: remove
char* http_engine_recvbuf (HTTP_Engine *eng, int *cap);
void http_engine_recvack (HTTP_Engine *eng, int num);
char* http_engine_sendbuf (HTTP_Engine *eng, int *len);
void http_engine_sendack (HTTP_Engine *eng, int num);
HTTP_Request* http_engine_getreq (HTTP_Engine *eng);
HTTP_Response* http_engine_getres (HTTP_Engine *eng);
void http_engine_url (HTTP_Engine *eng, HTTP_Method method, HTTP_String url, int minor);
void http_engine_status (HTTP_Engine *eng, int status);
void http_engine_header (HTTP_Engine *eng, HTTP_String str);
void http_engine_body (HTTP_Engine *eng, HTTP_String str);
void http_engine_bodycap (HTTP_Engine *eng, int mincap);
char* http_engine_bodybuf (HTTP_Engine *eng, int *cap);
void http_engine_bodyack (HTTP_Engine *eng, int num);
void http_engine_done (HTTP_Engine *eng);
void http_engine_undo (HTTP_Engine *eng);
#endif // HTTP_ENGINE_INCLUDED
////////////////////////////////////////////////////////////////////////////////////////
// src/cert.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/cert.h"
#ifndef CERT_INCLUDED
#define CERT_INCLUDED
#ifndef HTTP_AMALGAMATION
#include "basic.h"
#endif
// This is an utility to create self-signed certificates
// useful when testing HTTPS servers locally. This is only
// meant to be used by people starting out with a library
// and simplifying the zero to one phase.
//
// The C, O, and CN are respectively country name, organization name,
// and common name of the certificate. For instance:
//
// C="IT"
// O="My Organization"
// CN="my_website.com"
//
// The output is a certificate file in PEM format and a private
// key file with the key used to sign the certificate.
int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN,
HTTP_String cert_file, HTTP_String key_file);
#endif // CERT_INCLUDED
////////////////////////////////////////////////////////////////////////////////////////
// src/client.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/client.h"
#ifndef CLIENT_INCLUDED
#define CLIENT_INCLUDED
#include <stdbool.h>
#ifndef HTTP_AMALGAMATION
#include "parse.h"
#endif
// Initialize the global state of cHTTP.
//
// cHTTP tries to avoid global state. What this function
// does is call the global initialization functions of
// its dependencies (OpenSSL and Winsock)
int http_global_init(void);
// Free the global state of cHTTP.
void http_global_free(void);
// Opaque type describing an "HTTP client". Any request
// that is started must always be associated to an HTTP
// client object.
typedef struct HTTP_Client HTTP_Client;
// Handle for a pending request. This should be considered
// opaque. Don't read or modify its fields!
typedef struct {
void *data0;
int data1;
int data2;
} HTTP_RequestBuilder;
// Initialize a client object. If something goes wrong,
// NULL is returned.
HTTP_Client *http_client_init(void);
// Deinitialize a client object
void http_client_free(HTTP_Client *client);
// Create a request object associated to the given client.
// On success, 0 is returned and the handle is initialized.
// On error, -1 is returned.
int http_client_get_builder(HTTP_Client *client, HTTP_RequestBuilder *builder);
void http_request_builder_user_data(HTTP_RequestBuilder builder, void *user_data);
// Enable/disable I/O tracing for the specified request.
// This must be done when the request is in the initialization
// phase.
void http_request_builder_trace(HTTP_RequestBuilder builder, bool trace);
// Set the method and URL of the specified request object.
// This must be the first thing you do after http_client_request
// is called (you may http_request_trace before, but nothing
// else!)
void http_request_builder_line(HTTP_RequestBuilder builder, HTTP_Method method, HTTP_String url);
// Append a header to the specified request. You must call
// this after http_request_line and may do so multiple times.
void http_request_builder_header(HTTP_RequestBuilder builder, HTTP_String str);
// Append some data to the request's body. You must call
// this after either http_request_line or http_request_header.
void http_request_builder_body(HTTP_RequestBuilder builder, HTTP_String str);
// Mark the initialization of the request as completed and
// perform the request.
void http_request_builder_submit(HTTP_RequestBuilder builder);
// Free resources associated to a request. This must be called
// after the request has completed.
//
// TODO: allow aborting pending requests
void http_response_free(HTTP_Response *res);
// Wait for the completion of one request associated to
// the client. The handle of the resolved request is returned
// through the handle output parameter. If you're not
// interested in which request completed (like when you
// have only one pending request), you can pass NULL.
//
// On error -1 is retutned, else 0 is returned and the
// handle is initialized.
//
// Note that calling this function when no requests are
// pending is considered an error.
int http_client_wait(HTTP_Client *client, HTTP_Response **res, void **user_data);
// TODO: comment
HTTP_Response *http_get(HTTP_String url,
HTTP_String *headers, int num_headers);
// TODO: comment
HTTP_Response *http_post(HTTP_String url,
HTTP_String *headers, int num_headers,
HTTP_String body);
#endif // CLIENT_INCLUDED
////////////////////////////////////////////////////////////////////////////////////////
// src/server.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/server.h"
#ifndef HTTP_SERVER_INCLUDED
#define HTTP_SERVER_INCLUDED
#include <stdint.h>
#ifndef HTTP_AMALGAMATION
#include "parse.h"
#endif
typedef struct {
void *data0;
int data1;
int data2;
} HTTP_ResponseBuilder;
typedef struct HTTP_Server HTTP_Server;
HTTP_Server *http_server_init(HTTP_String addr, uint16_t port);
HTTP_Server *http_server_init_ex(HTTP_String addr, uint16_t port,
uint16_t secure_port, HTTP_String cert_key, HTTP_String private_key);
void http_server_free (HTTP_Server *server);
int http_server_wait (HTTP_Server *server, HTTP_Request **req, HTTP_ResponseBuilder *handle);
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);
void http_response_builder_body (HTTP_ResponseBuilder res, HTTP_String str);
void http_response_builder_bodycap (HTTP_ResponseBuilder res, int mincap);
char* http_response_builder_bodybuf (HTTP_ResponseBuilder res, int *cap);
void http_response_builder_bodyack (HTTP_ResponseBuilder res, int num);
void http_response_builder_undo (HTTP_ResponseBuilder res);
void http_response_builder_done (HTTP_ResponseBuilder res);
#endif // HTTP_SERVER_INCLUDED
////////////////////////////////////////////////////////////////////////////////////////
// src/router.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/router.h"
#ifndef HTTP_ROUTER_INCLUDED
#define HTTP_ROUTER_INCLUDED
#ifndef HTTP_AMALGAMATION
#include "server.h"
#endif
typedef struct HTTP_Router HTTP_Router;
typedef void (*HTTP_RouterFunc)(HTTP_Request*, HTTP_ResponseBuilder, void*);;
HTTP_Router* http_router_init (void);
void http_router_free (HTTP_Router *router);
void http_router_resolve (HTTP_Router *router, HTTP_Request *req, HTTP_ResponseBuilder res);
void http_router_dir (HTTP_Router *router, HTTP_String endpoint, HTTP_String path);
void http_router_func (HTTP_Router *router, HTTP_Method method, HTTP_String endpoint, HTTP_RouterFunc func, void*);
int http_serve (char *addr, int port, HTTP_Router *router);
#endif // HTTP_ROUTER_INCLUDED
#endif // HTTP_AMALGAMATION
////////////////////////////////////////////////////////////////////////////////////////
// src/main.h
////////////////////////////////////////////////////////////////////////////////////////
#line 1 "src/main.h"
#include <stdint.h>
#include <stdbool.h>
#define CWEB_STR(X) (CWEB_String) { (X), SIZEOF(X)-1 }
#define CWEB_STR(X) (CWEB_String) { (X), (int) sizeof(X)-1 }
typedef struct {
char *ptr;
@@ -730,33 +200,17 @@ typedef struct {
#define CWEB_VARGS(...) CWEB_DISPATCH__(__VA_ARGS__, CWEB_VARGS_5, CWEB_VARGS_4, CWEB_VARGS_3, CWEB_VARGS_2, CWEB_VARGS_1)(__VA_ARGS__)
typedef struct CWEB CWEB;
typedef struct {
CWEB *cweb;
WL_Arena arena;
HTTP_Request *req;
HTTP_ResponseBuilder builder;
// Session
bool just_created_session;
int user_id;
CWEB_String sess;
CWEB_String csrf;
} CWEB_Request;
typedef struct CWEB_Request CWEB_Request;
int cweb_global_init(void);
void cweb_global_free(void);
int cweb_init(CWEB *cweb, CWEB_String addr, uint16_t port);
CWEB *cweb_init(CWEB_String addr, uint16_t port);
void cweb_free(CWEB *cweb);
int cweb_enable_database(CWEB *cweb, CWEB_String file);
CWEB_Request cweb_wait(CWEB *cweb);
CWEB_Request *cweb_wait(CWEB *cweb);
//////////////////////////////////////
// Session
+41 -37
View File
@@ -107,6 +107,8 @@ bool valid_comment_content(CWEB_String str)
return true;
}
// TODO: check for the correct methods at each endpoint
static int user_exists(CWEB *cweb, CWEB_String name, CWEB_String pass)
{
CWEB_QueryResult res = cweb_database_select(cweb, "SELECT id, hash FROM Users WHERE username=?", name);
@@ -136,7 +138,7 @@ static int user_exists(CWEB *cweb, CWEB_String name, CWEB_String pass)
return user_id;
}
static void endpoint_api_login(CWEB_Request *req)
static void endpoint_api_login(CWEB *cweb, CWEB_Request *req)
{
if (cweb_get_user_id(req) != -1) {
cweb_respond_redirect(req, CWEB_STR("/index"));
@@ -150,7 +152,7 @@ static void endpoint_api_login(CWEB_Request *req)
return;
}
int ret = user_exists(req->cweb, name, pass);
int ret = user_exists(cweb, name, pass);
if (ret < 0) {
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Invalid credentials</div>"));
return;
@@ -162,7 +164,7 @@ static void endpoint_api_login(CWEB_Request *req)
cweb_respond_redirect(req, CWEB_STR("/index"));
}
static void endpoint_api_signup(CWEB_Request *req)
static void endpoint_api_signup(CWEB *cweb, CWEB_Request *req)
{
if (cweb_get_user_id(req) != -1) {
cweb_respond_redirect(req, CWEB_STR("/index"));
@@ -191,7 +193,7 @@ static void endpoint_api_signup(CWEB_Request *req)
return;
}
int64_t insert_id = cweb_database_insert(req->cweb, "INSERT INTO Users(username, email, hash) VALUES (?, ?, ?)", name, email, hash);
int64_t insert_id = cweb_database_insert(cweb, "INSERT INTO Users(username, email, hash) VALUES (?, ?, ?)", name, email, hash);
if (insert_id < 0) {
// TODO: What if the user exists?
cweb_respond_basic(req, 400, CWEB_STR("<div class=\"error\">Internal error</div>"));
@@ -202,13 +204,13 @@ static void endpoint_api_signup(CWEB_Request *req)
cweb_respond_redirect(req, CWEB_STR("/index"));
}
static void endpoint_api_logout(CWEB_Request *req)
static void endpoint_api_logout(CWEB *cweb, CWEB_Request *req)
{
cweb_set_current_user_id(req, -1);
cweb_set_session_user_id(req, -1);
cweb_respond_redirect(req, CWEB_STR("/index"));
}
static void endpoint_api_post(CWEB_Request *req)
static void endpoint_api_post(CWEB *cweb, CWEB_Request *req)
{
int user_id = cweb_get_session_user_id(req);
if (user_id == -1) {
@@ -247,7 +249,7 @@ static void endpoint_api_post(CWEB_Request *req)
content = link;
}
int64_t insert_id = cweb_database_insert(req->cweb,
int64_t insert_id = cweb_database_insert(cweb,
"INSERT INTO Posts(author, title, is_link, content) VALUES (?, ?, ?, ?)",
user_id, title, is_link, content);
@@ -260,7 +262,7 @@ static void endpoint_api_post(CWEB_Request *req)
cweb_respond_redirect(req, "/post?id=%d", post_id);
}
static void endpoint_api_comment(CWEB_Request *req)
static void endpoint_api_comment(CWEB *cweb, CWEB_Request *req)
{
int user_id = cweb_get_session_user_id(req);
if (user_id == -1) {
@@ -285,8 +287,8 @@ static void endpoint_api_comment(CWEB_Request *req)
}
int64_t insert_id;
if (parent_comment == -1) insert_id = cweb_database_insert(req->cweb, "INSERT INTO Comments(author, content, parent_post) VALUES (?, ?, ?)", user_id, content, parent_post);
else insert_id = cweb_database_insert(req->cweb, "INSERT INTO Comments(author, content, parent_post, parent_comment) VALUES (?, ?, ?, ?)", user_id, content, parent_post, parent_comment);
if (parent_comment == -1) insert_id = cweb_database_insert(cweb, "INSERT INTO Comments(author, content, parent_post) VALUES (?, ?, ?)", user_id, content, parent_post);
else insert_id = cweb_database_insert(cweb, "INSERT INTO Comments(author, content, parent_post, parent_comment) VALUES (?, ?, ?, ?)", user_id, content, parent_post, parent_comment);
if (insert_id < 0) {
cweb_respond_basic(req, 200, CWEB_STR("<div class=\"error\">Internal error</div>"));
return;
@@ -295,12 +297,12 @@ static void endpoint_api_comment(CWEB_Request *req)
cweb_respond_redirect(req, "/post?id=%d", parent_post);
}
static void endpoint_index(CWEB_Request *req)
static void endpoint_index(CWEB *cweb, CWEB_Request *req)
{
cweb_respond_template(req, 200, CWEB_STR("pages/index.wl"), -1);
}
static void endpoint_write(CWEB_Request *req)
static void endpoint_write(CWEB *cweb, CWEB_Request *req)
{
if (cweb_get_session_user_id(req) == -1) {
cweb_respond_redirect(req, CWEB_STR("/index"));
@@ -310,7 +312,7 @@ static void endpoint_write(CWEB_Request *req)
cweb_respond_template(req, 200, CWEB_STR("pages/write.wl"), -1);
}
static void endpoint_login(CWEB_Request *req)
static void endpoint_login(CWEB *cweb, CWEB_Request *req)
{
if (cweb_get_session_user_id(req) != -1) {
cweb_respond_redirect(req, CWEB_STR("/index"));
@@ -320,7 +322,7 @@ static void endpoint_login(CWEB_Request *req)
cweb_respond_template(req, 200, CWEB_STR("pages/login.wl"), -1);
}
static void endpoint_signup(CWEB_Request *req)
static void endpoint_signup(CWEB *cweb, CWEB_Request *req)
{
if (cweb_get_session_user_id(req) != -1) {
cweb_respond_redirect(req, CWEB_STR("/index"));
@@ -330,15 +332,15 @@ static void endpoint_signup(CWEB_Request *req)
cweb_respond_template(req, 200, CWEB_STR("pages/signup.wl"), -1);
}
static void endpoint_post(CWEB_Request *req)
static void endpoint_post(CWEB *cweb, CWEB_Request *req)
{
int post_id = cweb_request_get_parami(req, CWEB_STR("id"));
int post_id = cweb_get_param_i(req, CWEB_STR("id"));
if (post_id < 0) {
cweb_respond_template(req, 404, CWEB_STR("pages/notfound.wl"), -1);
return;
}
CWEB_QueryResult res = cweb_database_select(req->cweb,
CWEB_QueryResult res = cweb_database_select(cweb,
"SELECT COUNT(*) FROM Posts WHERE id=?", post_id);
int num;
@@ -362,7 +364,7 @@ static void endpoint_post(CWEB_Request *req)
cweb_respond_template(req, 200, CWEB_STR("pages/post.wl"), post_id);
}
static void endpoint_fallback(CWEB_Request *req)
static void endpoint_fallback(CWEB *cweb, CWEB_Request *req)
{
cweb_respond_template(req, 404, CWEB_STR("pages/notfound.wl"), -1);
}
@@ -371,31 +373,33 @@ int main(void)
{
CWEB_String addr = CWEB_STR("127.0.0.1");
uint16_t port = 8080;
CWEB *cweb;
if (cweb_global_init() < 0)
return -1;
if (cweb_init(&cweb, addr, port) < 0)
CWEB *cweb = cweb_init(addr, port);
if (cweb == NULL) {
cweb_global_free();
return -1;
for (;;) {
CWEB_Request request = cweb_wait(&cweb);
cweb_add_endpoint(cweb, CWEB_STR("/api/login"), endpoint_api_login, CWEB_ENDPOINT_POST | CWEB_ENDPOINT_SECURE);
cweb_add_endpoint(cweb, CWEB_STR("/api/signup"), endpoint_api_signup, CWEB_ENDPOINT_POST | CWEB_ENDPOINT_SECURE);
cweb_add_endpoint(cweb, CWEB_STR("/api/logout"), endpoint_api_logout, CWEB_ENDPOINT_POST | CWEB_ENDPOINT_SECURE);
cweb_add_endpoint(cweb, CWEB_STR("/api/post"), endpoint_api_post, CWEB_ENDPOINT_POST);
cweb_add_endpoint(cweb, CWEB_STR("/api/comment"), endpoint_api_comment, CWEB_ENDPOINT_POST);
cweb_add_endpoint(cweb, CWEB_STR("/index"), endpoint_index, CWEB_ENDPOINT_GET);
cweb_add_endpoint(cweb, CWEB_STR("/write"), endpoint_write, CWEB_ENDPOINT_GET);
cweb_add_endpoint(cweb, CWEB_STR("/login"), endpoint_login, CWEB_ENDPOINT_GET);
cweb_add_endpoint(cweb, CWEB_STR("/signup"), endpoint_signup, CWEB_ENDPOINT_GET);
cweb_add_endpoint(cweb, CWEB_STR("/post"), endpoint_post, CWEB_ENDPOINT_GET);
cweb_fallback_endpoint(cweb, endpoint_fallback);
}
cweb_run(&cweb);
cweb_free(&cweb);
for (;;) {
CWEB_Request *req = cweb_wait(cweb);
if (0) {}
else if (cweb_match_endpoint(req, CWEB_STR("/api/login"))) endpoint_api_login(cweb, req);
else if (cweb_match_endpoint(req, CWEB_STR("/api/signup"))) endpoint_api_signup(cweb, req);
else if (cweb_match_endpoint(req, CWEB_STR("/api/logout"))) endpoint_api_logout(cweb, req);
else if (cweb_match_endpoint(req, CWEB_STR("/api/post"))) endpoint_api_post(cweb, req);
else if (cweb_match_endpoint(req, CWEB_STR("/api/comment"))) endpoint_api_comment(cweb, req);
else if (cweb_match_endpoint(req, CWEB_STR("/index"))) endpoint_index(cweb, req);
else if (cweb_match_endpoint(req, CWEB_STR("/write"))) endpoint_write(cweb, req);
else if (cweb_match_endpoint(req, CWEB_STR("/login"))) endpoint_login(cweb, req);
else if (cweb_match_endpoint(req, CWEB_STR("/signup"))) endpoint_signup(cweb, req);
else if (cweb_match_endpoint(req, CWEB_STR("/post"))) endpoint_post(cweb, req);
else endpoint_fallback(cweb, req);
}
cweb_free(cweb);
cweb_global_free();
return 0;
}
+62 -31
View File
@@ -1,4 +1,6 @@
#include "sqlite3.h"
#include "wl.h"
#include "chttp.h"
#include "cweb.h"
#ifdef __linux__
@@ -55,9 +57,27 @@ struct CWEB {
SQLiteCache *dbcache;
// Template
TemplateCache *tcpcache;
TemplateCache *tpcache;
bool allow_insecure_login;
CWEB_Request req;
};
struct CWEB_Request {
CWEB *cweb;
WL_Arena arena;
HTTP_Request *req;
HTTP_ResponseBuilder builder;
// Session
bool just_created_session;
int user_id;
CWEB_String sess;
CWEB_String csrf;
};
///////////////////////////
@@ -268,7 +288,7 @@ static void session_storage_free(SessionStorage *storage)
free(storage);
}
static Session *lookup_session_slot(SessionStorage *storage, HTTP_String sess, bool find_unused)
static Session *lookup_session_slot(SessionStorage *storage, CWEB_String sess, bool find_unused)
{
if (find_unused && 2 * storage->count + 2 > storage->capacity)
return NULL;
@@ -321,7 +341,7 @@ static Session *lookup_session_slot(SessionStorage *storage, HTTP_String sess, b
return NULL;
}
static int create_session(SessionStorage *storage, int user, HTTP_String *psess, HTTP_String *pcsrf)
static int create_session(SessionStorage *storage, int user, CWEB_String *psess, CWEB_String *pcsrf)
{
int ret;
char raw_sess[SESS_RAW_TOKEN_SIZE];
@@ -338,21 +358,21 @@ static int create_session(SessionStorage *storage, int user, HTTP_String *psess,
unpack_token(raw_sess, SESS_RAW_TOKEN_SIZE, sess, SESS_TOKEN_SIZE);
unpack_token(raw_csrf, CSRF_RAW_TOKEN_SIZE, csrf, CSRF_TOKEN_SIZE);
Session *found = lookup_session_slot(storage, (HTTP_String) { sess, SESS_TOKEN_SIZE }, true);
Session *found = lookup_session_slot(storage, (CWEB_String) { sess, SESS_TOKEN_SIZE }, true);
if (found == NULL) return -1;
found->user = user;
memcpy(found->sess, sess, SESS_TOKEN_SIZE);
memcpy(found->csrf, csrf, CSRF_TOKEN_SIZE);
*psess = (HTTP_String) { found->sess, SESS_TOKEN_SIZE };
*pcsrf = (HTTP_String) { found->csrf, CSRF_TOKEN_SIZE };
*psess = (CWEB_String) { found->sess, SESS_TOKEN_SIZE };
*pcsrf = (CWEB_String) { found->csrf, CSRF_TOKEN_SIZE };
storage->count++;
return 0;
}
static int delete_session(SessionStorage *storage, HTTP_String sess)
static int delete_session(SessionStorage *storage, CWEB_String sess)
{
char raw_sess[SESS_RAW_TOKEN_SIZE];
if (sess.len != SESS_TOKEN_SIZE || pack_token(sess.ptr, sess.len, raw_sess, (int) sizeof(raw_sess)) < 0)
@@ -366,13 +386,13 @@ static int delete_session(SessionStorage *storage, HTTP_String sess)
return 0;
}
static int find_session(SessionStorage *storage, HTTP_String sess, HTTP_String *pcsrf, int *puser)
static int find_session(SessionStorage *storage, CWEB_String sess, CWEB_String *pcsrf, int *puser)
{
Session *found = lookup_session_slot(storage, sess, false);
if (found == NULL)
return -1;
assert(found->user >= 0);
*pcsrf = (HTTP_String) { found->csrf, CSRF_TOKEN_SIZE };
*pcsrf = (CWEB_String) { found->csrf, CSRF_TOKEN_SIZE };
*puser = found->user;
return 0;
}
@@ -493,7 +513,7 @@ static int sqlite3utils_prepare(SQLiteCache *cache, sqlite3_stmt **pstmt, char *
}
static int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
sqlite3_stmt **pstmt, char *fmt, VArgs args)
sqlite3_stmt **pstmt, char *fmt, CWEB_VArgs args)
{
sqlite3_stmt *stmt;
int ret = sqlite3utils_prepare(cache, &stmt, fmt, strlen(fmt));
@@ -533,7 +553,7 @@ static int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
return SQLITE_OK;
}
int64_t cweb_database_insert_impl(CWEB *cweb, const char *fmt, VArgs args)
int64_t cweb_database_insert_impl(CWEB *cweb, const char *fmt, CWEB_VArgs args)
{
sqlite3_stmt *stmt;
int ret = sqlite3utils_prepare_and_bind_impl(cweb->dbcache, &stmt, fmt, args);
@@ -638,7 +658,7 @@ int cweb_next_query_row_impl(CWEB_QueryResult *res, CWEB_VArgs args)
case CWEB_VARG_TYPE_PSTR:
{
*args.ptr[i].pstr = (HTTP_String) {
*args.ptr[i].pstr = (CWEB_String) {
sqlite3_column_text(res->handle, i),
sqlite3_column_bytes(res->handle, i),
};
@@ -673,7 +693,7 @@ void cweb_global_free(void)
http_global_free();
}
int cweb_init(CWEB *cweb, CWEB_String addr, uint16_t port)
CWEB *web_init(CWEB_String addr, uint16_t port)
{
// If set, allows logins and signups over HTTP, which is highly insecure.
// This allows compiling the application without TLS when developing.
@@ -682,29 +702,38 @@ int cweb_init(CWEB *cweb, CWEB_String addr, uint16_t port)
if (allow_insecure_login)
printf("WARNING: allow_insecure_login is true\n");
CWEB *cweb = malloc(sizeof(CWEB));
if (cweb == NULL)
return -1;
cweb->pool_cap = 1<<20;
cweb->pool = malloc(cweb->pool_cap);
if (cweb->pool == NULL)
if (cweb->pool == NULL) {
free(cweb);
return -1;
}
cweb->tpcache = template_cache_init(4);
if (cweb->tpcache == NULL) {
free(cweb->pool);
free(cweb);
return -1;
}
cweb->session_storage = session_storage_init(1024);
if (cweb->session_storage == NULL) {
template_cache_free(cweb->tcpcache);
template_cache_free(cweb->tpcache);
free(cweb->pool);
free(cweb);
return -1;
}
cweb->server = http_server_init(addr, port);
cweb->server = http_server_init((HTTP_String) { addr.ptr, addr.len }, port);
if (cweb->server == NULL) {
session_storage_free(cweb->session_storage);
template_cache_free(cweb->tcpcache);
template_cache_free(cweb->tpcache);
free(cweb->pool);
free(cweb);
return -1;
}
@@ -725,6 +754,7 @@ void cweb_free(CWEB *cweb)
sqlite_cache_free(cweb->dbcache);
sqlite3_close(cweb->db);
}
free(cweb);
}
void cweb_version(void)
@@ -778,30 +808,31 @@ int cweb_enable_database(CWEB *cweb, CWEB_String file)
return 0;
}
CWEB_Request cweb_wait(CWEB *cweb)
CWEB_Request *cweb_wait(CWEB *cweb)
{
CWEB_Request req;
CWEB_Request *req = &cweb->req;
int ret = http_server_wait(cweb->server, &req.req, &req.builder);
int ret = http_server_wait(cweb->server, &req->req, &req->builder);
if (ret < 0) return -1;
req.arena = (WL_Arena) { cweb->pool, cweb->pool_cap, 0 };
req->arena = (WL_Arena) { cweb->pool, cweb->pool_cap, 0 };
int user_id;
HTTP_String sess;
HTTP_String csrf;
req.just_created_session = false;
req.sess = http_getcookie(req.req, HTTP_STR("sess_token"));
if (find_session(cweb->session_storage, sess, &csrf, &user_id) < 0) {
req.user_id = -1;
req.sess = (HTTP_String) { NULL, 0 };
req.csrf = (HTTP_String) { NULL, 0 };
req->just_created_session = false;
req->sess = http_get_cookie(req->req, HTTP_STR("sess_token"));
if (find_session(cweb->session_storage, req->sess, &req->csrf, &req->user_id) < 0) {
req->user_id = -1;
req->sess = (CWEB_String) { NULL, 0 };
req->csrf = (CWEB_String) { NULL, 0 };
}
return req;
}
bool cweb_match_endpoint(CWEB_Request *req, CWEB_String str)
{
return http_streq(req->req->url.path, (HTTP_String) { str.ptr, str.len });
}
CWEB_String cweb_get_param_s(CWEB_Request *req, CWEB_String name)
{
HTTP_String res = http_get_param(req->req->body,
+4 -24
View File
@@ -1,11 +1,6 @@
#include <stdint.h>
#include <stdbool.h>
#ifndef CWEB_AMALGAMATION
#include "wl.h"
#include "chttp.h"
#endif
#define CWEB_STR(X) (CWEB_String) { (X), (int) sizeof(X)-1 }
typedef struct {
@@ -195,33 +190,17 @@ typedef struct {
#define CWEB_VARGS(...) CWEB_DISPATCH__(__VA_ARGS__, CWEB_VARGS_5, CWEB_VARGS_4, CWEB_VARGS_3, CWEB_VARGS_2, CWEB_VARGS_1)(__VA_ARGS__)
typedef struct CWEB CWEB;
typedef struct {
CWEB *cweb;
WL_Arena arena;
HTTP_Request *req;
HTTP_ResponseBuilder builder;
// Session
bool just_created_session;
int user_id;
CWEB_String sess;
CWEB_String csrf;
} CWEB_Request;
typedef struct CWEB_Request CWEB_Request;
int cweb_global_init(void);
void cweb_global_free(void);
int cweb_init(CWEB *cweb, CWEB_String addr, uint16_t port);
CWEB *cweb_init(CWEB_String addr, uint16_t port);
void cweb_free(CWEB *cweb);
int cweb_enable_database(CWEB *cweb, CWEB_String file);
CWEB_Request cweb_wait(CWEB *cweb);
CWEB_Request *cweb_wait(CWEB *cweb);
//////////////////////////////////////
// Session
@@ -233,6 +212,7 @@ int cweb_set_session_user_id(CWEB_Request *req, int user_id);
//////////////////////////////////////
// Request
bool cweb_match_endpoint(CWEB_Request *req, CWEB_String str);
CWEB_String cweb_get_param_s(CWEB_Request *req, CWEB_String name);
int cweb_get_param_i(CWEB_Request *req, CWEB_String name);