Fix more errors
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user