diff options
author | default <nobody@localhost> | 2022-09-19 20:41:11 +0200 |
---|---|---|
committer | default <nobody@localhost> | 2022-09-19 20:41:11 +0200 |
commit | 67288a763b8bceadbb128d2cf5bdc431ba8a686f (patch) | |
tree | 0a0bc1922016bbd3d3cd2ec3c80a033970280a9f /xs_httpd.h | |
parent | ef03035ef0af5a68ba7e03ae834a43db5dd3a8e3 (diff) |
Imported xs.
Diffstat (limited to 'xs_httpd.h')
-rw-r--r-- | xs_httpd.h | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/xs_httpd.h b/xs_httpd.h new file mode 100644 index 0000000..3d520ec --- /dev/null +++ b/xs_httpd.h @@ -0,0 +1,184 @@ +/* copyright (c) 2022 grunfink - MIT license */ + +#ifndef _XS_HTTPD_H + +#define _XS_HTTPD_H + +d_char *xs_url_dec(char *str); +d_char *xs_url_vars(char *str); +d_char *xs_httpd_request(FILE *f); +void xs_httpd_response(FILE *f, int status, d_char *headers, char *body, int b_size); + + +#ifdef XS_IMPLEMENTATION + +d_char *xs_url_dec(char *str) +/* decodes an URL */ +{ + d_char *s = xs_str_new(NULL); + + while (*str) { + if (*str == '%') { + int i; + + if (sscanf(str + 1, "%02x", &i) == 1) { + unsigned char uc = i; + + s = xs_append_m(s, (char *)&uc, 1); + str += 2; + } + } + else + if (*str == '+') + s = xs_append_m(s, " ", 1); + else + s = xs_append_m(s, str, 1); + + str++; + } + + return s; +} + + +d_char *xs_url_vars(char *str) +/* parse url variables */ +{ + d_char *vars; + + vars = xs_dict_new(); + + if (str != NULL) { + char *v, *l; + xs *args; + + /* split by arguments */ + args = xs_split(str, "&"); + + l = args; + while (xs_list_iter(&l, &v)) { + xs *kv = xs_splitn(v, "=", 2); + + if (xs_list_len(kv) == 2) + vars = xs_dict_append(vars, + xs_list_get(kv, 0), xs_list_get(kv, 1)); + } + } + + return vars; +} + + +d_char *xs_httpd_request(FILE *f) +/* processes an httpd connection */ +{ + xs *headers = NULL; + xs *q_vars = NULL; + xs *p_vars = NULL; + d_char *req = NULL; + xs *l1, *l2; + char *v; + + xs_socket_timeout(fileno(f), 2.0, 0.0); + + /* read the first line and split it */ + l1 = xs_strip(xs_readline(f)); + l2 = xs_split(l1, " "); + + if (xs_list_len(l2) != 3) { + /* error or timeout */ + return NULL; + } + + headers = xs_dict_new(); + + headers = xs_dict_append(headers, "method", xs_list_get(l2, 0)); + headers = xs_dict_append(headers, "proto", xs_list_get(l2, 2)); + + { + /* split the path with its optional variables */ + xs *udp = xs_url_dec(xs_list_get(l2, 1)); + xs *pnv = xs_splitn(udp, "?", 1); + + /* store the path */ + headers = xs_dict_append(headers, "path", xs_list_get(pnv, 0)); + + /* get the variables */ + q_vars = xs_url_vars(xs_list_get(pnv, 1)); + } + + /* read the headers */ + for (;;) { + xs *l, *p = NULL; + + l = xs_strip(xs_readline(f)); + + /* done with the header? */ + if (strcmp(l, "") == 0) + break; + + /* split header and content */ + p = xs_splitn(l, ": ", 1); + + if (xs_list_len(p) == 2) + headers = xs_dict_append(headers, + xs_tolower(xs_list_get(p, 0)), xs_list_get(p, 1)); + } + + xs_socket_timeout(fileno(f), 5.0, 0.0); + + /* does it have a payload with form urlencoded variables? */ + v = xs_dict_get(headers, "content-type"); + + if (v && strcmp(v, "application/x-www-form-urlencoded") == 0) { + if ((v = xs_dict_get(headers, "content-length")) != NULL) { + int cl = atoi(v); + xs *payload; + + if ((payload = xs_read(f, cl)) != NULL) { + xs *upl = xs_url_dec(payload); + p_vars = xs_url_vars(upl); + } + } + } + else + p_vars = xs_dict_new(); + + if (errno == 0) { + req = xs_dict_new(); + req = xs_dict_append(req, "headers", headers); + req = xs_dict_append(req, "q_vars", q_vars); + req = xs_dict_append(req, "p_vars", p_vars); + } + + return req; +} + + +void xs_httpd_response(FILE *f, int status, d_char *headers, char *body, int b_size) +/* sends an httpd response */ +{ + xs *proto; + char *p, *k, *v; + + proto = xs_fmt("HTTP/1.1 %d", status); + fprintf(f, "%s\r\n", proto); + + p = headers; + while (xs_dict_iter(&p, &k, &v)) { + fprintf(f, "%s: %s\r\n", k, v); + } + + if (b_size != 0) + fprintf(f, "content-length: %d\r\n", b_size); + + fprintf(f, "\r\n"); + + if (body != NULL && b_size != 0) + fwrite(body, b_size, 1, f); +} + + +#endif /* XS_IMPLEMENTATION */ + +#endif /* XS_HTTPD_H */ |