From 1d8e7d8ef36de7bae2c62f63bec0e9914f18e77d Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Tue, 17 Mar 2020 23:27:44 +0300 Subject: [magi] --- Makefile | 57 ++++++++++++++++++++++++++----------------------- examples/fastcgi.c | 34 ----------------------------- examples/fastcgi.todo | 34 +++++++++++++++++++++++++++++ include/magi/response.h | 5 ++++- src/cgi.c | 17 ++++++++++++--- src/cookies.c | 4 ++-- src/multipart.c | 4 ++-- src/response.c | 53 +++++++++++++++++++++++++++++++++++++++------ 8 files changed, 132 insertions(+), 76 deletions(-) delete mode 100644 examples/fastcgi.c create mode 100644 examples/fastcgi.todo diff --git a/Makefile b/Makefile index fd2fc64..df3856d 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,13 @@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Compilation Options -# Debug mode (allowing to debug the library via gdb): -# DEBUG = yes -# Specify directory to store object files: -OBJ_DIR = build +# Debug mode [yes/no] (allowing to debug the library via gdb): +DEBUG ?= no +# Specify build directory: +BUILD ?= build # Optional modules (remove unwanted ones): -MODULES = cgi fastcgi loadfile urlenc -# Examples to build with 'examples' target: -EXAMPLES = append cookie echo upload +MODULES ?= cgi fastcgi loadfile urlenc # Specify your favourite C compiler here: -CC = gcc +CC ?= gcc # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -37,10 +35,12 @@ INNER_H = $(wildcard $(SRC_DIR)/*.h) INNER_C = $(INNER_H:.h=.c) SRC = $(INTER_C) $(INNER_C) NAMES = $(notdir $(SRC:.c=)) -OBJ = $(foreach name,$(NAMES),$(OBJ_DIR)/$(name).o) +OBJ = $(foreach name,$(NAMES),$(BUILD)/$(SRC_DIR)/$(name).o) EXDIR = examples -EXSRC = $(foreach ex,$(EXAMPLES),$(EXDIR)/$(ex).c) +EXSRC = $(wildcard $(EXDIR)/*.c) +EXNAMES = $(notdir $(EXSRC:.c=)) +EXAMPLES = $(foreach ex,$(EXNAMES),$(BUILD)/$(EXDIR)/$(ex)) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -48,42 +48,45 @@ EXSRC = $(foreach ex,$(EXAMPLES),$(EXDIR)/$(ex).c) .PHONY: default clean examples # 'make' produces library by default: -default: $(OBJ_DIR) $(LIB) +default: $(BUILD)/$(LIB) + +examples: $(EXAMPLES) # Cleaning means removing everything automatically produced: clean: - rm -rf $(OBJ_DIR) $(LIB) $(EXAMPLES) deps.mk - -examples: default $(EXAMPLES) + rm -rf $(BUILD) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Compilation # Compile object files from corresponding source and header: -$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c +$(BUILD)/$(SRC_DIR)/%.o: $(SRC_DIR)/%.c $(CC) $(CFLAGS) -I $(INC_DIR) -c $< -o $@ # Packing object files into library: -$(LIB): $(OBJ) +$(BUILD)/$(LIB): $(OBJ) ar rcs $@ $^ -# Making directory for object files: -$(OBJ_DIR): - mkdir $@ - # Compile executables from corresponding sources and library: -%: $(EXDIR)/%.c - $(CC) $(CFLAGS) -I include $< -L. -lmagi -o $@ +$(BUILD)/$(EXDIR)/%: $(EXDIR)/%.c $(BUILD)/$(LIB) + $(CC) $(CFLAGS) -I include $< -L$(BUILD) -lmagi -o $@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Dependencies -deps.mk: $(SRC) - echo '' > deps.mk - for t in $(NAMES); do \ - $(CC) -I $(INC_DIR) -MT $(OBJ_DIR)/$${t}.o -MM $(SRC_DIR)/$${t}.c >> $@; \ +$(BUILD)/deps.mk: $(SRC) $(EXSRC) + mkdir $(BUILD) $(BUILD)/$(SRC_DIR) $(BUILD)/$(EXDIR); echo '' > $@ + for t in $(NAMES); do \ + $(CC) -I $(INC_DIR) \ + -MT $(BUILD)/$(SRC_DIR)/$${t}.o \ + -MM $(SRC_DIR)/$${t}.c >> $@; \ + done + for t in $(EXNAMES); do \ + $(CC) -I include \ + -MT $(BUILD)/$(EXDIR)/$${t}.o \ + -MM $(EXDIR)/$${t}.c >> $@; \ done ifneq (clean, $(MAKECMDGOALS)) --include deps.mk +-include $(BUILD)/deps.mk endif diff --git a/examples/fastcgi.c b/examples/fastcgi.c deleted file mode 100644 index 5d3c4b1..0000000 --- a/examples/fastcgi.c +++ /dev/null @@ -1,34 +0,0 @@ -#include - - -void response(magi_request *r) -{ - magi_response(r, - "" - "" - "Fast CGI" - "Hi!" - ""); -} - -int main(int argc, char const *argv[]) -{ - magi_session session; - magi_request request; - magi_request_init(&request); - magi_session_init(&session); - magi_session_inet(&session, "localhost", "9973"); - magi_session_unix(&session, "unix.sock"); - while (magi_fastcgi(&session, &request)) { - if (request.error) { - magi_response_error(&request); - } else { - response(&request); - } - magi_request_free(&request); - } - magi_request_free(&request); - magi_session_free(&session); - return 0; -} diff --git a/examples/fastcgi.todo b/examples/fastcgi.todo new file mode 100644 index 0000000..5d3c4b1 --- /dev/null +++ b/examples/fastcgi.todo @@ -0,0 +1,34 @@ +#include + + +void response(magi_request *r) +{ + magi_response(r, + "" + "" + "Fast CGI" + "Hi!" + ""); +} + +int main(int argc, char const *argv[]) +{ + magi_session session; + magi_request request; + magi_request_init(&request); + magi_session_init(&session); + magi_session_inet(&session, "localhost", "9973"); + magi_session_unix(&session, "unix.sock"); + while (magi_fastcgi(&session, &request)) { + if (request.error) { + magi_response_error(&request); + } else { + response(&request); + } + magi_request_free(&request); + } + magi_request_free(&request); + magi_session_free(&session); + return 0; +} diff --git a/include/magi/response.h b/include/magi/response.h index 756e2bd..4b71ef5 100644 --- a/include/magi/response.h +++ b/include/magi/response.h @@ -12,12 +12,14 @@ */ #include "request.h" #include +#include -/* * * TODO * * */ +/* * * TODO: Comments * * */ typedef void (*magi_response_method_head)(void *ud, magi_param *header); typedef void (*magi_response_method_start_body)(void *ud); typedef void (*magi_response_method_body)(void *ud, const char *data, int len); +typedef void (*magi_response_method_fmt)(void *ud, const char *f, va_list a); typedef void (*magi_response_method_file)(void *ud, FILE *file); typedef void (*magi_response_method_close)(void *ud); @@ -25,6 +27,7 @@ typedef struct magi_response_methods { magi_response_method_head head; magi_response_method_start_body start_body; magi_response_method_body body; + magi_response_method_fmt format; magi_response_method_file file; magi_response_method_close close; } magi_response_methods; diff --git a/src/cgi.c b/src/cgi.c index 810d85e..0fd258e 100644 --- a/src/cgi.c +++ b/src/cgi.c @@ -85,7 +85,7 @@ static void cgi_cookies(magi_request *r) r->cookies = 0; return; } - if (strlen(env) > r->limits.cookies && r->limits.cookies) { + if ((int)strlen(env) > r->limits.cookies && r->limits.cookies) { r->error = magi_error_limit; return; } @@ -127,7 +127,7 @@ static void cgi_input_post(magi_error *e, char **input, int max) return; } *input = magi_str_create(input_len); - if (fread(*input, 1, input_len, stdin) != input_len) { + if ((int)fread(*input, 1, input_len, stdin) != input_len) { *e = magi_error_length; return; } @@ -154,6 +154,7 @@ static int next() static void mhead(void *any, magi_param *header) { + (void)any; fputs(header->name, stdout); fputs(": ", stdout); fputs(header->data, stdout); @@ -162,16 +163,25 @@ static void mhead(void *any, magi_param *header) static void mstart_body(void *any) { + (void)any; fputs("\r\n", stdout); } static void mbody(void *any, const char *data, int len) { + (void)any; fwrite(data, 1, len, stdout); } +static void mformat(void *any, const char *format, va_list args) +{ + (void)any; + vprintf(format, args); +} + static void mfile(void *any, FILE *file) { + (void)any; while (!feof(file)) { char buf[64]; int len = fread(buf, 1, 64, file); @@ -179,7 +189,7 @@ static void mfile(void *any, FILE *file) } } -static void mclose(void *any) {} +static void mclose(void *any) { (void)any; } static void setup_response(magi_request *r) { @@ -187,6 +197,7 @@ static void setup_response(magi_request *r) mhead, mstart_body, mbody, + mformat, mfile, mclose }; diff --git a/src/cookies.c b/src/cookies.c index 7e8248b..f5b030e 100644 --- a/src/cookies.c +++ b/src/cookies.c @@ -124,7 +124,7 @@ static st parse_name(automata *a, char c) return state; } -static st parse_post_name(automata *a, char c) +static st parse_post_name(char c) { st state; if (c == '=') { @@ -239,7 +239,7 @@ void magi_parse_cookies(magi_request *request, const char *data) switch (state) { case st_pre_name: state = parse_pre_name(&a, *data); break; case st_name: state = parse_name(&a, *data); break; - case st_post_name: state = parse_post_name(&a, *data); break; + case st_post_name: state = parse_post_name(*data); break; case st_pre_data: state = parse_pre_data(&a, *data); break; case st_data: state = parse_data(&a, *data); break; case st_post_data: state = parse_post_data(&a, *data); break; diff --git a/src/multipart.c b/src/multipart.c index 72fe607..ef988b1 100644 --- a/src/multipart.c +++ b/src/multipart.c @@ -383,7 +383,7 @@ static st parse_data(automata *a, char c) return data_add(a, c); } -static st parse_end(automata *a, char c) { return st_end; } +static st parse_end() { return st_end; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * @@ -405,7 +405,7 @@ static void run_automata(automata *a, case st_pname_end: state = parse_pname_end(a, c); break; case st_pdata: state = parse_pdata(a, c); break; case st_data: state = parse_data(a, c); break; - case st_end: state = parse_end(a, c); break; + case st_end: state = parse_end(); break; default: break; } c = next(next_userdata); diff --git a/src/response.c b/src/response.c index 400080a..dc36bb0 100644 --- a/src/response.c +++ b/src/response.c @@ -29,7 +29,7 @@ void magi_response_cookie(magi_request *r, const char *name, const char *data) magi_param addon; int nlen; int dlen; - if (r->response->head_done) { + if (r->response->head_done || !name || !data) { return; } nlen = strlen(name); @@ -45,22 +45,59 @@ void magi_response_cookie(magi_request *r, const char *name, const char *data) void magi_response_cookie_complex(magi_request *r, magi_cookie *c) { magi_param addon; - if (r->response->head_done) { + char *pointer; + int nlen, dlen, dsize, psize, msize; + const int cdsize = 9; + const int cpsize = 7; + const int cmsize = 10; + if (r->response->head_done || !c->name) { return; } + nlen = strlen(c->name); + dlen = c->data ? strlen(c->data) : 0; + dsize = c->domain ? strlen(c->domain) + cdsize : 0; + psize = c->path ? strlen(c->path) + cpsize : 0; + msize = c->max_age ? strlen(c->max_age) + cmsize : 0; addon.name = magi_str_create_copy("Set-Cookie", 10); - /* TODO */ + addon.data = magi_str_create(nlen + dlen + dsize + psize + msize + 1); + pointer = addon.data; + memcpy(pointer, c->name, nlen); + pointer += nlen; + *pointer = '='; + ++pointer; + if (dlen) { + memcpy(pointer, c->data, dlen); + pointer += dlen; + } + if (dsize) { + memcpy(pointer, "; Domain=", cdsize); + memcpy(pointer + cdsize, c->domain, dsize - cdsize); + pointer += dsize; + } + if (psize) { + memcpy(pointer, "; Path=", cpsize); + memcpy(pointer + cpsize, c->path, psize - cpsize); + pointer += psize; + } + if (msize) { + memcpy(pointer, "; Max-Age=", cmsize); + memcpy(pointer + cmsize, c->max_age, msize - cmsize); + } magi_params_add(&r->response->head_general, &addon); } void magi_response_cookie_discard(magi_request *r, const char *name) { magi_param addon; - if (r->response->head_done) { + int len; + if (r->response->head_done || !name) { return; } + len = strlen(name); addon.name = magi_str_create_copy("Set-Cookie", 10); - /* TODO */ + addon.data = malloc(len + 13); + memcpy(addon.data, name, len); + memcpy(addon.data + len, "=; Max-Age=1", 13); magi_params_add(&r->response->head_general, &addon); } @@ -136,8 +173,11 @@ void magi_response(magi_request *r, const char *addon) void magi_response_format(magi_request *r, const char *format, ...) { + va_list args; magi_response_head(r); - /* TODO */ + va_start(args, format); + r->response->methods->format(r->response->userdata, format, args); + va_end(args); } void magi_response_file(magi_request *r, FILE *file) @@ -149,7 +189,6 @@ void magi_response_file(magi_request *r, FILE *file) void magi_response_error(magi_request *r) { - /* TODO */ magi_response_status(r, 400, "Bad Request"); magi_response(r, "