summaryrefslogtreecommitdiff
path: root/xs_httpd.h
diff options
context:
space:
mode:
authorGravatar default2023-09-25 18:25:09 +0200
committerGravatar default2023-09-25 18:25:09 +0200
commitc314e995a4acd2982806fd53565367abe8b6f2b8 (patch)
treed1ea6795ce91bd0cb8ca5867a1b478e0cae882b6 /xs_httpd.h
parentBackport from xs. (diff)
downloadsnac2-c314e995a4acd2982806fd53565367abe8b6f2b8.tar.gz
snac2-c314e995a4acd2982806fd53565367abe8b6f2b8.tar.xz
snac2-c314e995a4acd2982806fd53565367abe8b6f2b8.zip
Backport from xs.
Diffstat (limited to 'xs_httpd.h')
-rw-r--r--xs_httpd.h190
1 files changed, 1 insertions, 189 deletions
diff --git a/xs_httpd.h b/xs_httpd.h
index 0e60b64..644b3ed 100644
--- a/xs_httpd.h
+++ b/xs_httpd.h
@@ -4,200 +4,12 @@
4 4
5#define _XS_HTTPD_H 5#define _XS_HTTPD_H
6 6
7xs_str *xs_url_dec(const char *str);
8xs_dict *xs_url_vars(const char *str);
9xs_dict *xs_httpd_request(FILE *f, xs_str **payload, int *p_size); 7xs_dict *xs_httpd_request(FILE *f, xs_str **payload, int *p_size);
10void xs_httpd_response(FILE *f, int status, xs_dict *headers, xs_str *body, int b_size); 8void xs_httpd_response(FILE *f, int status, xs_dict *headers, xs_str *body, int b_size);
11 9
12 10
13#ifdef XS_IMPLEMENTATION 11#ifdef XS_IMPLEMENTATION
14 12
15xs_str *xs_url_dec(const char *str)
16/* decodes an URL */
17{
18 xs_str *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
44xs_dict *xs_url_vars(const char *str)
45/* parse url variables */
46{
47 xs_dict *vars;
48
49 vars = xs_dict_new();
50
51 if (str != NULL) {
52 /* split by arguments */
53 xs *args = xs_split(str, "&");
54
55 xs_list *l;
56 xs_val *v;
57
58 l = args;
59 while (xs_list_iter(&l, &v)) {
60 xs *kv = xs_split_n(v, "=", 2);
61
62 if (xs_list_len(kv) == 2) {
63 const char *key = xs_list_get(kv, 0);
64 const char *pv = xs_dict_get(vars, key);
65
66 if (!xs_is_null(pv)) {
67 /* there is a previous value: convert to a list and append */
68 xs *vlist = NULL;
69 if (xs_type(pv) == XSTYPE_LIST)
70 vlist = xs_dup(pv);
71 else {
72 vlist = xs_list_new();
73 vlist = xs_list_append(vlist, pv);
74 }
75
76 vlist = xs_list_append(vlist, xs_list_get(kv, 1));
77 vars = xs_dict_set(vars, key, vlist);
78 }
79 else {
80 /* ends with []? force to always be a list */
81 if (xs_endswith(key, "[]")) {
82 xs *vlist = xs_list_new();
83 vlist = xs_list_append(vlist, xs_list_get(kv, 1));
84 vars = xs_dict_append(vars, key, vlist);
85 }
86 else
87 vars = xs_dict_append(vars, key, xs_list_get(kv, 1));
88 }
89 }
90 }
91 }
92
93 return vars;
94}
95
96
97xs_dict *_xs_multipart_form_data(xs_str *payload, int p_size, char *header)
98/* parses a multipart/form-data payload */
99{
100 xs *boundary = NULL;
101 int offset = 0;
102 int bsz;
103 char *p;
104
105 /* build the boundary string */
106 {
107 xs *l1 = xs_split(header, "=");
108
109 if (xs_list_len(l1) != 2)
110 return NULL;
111
112 boundary = xs_fmt("--%s", xs_list_get(l1, 1));
113 }
114
115 bsz = strlen(boundary);
116
117 xs_dict *p_vars = xs_dict_new();
118
119 /* iterate searching the boundaries */
120 while ((p = xs_memmem(payload + offset, p_size - offset, boundary, bsz)) != NULL) {
121 xs *s1 = NULL;
122 xs *l1 = NULL;
123 char *vn = NULL;
124 char *fn = NULL;
125 char *q;
126 int po, ps;
127
128 /* final boundary? */
129 p += bsz;
130
131 if (p[0] == '-' && p[1] == '-')
132 break;
133
134 /* skip the \r\n */
135 p += 2;
136
137 /* now on a Content-Disposition... line; get it */
138 q = strchr(p, '\r');
139 s1 = xs_realloc(NULL, q - p + 1);
140 memcpy(s1, p, q - p);
141 s1[q - p] = '\0';
142
143 /* move on (over a \r\n) */
144 p = q;
145
146 /* split by " like a primitive man */
147 l1 = xs_split(s1, "\"");
148
149 /* get the variable name */
150 vn = xs_list_get(l1, 1);
151
152 /* is it an attached file? */
153 if (xs_list_len(l1) >= 4 && strcmp(xs_list_get(l1, 2), "; filename=") == 0) {
154 /* get the file name */
155 fn = xs_list_get(l1, 3);
156 }
157
158 /* find the start of the part content */
159 if ((p = xs_memmem(p, p_size - (p - payload), "\r\n\r\n", 4)) == NULL)
160 break;
161
162 p += 4;
163
164 /* find the next boundary */
165 if ((q = xs_memmem(p, p_size - (p - payload), boundary, bsz)) == NULL)
166 break;
167
168 po = p - payload;
169 ps = q - p - 2; /* - 2 because the final \r\n */
170
171 /* is it a filename? */
172 if (fn != NULL) {
173 /* p_var value is a list */
174 xs *l1 = xs_list_new();
175 xs *vpo = xs_number_new(po);
176 xs *vps = xs_number_new(ps);
177
178 l1 = xs_list_append(l1, fn);
179 l1 = xs_list_append(l1, vpo);
180 l1 = xs_list_append(l1, vps);
181
182 p_vars = xs_dict_append(p_vars, vn, l1);
183 }
184 else {
185 /* regular variable; just copy */
186 xs *vc = xs_realloc(NULL, ps + 1);
187 memcpy(vc, payload + po, ps);
188 vc[ps] = '\0';
189
190 p_vars = xs_dict_append(p_vars, vn, vc);
191 }
192
193 /* move on */
194 offset = q - payload;
195 }
196
197 return p_vars;
198}
199
200
201xs_dict *xs_httpd_request(FILE *f, xs_str **payload, int *p_size) 13xs_dict *xs_httpd_request(FILE *f, xs_str **payload, int *p_size)
202/* processes an httpd connection */ 14/* processes an httpd connection */
203{ 15{
@@ -267,7 +79,7 @@ xs_dict *xs_httpd_request(FILE *f, xs_str **payload, int *p_size)
267 } 79 }
268 else 80 else
269 if (*payload && v && xs_startswith(v, "multipart/form-data")) { 81 if (*payload && v && xs_startswith(v, "multipart/form-data")) {
270 p_vars = _xs_multipart_form_data(*payload, *p_size, v); 82 p_vars = xs_multipart_form_data(*payload, *p_size, v);
271 } 83 }
272 else 84 else
273 p_vars = xs_dict_new(); 85 p_vars = xs_dict_new();