summaryrefslogtreecommitdiff
path: root/xs_httpd.h
diff options
context:
space:
mode:
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 @@
1/* copyright (c) 2022 grunfink - MIT license */
2
3#ifndef _XS_HTTPD_H
4
5#define _XS_HTTPD_H
6
7d_char *xs_url_dec(char *str);
8d_char *xs_url_vars(char *str);
9d_char *xs_httpd_request(FILE *f);
10void xs_httpd_response(FILE *f, int status, d_char *headers, char *body, int b_size);
11
12
13#ifdef XS_IMPLEMENTATION
14
15d_char *xs_url_dec(char *str)
16/* decodes an URL */
17{
18 d_char *s = xs_str_new(NULL);
19
20 while (*str) {
21 if (*str == '%') {
22 int i;
23
24 if (sscanf(str + 1, "%02x", &i) == 1) {
25 unsigned char uc = i;
26
27 s = xs_append_m(s, (char *)&uc, 1);
28 str += 2;
29 }
30 }
31 else
32 if (*str == '+')
33 s = xs_append_m(s, " ", 1);
34 else
35 s = xs_append_m(s, str, 1);
36
37 str++;
38 }
39
40 return s;
41}
42
43
44d_char *xs_url_vars(char *str)
45/* parse url variables */
46{
47 d_char *vars;
48
49 vars = xs_dict_new();
50
51 if (str != NULL) {
52 char *v, *l;
53 xs *args;
54
55 /* split by arguments */
56 args = xs_split(str, "&");
57
58 l = args;
59 while (xs_list_iter(&l, &v)) {
60 xs *kv = xs_splitn(v, "=", 2);
61
62 if (xs_list_len(kv) == 2)
63 vars = xs_dict_append(vars,
64 xs_list_get(kv, 0), xs_list_get(kv, 1));
65 }
66 }
67
68 return vars;
69}
70
71
72d_char *xs_httpd_request(FILE *f)
73/* processes an httpd connection */
74{
75 xs *headers = NULL;
76 xs *q_vars = NULL;
77 xs *p_vars = NULL;
78 d_char *req = NULL;
79 xs *l1, *l2;
80 char *v;
81
82 xs_socket_timeout(fileno(f), 2.0, 0.0);
83
84 /* read the first line and split it */
85 l1 = xs_strip(xs_readline(f));
86 l2 = xs_split(l1, " ");
87
88 if (xs_list_len(l2) != 3) {
89 /* error or timeout */
90 return NULL;
91 }
92
93 headers = xs_dict_new();
94
95 headers = xs_dict_append(headers, "method", xs_list_get(l2, 0));
96 headers = xs_dict_append(headers, "proto", xs_list_get(l2, 2));
97
98 {
99 /* split the path with its optional variables */
100 xs *udp = xs_url_dec(xs_list_get(l2, 1));
101 xs *pnv = xs_splitn(udp, "?", 1);
102
103 /* store the path */
104 headers = xs_dict_append(headers, "path", xs_list_get(pnv, 0));
105
106 /* get the variables */
107 q_vars = xs_url_vars(xs_list_get(pnv, 1));
108 }
109
110 /* read the headers */
111 for (;;) {
112 xs *l, *p = NULL;
113
114 l = xs_strip(xs_readline(f));
115
116 /* done with the header? */
117 if (strcmp(l, "") == 0)
118 break;
119
120 /* split header and content */
121 p = xs_splitn(l, ": ", 1);
122
123 if (xs_list_len(p) == 2)
124 headers = xs_dict_append(headers,
125 xs_tolower(xs_list_get(p, 0)), xs_list_get(p, 1));
126 }
127
128 xs_socket_timeout(fileno(f), 5.0, 0.0);
129
130 /* does it have a payload with form urlencoded variables? */
131 v = xs_dict_get(headers, "content-type");
132
133 if (v && strcmp(v, "application/x-www-form-urlencoded") == 0) {
134 if ((v = xs_dict_get(headers, "content-length")) != NULL) {
135 int cl = atoi(v);
136 xs *payload;
137
138 if ((payload = xs_read(f, cl)) != NULL) {
139 xs *upl = xs_url_dec(payload);
140 p_vars = xs_url_vars(upl);
141 }
142 }
143 }
144 else
145 p_vars = xs_dict_new();
146
147 if (errno == 0) {
148 req = xs_dict_new();
149 req = xs_dict_append(req, "headers", headers);
150 req = xs_dict_append(req, "q_vars", q_vars);
151 req = xs_dict_append(req, "p_vars", p_vars);
152 }
153
154 return req;
155}
156
157
158void xs_httpd_response(FILE *f, int status, d_char *headers, char *body, int b_size)
159/* sends an httpd response */
160{
161 xs *proto;
162 char *p, *k, *v;
163
164 proto = xs_fmt("HTTP/1.1 %d", status);
165 fprintf(f, "%s\r\n", proto);
166
167 p = headers;
168 while (xs_dict_iter(&p, &k, &v)) {
169 fprintf(f, "%s: %s\r\n", k, v);
170 }
171
172 if (b_size != 0)
173 fprintf(f, "content-length: %d\r\n", b_size);
174
175 fprintf(f, "\r\n");
176
177 if (body != NULL && b_size != 0)
178 fwrite(body, b_size, 1, f);
179}
180
181
182#endif /* XS_IMPLEMENTATION */
183
184#endif /* XS_HTTPD_H */