summaryrefslogtreecommitdiff
path: root/xs_httpd.h
diff options
context:
space:
mode:
authordefault <nobody@localhost>2022-09-19 20:41:11 +0200
committerdefault <nobody@localhost>2022-09-19 20:41:11 +0200
commit67288a763b8bceadbb128d2cf5bdc431ba8a686f (patch)
tree0a0bc1922016bbd3d3cd2ec3c80a033970280a9f /xs_httpd.h
parentef03035ef0af5a68ba7e03ae834a43db5dd3a8e3 (diff)
Imported xs.
Diffstat (limited to 'xs_httpd.h')
-rw-r--r--xs_httpd.h184
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 */