xref: /aosp_15_r20/external/libwebsockets/lib/roles/http/server/lws-spa.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * libwebsockets - small server side websockets and web server implementation
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker  *
6*1c60b9acSAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*1c60b9acSAndroid Build Coastguard Worker  * of this software and associated documentation files (the "Software"), to
8*1c60b9acSAndroid Build Coastguard Worker  * deal in the Software without restriction, including without limitation the
9*1c60b9acSAndroid Build Coastguard Worker  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10*1c60b9acSAndroid Build Coastguard Worker  * sell copies of the Software, and to permit persons to whom the Software is
11*1c60b9acSAndroid Build Coastguard Worker  * furnished to do so, subject to the following conditions:
12*1c60b9acSAndroid Build Coastguard Worker  *
13*1c60b9acSAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be included in
14*1c60b9acSAndroid Build Coastguard Worker  * all copies or substantial portions of the Software.
15*1c60b9acSAndroid Build Coastguard Worker  *
16*1c60b9acSAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*1c60b9acSAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*1c60b9acSAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*1c60b9acSAndroid Build Coastguard Worker  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*1c60b9acSAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21*1c60b9acSAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22*1c60b9acSAndroid Build Coastguard Worker  * IN THE SOFTWARE.
23*1c60b9acSAndroid Build Coastguard Worker  */
24*1c60b9acSAndroid Build Coastguard Worker 
25*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-core.h"
26*1c60b9acSAndroid Build Coastguard Worker 
27*1c60b9acSAndroid Build Coastguard Worker #define LWS_MAX_ELEM_NAME 32
28*1c60b9acSAndroid Build Coastguard Worker 
29*1c60b9acSAndroid Build Coastguard Worker enum urldecode_stateful {
30*1c60b9acSAndroid Build Coastguard Worker 	US_NAME,
31*1c60b9acSAndroid Build Coastguard Worker 	US_IDLE,
32*1c60b9acSAndroid Build Coastguard Worker 	US_PC1,
33*1c60b9acSAndroid Build Coastguard Worker 	US_PC2,
34*1c60b9acSAndroid Build Coastguard Worker 
35*1c60b9acSAndroid Build Coastguard Worker 	MT_LOOK_BOUND_IN,
36*1c60b9acSAndroid Build Coastguard Worker 	MT_HNAME,
37*1c60b9acSAndroid Build Coastguard Worker 	MT_DISP,
38*1c60b9acSAndroid Build Coastguard Worker 	MT_TYPE,
39*1c60b9acSAndroid Build Coastguard Worker 	MT_IGNORE1,
40*1c60b9acSAndroid Build Coastguard Worker 	MT_IGNORE2,
41*1c60b9acSAndroid Build Coastguard Worker 	MT_IGNORE3,
42*1c60b9acSAndroid Build Coastguard Worker 	MT_COMPLETED,
43*1c60b9acSAndroid Build Coastguard Worker };
44*1c60b9acSAndroid Build Coastguard Worker 
45*1c60b9acSAndroid Build Coastguard Worker static struct mp_hdr {
46*1c60b9acSAndroid Build Coastguard Worker 	const char * const	hdr;
47*1c60b9acSAndroid Build Coastguard Worker 	uint8_t			hdr_len;
48*1c60b9acSAndroid Build Coastguard Worker } mp_hdrs[] = {
49*1c60b9acSAndroid Build Coastguard Worker 	{ "content-disposition: ", 21 },
50*1c60b9acSAndroid Build Coastguard Worker 	{ "content-type: ", 14 },
51*1c60b9acSAndroid Build Coastguard Worker 	{ "\x0d\x0a", 2 }
52*1c60b9acSAndroid Build Coastguard Worker };
53*1c60b9acSAndroid Build Coastguard Worker 
54*1c60b9acSAndroid Build Coastguard Worker struct lws_spa;
55*1c60b9acSAndroid Build Coastguard Worker 
56*1c60b9acSAndroid Build Coastguard Worker typedef int (*lws_urldecode_stateful_cb)(struct lws_spa *spa,
57*1c60b9acSAndroid Build Coastguard Worker 		const char *name, char **buf, int len, int final);
58*1c60b9acSAndroid Build Coastguard Worker 
59*1c60b9acSAndroid Build Coastguard Worker struct lws_urldecode_stateful {
60*1c60b9acSAndroid Build Coastguard Worker 	char *out;
61*1c60b9acSAndroid Build Coastguard Worker 	struct lws_spa *data;
62*1c60b9acSAndroid Build Coastguard Worker 	struct lws *wsi;
63*1c60b9acSAndroid Build Coastguard Worker 	char name[LWS_MAX_ELEM_NAME];
64*1c60b9acSAndroid Build Coastguard Worker 	char temp[LWS_MAX_ELEM_NAME];
65*1c60b9acSAndroid Build Coastguard Worker 	char content_type[32];
66*1c60b9acSAndroid Build Coastguard Worker 	char content_disp[32];
67*1c60b9acSAndroid Build Coastguard Worker 	char content_disp_filename[256];
68*1c60b9acSAndroid Build Coastguard Worker 	char mime_boundary[128];
69*1c60b9acSAndroid Build Coastguard Worker 	int out_len;
70*1c60b9acSAndroid Build Coastguard Worker 	int pos;
71*1c60b9acSAndroid Build Coastguard Worker 	int hdr_idx;
72*1c60b9acSAndroid Build Coastguard Worker 	int mp;
73*1c60b9acSAndroid Build Coastguard Worker 	int sum;
74*1c60b9acSAndroid Build Coastguard Worker 
75*1c60b9acSAndroid Build Coastguard Worker 	uint8_t matchable;
76*1c60b9acSAndroid Build Coastguard Worker 
77*1c60b9acSAndroid Build Coastguard Worker 	uint8_t multipart_form_data:1;
78*1c60b9acSAndroid Build Coastguard Worker 	uint8_t inside_quote:1;
79*1c60b9acSAndroid Build Coastguard Worker 	uint8_t subname:1;
80*1c60b9acSAndroid Build Coastguard Worker 	uint8_t boundary_real_crlf:1;
81*1c60b9acSAndroid Build Coastguard Worker 
82*1c60b9acSAndroid Build Coastguard Worker 	enum urldecode_stateful state;
83*1c60b9acSAndroid Build Coastguard Worker 
84*1c60b9acSAndroid Build Coastguard Worker 	lws_urldecode_stateful_cb output;
85*1c60b9acSAndroid Build Coastguard Worker };
86*1c60b9acSAndroid Build Coastguard Worker 
87*1c60b9acSAndroid Build Coastguard Worker struct lws_spa {
88*1c60b9acSAndroid Build Coastguard Worker 	struct lws_urldecode_stateful *s;
89*1c60b9acSAndroid Build Coastguard Worker 	lws_spa_create_info_t i;
90*1c60b9acSAndroid Build Coastguard Worker 	int *param_length;
91*1c60b9acSAndroid Build Coastguard Worker 	char finalized;
92*1c60b9acSAndroid Build Coastguard Worker 	char **params;
93*1c60b9acSAndroid Build Coastguard Worker 	char *storage;
94*1c60b9acSAndroid Build Coastguard Worker 	char *end;
95*1c60b9acSAndroid Build Coastguard Worker };
96*1c60b9acSAndroid Build Coastguard Worker 
97*1c60b9acSAndroid Build Coastguard Worker static struct lws_urldecode_stateful *
lws_urldecode_s_create(struct lws_spa * spa,struct lws * wsi,char * out,int out_len,lws_urldecode_stateful_cb output)98*1c60b9acSAndroid Build Coastguard Worker lws_urldecode_s_create(struct lws_spa *spa, struct lws *wsi, char *out,
99*1c60b9acSAndroid Build Coastguard Worker 		       int out_len, lws_urldecode_stateful_cb output)
100*1c60b9acSAndroid Build Coastguard Worker {
101*1c60b9acSAndroid Build Coastguard Worker 	struct lws_urldecode_stateful *s;
102*1c60b9acSAndroid Build Coastguard Worker 	char buf[205], *p;
103*1c60b9acSAndroid Build Coastguard Worker 	int m = 0;
104*1c60b9acSAndroid Build Coastguard Worker 
105*1c60b9acSAndroid Build Coastguard Worker 	if (spa->i.ac)
106*1c60b9acSAndroid Build Coastguard Worker 		s = lwsac_use_zero(spa->i.ac, sizeof(*s), spa->i.ac_chunk_size);
107*1c60b9acSAndroid Build Coastguard Worker 	else
108*1c60b9acSAndroid Build Coastguard Worker 		s = lws_zalloc(sizeof(*s), "stateful urldecode");
109*1c60b9acSAndroid Build Coastguard Worker 
110*1c60b9acSAndroid Build Coastguard Worker 	if (!s)
111*1c60b9acSAndroid Build Coastguard Worker 		return NULL;
112*1c60b9acSAndroid Build Coastguard Worker 
113*1c60b9acSAndroid Build Coastguard Worker 	s->out = out;
114*1c60b9acSAndroid Build Coastguard Worker 	s->out_len  = out_len;
115*1c60b9acSAndroid Build Coastguard Worker 	s->output = output;
116*1c60b9acSAndroid Build Coastguard Worker 	s->pos = 0;
117*1c60b9acSAndroid Build Coastguard Worker 	s->sum = 0;
118*1c60b9acSAndroid Build Coastguard Worker 	s->mp = 0;
119*1c60b9acSAndroid Build Coastguard Worker 	s->state = US_NAME;
120*1c60b9acSAndroid Build Coastguard Worker 	s->name[0] = '\0';
121*1c60b9acSAndroid Build Coastguard Worker 	s->data = spa;
122*1c60b9acSAndroid Build Coastguard Worker 	s->wsi = wsi;
123*1c60b9acSAndroid Build Coastguard Worker 
124*1c60b9acSAndroid Build Coastguard Worker 	if (lws_hdr_copy(wsi, buf, sizeof(buf),
125*1c60b9acSAndroid Build Coastguard Worker 			 WSI_TOKEN_HTTP_CONTENT_TYPE) > 0) {
126*1c60b9acSAndroid Build Coastguard Worker 	/* multipart/form-data;
127*1c60b9acSAndroid Build Coastguard Worker 	 * boundary=----WebKitFormBoundarycc7YgAPEIHvgE9Bf */
128*1c60b9acSAndroid Build Coastguard Worker 
129*1c60b9acSAndroid Build Coastguard Worker 		if (!strncmp(buf, "multipart/form-data", 19) ||
130*1c60b9acSAndroid Build Coastguard Worker 		    !strncmp(buf, "multipart/related", 17)) {
131*1c60b9acSAndroid Build Coastguard Worker 			s->multipart_form_data = 1;
132*1c60b9acSAndroid Build Coastguard Worker 			s->state = MT_LOOK_BOUND_IN;
133*1c60b9acSAndroid Build Coastguard Worker 			s->mp = 2;
134*1c60b9acSAndroid Build Coastguard Worker 			p = strstr(buf, "boundary=");
135*1c60b9acSAndroid Build Coastguard Worker 			if (p) {
136*1c60b9acSAndroid Build Coastguard Worker 				p += 9;
137*1c60b9acSAndroid Build Coastguard Worker 				s->mime_boundary[m++] = '\x0d';
138*1c60b9acSAndroid Build Coastguard Worker 				s->mime_boundary[m++] = '\x0a';
139*1c60b9acSAndroid Build Coastguard Worker 				s->mime_boundary[m++] = '-';
140*1c60b9acSAndroid Build Coastguard Worker 				s->mime_boundary[m++] = '-';
141*1c60b9acSAndroid Build Coastguard Worker 				if (*p == '\"')
142*1c60b9acSAndroid Build Coastguard Worker 					p++;
143*1c60b9acSAndroid Build Coastguard Worker 				while (m < (int)sizeof(s->mime_boundary) - 1 &&
144*1c60b9acSAndroid Build Coastguard Worker 				       *p && *p != ' ' && *p != ';' && *p != '\"')
145*1c60b9acSAndroid Build Coastguard Worker 					s->mime_boundary[m++] = *p++;
146*1c60b9acSAndroid Build Coastguard Worker 				s->mime_boundary[m] = '\0';
147*1c60b9acSAndroid Build Coastguard Worker 
148*1c60b9acSAndroid Build Coastguard Worker 				// lwsl_notice("boundary '%s'\n", s->mime_boundary);
149*1c60b9acSAndroid Build Coastguard Worker 			}
150*1c60b9acSAndroid Build Coastguard Worker 		}
151*1c60b9acSAndroid Build Coastguard Worker 	}
152*1c60b9acSAndroid Build Coastguard Worker 
153*1c60b9acSAndroid Build Coastguard Worker 	return s;
154*1c60b9acSAndroid Build Coastguard Worker }
155*1c60b9acSAndroid Build Coastguard Worker 
156*1c60b9acSAndroid Build Coastguard Worker static int
lws_urldecode_s_process(struct lws_urldecode_stateful * s,const char * in,int len)157*1c60b9acSAndroid Build Coastguard Worker lws_urldecode_s_process(struct lws_urldecode_stateful *s, const char *in,
158*1c60b9acSAndroid Build Coastguard Worker 			int len)
159*1c60b9acSAndroid Build Coastguard Worker {
160*1c60b9acSAndroid Build Coastguard Worker 	int n, hit;
161*1c60b9acSAndroid Build Coastguard Worker 	char c;
162*1c60b9acSAndroid Build Coastguard Worker 
163*1c60b9acSAndroid Build Coastguard Worker 	while (len--) {
164*1c60b9acSAndroid Build Coastguard Worker 		if (s->pos == s->out_len - s->mp - 1) {
165*1c60b9acSAndroid Build Coastguard Worker 			if (s->output(s->data, s->name, &s->out, s->pos,
166*1c60b9acSAndroid Build Coastguard Worker 				      LWS_UFS_CONTENT))
167*1c60b9acSAndroid Build Coastguard Worker 				return -1;
168*1c60b9acSAndroid Build Coastguard Worker 
169*1c60b9acSAndroid Build Coastguard Worker 			s->pos = 0;
170*1c60b9acSAndroid Build Coastguard Worker 		}
171*1c60b9acSAndroid Build Coastguard Worker 
172*1c60b9acSAndroid Build Coastguard Worker 		switch (s->state) {
173*1c60b9acSAndroid Build Coastguard Worker 
174*1c60b9acSAndroid Build Coastguard Worker 		/* states for url arg style */
175*1c60b9acSAndroid Build Coastguard Worker 
176*1c60b9acSAndroid Build Coastguard Worker 		case US_NAME:
177*1c60b9acSAndroid Build Coastguard Worker 			s->inside_quote = 0;
178*1c60b9acSAndroid Build Coastguard Worker 			if (*in == '=') {
179*1c60b9acSAndroid Build Coastguard Worker 				s->name[s->pos] = '\0';
180*1c60b9acSAndroid Build Coastguard Worker 				s->pos = 0;
181*1c60b9acSAndroid Build Coastguard Worker 				s->state = US_IDLE;
182*1c60b9acSAndroid Build Coastguard Worker 				in++;
183*1c60b9acSAndroid Build Coastguard Worker 				continue;
184*1c60b9acSAndroid Build Coastguard Worker 			}
185*1c60b9acSAndroid Build Coastguard Worker 			if (*in == '&') {
186*1c60b9acSAndroid Build Coastguard Worker 				s->name[s->pos] = '\0';
187*1c60b9acSAndroid Build Coastguard Worker 				if (s->output(s->data, s->name, &s->out,
188*1c60b9acSAndroid Build Coastguard Worker 					      s->pos, LWS_UFS_FINAL_CONTENT))
189*1c60b9acSAndroid Build Coastguard Worker 					return -1;
190*1c60b9acSAndroid Build Coastguard Worker 				s->pos = 0;
191*1c60b9acSAndroid Build Coastguard Worker 				s->state = US_IDLE;
192*1c60b9acSAndroid Build Coastguard Worker 				in++;
193*1c60b9acSAndroid Build Coastguard Worker 				continue;
194*1c60b9acSAndroid Build Coastguard Worker 			}
195*1c60b9acSAndroid Build Coastguard Worker 			if (s->pos >= (int)sizeof(s->name) - 1) {
196*1c60b9acSAndroid Build Coastguard Worker 				lwsl_hexdump_notice(s->name, (size_t)s->pos);
197*1c60b9acSAndroid Build Coastguard Worker 				lwsl_notice("Name too long...\n");
198*1c60b9acSAndroid Build Coastguard Worker 				return -1;
199*1c60b9acSAndroid Build Coastguard Worker 			}
200*1c60b9acSAndroid Build Coastguard Worker 			s->name[s->pos++] = *in++;
201*1c60b9acSAndroid Build Coastguard Worker 			break;
202*1c60b9acSAndroid Build Coastguard Worker 		case US_IDLE:
203*1c60b9acSAndroid Build Coastguard Worker 			if (*in == '%') {
204*1c60b9acSAndroid Build Coastguard Worker 				s->state++;
205*1c60b9acSAndroid Build Coastguard Worker 				in++;
206*1c60b9acSAndroid Build Coastguard Worker 				continue;
207*1c60b9acSAndroid Build Coastguard Worker 			}
208*1c60b9acSAndroid Build Coastguard Worker 			if (*in == '&') {
209*1c60b9acSAndroid Build Coastguard Worker 				s->out[s->pos] = '\0';
210*1c60b9acSAndroid Build Coastguard Worker 				if (s->output(s->data, s->name, &s->out,
211*1c60b9acSAndroid Build Coastguard Worker 					      s->pos, LWS_UFS_FINAL_CONTENT))
212*1c60b9acSAndroid Build Coastguard Worker 					return -1;
213*1c60b9acSAndroid Build Coastguard Worker 				s->pos = 0;
214*1c60b9acSAndroid Build Coastguard Worker 				s->state = US_NAME;
215*1c60b9acSAndroid Build Coastguard Worker 				in++;
216*1c60b9acSAndroid Build Coastguard Worker 				continue;
217*1c60b9acSAndroid Build Coastguard Worker 			}
218*1c60b9acSAndroid Build Coastguard Worker 			if (*in == '+') {
219*1c60b9acSAndroid Build Coastguard Worker 				in++;
220*1c60b9acSAndroid Build Coastguard Worker 				s->out[s->pos++] = ' ';
221*1c60b9acSAndroid Build Coastguard Worker 				continue;
222*1c60b9acSAndroid Build Coastguard Worker 			}
223*1c60b9acSAndroid Build Coastguard Worker 			s->out[s->pos++] = *in++;
224*1c60b9acSAndroid Build Coastguard Worker 			break;
225*1c60b9acSAndroid Build Coastguard Worker 		case US_PC1:
226*1c60b9acSAndroid Build Coastguard Worker 			n = char_to_hex(*in);
227*1c60b9acSAndroid Build Coastguard Worker 			if (n < 0)
228*1c60b9acSAndroid Build Coastguard Worker 				return -1;
229*1c60b9acSAndroid Build Coastguard Worker 
230*1c60b9acSAndroid Build Coastguard Worker 			in++;
231*1c60b9acSAndroid Build Coastguard Worker 			s->sum = n << 4;
232*1c60b9acSAndroid Build Coastguard Worker 			s->state++;
233*1c60b9acSAndroid Build Coastguard Worker 			break;
234*1c60b9acSAndroid Build Coastguard Worker 
235*1c60b9acSAndroid Build Coastguard Worker 		case US_PC2:
236*1c60b9acSAndroid Build Coastguard Worker 			n = char_to_hex(*in);
237*1c60b9acSAndroid Build Coastguard Worker 			if (n < 0)
238*1c60b9acSAndroid Build Coastguard Worker 				return -1;
239*1c60b9acSAndroid Build Coastguard Worker 
240*1c60b9acSAndroid Build Coastguard Worker 			in++;
241*1c60b9acSAndroid Build Coastguard Worker 			s->out[s->pos++] = (char)(s->sum | n);
242*1c60b9acSAndroid Build Coastguard Worker 			s->state = US_IDLE;
243*1c60b9acSAndroid Build Coastguard Worker 			break;
244*1c60b9acSAndroid Build Coastguard Worker 
245*1c60b9acSAndroid Build Coastguard Worker 
246*1c60b9acSAndroid Build Coastguard Worker 		/* states for multipart / mime style */
247*1c60b9acSAndroid Build Coastguard Worker 
248*1c60b9acSAndroid Build Coastguard Worker 		case MT_LOOK_BOUND_IN:
249*1c60b9acSAndroid Build Coastguard Worker retry_as_first:
250*1c60b9acSAndroid Build Coastguard Worker 			if (*in == s->mime_boundary[s->mp] &&
251*1c60b9acSAndroid Build Coastguard Worker 			    s->mime_boundary[s->mp]) {
252*1c60b9acSAndroid Build Coastguard Worker 				in++;
253*1c60b9acSAndroid Build Coastguard Worker 				s->mp++;
254*1c60b9acSAndroid Build Coastguard Worker 				if (!s->mime_boundary[s->mp]) {
255*1c60b9acSAndroid Build Coastguard Worker 					s->mp = 0;
256*1c60b9acSAndroid Build Coastguard Worker 					s->state = MT_IGNORE1;
257*1c60b9acSAndroid Build Coastguard Worker 
258*1c60b9acSAndroid Build Coastguard Worker 					if (s->output(s->data, s->name,
259*1c60b9acSAndroid Build Coastguard Worker 						      &s->out, s->pos,
260*1c60b9acSAndroid Build Coastguard Worker 						      LWS_UFS_FINAL_CONTENT))
261*1c60b9acSAndroid Build Coastguard Worker 						return -1;
262*1c60b9acSAndroid Build Coastguard Worker 
263*1c60b9acSAndroid Build Coastguard Worker 					s->pos = 0;
264*1c60b9acSAndroid Build Coastguard Worker 
265*1c60b9acSAndroid Build Coastguard Worker 					s->content_disp[0] = '\0';
266*1c60b9acSAndroid Build Coastguard Worker 					s->name[0] = '\0';
267*1c60b9acSAndroid Build Coastguard Worker 					s->content_disp_filename[0] = '\0';
268*1c60b9acSAndroid Build Coastguard Worker 					s->boundary_real_crlf = 1;
269*1c60b9acSAndroid Build Coastguard Worker 				}
270*1c60b9acSAndroid Build Coastguard Worker 				continue;
271*1c60b9acSAndroid Build Coastguard Worker 			}
272*1c60b9acSAndroid Build Coastguard Worker 			if (s->mp) {
273*1c60b9acSAndroid Build Coastguard Worker 				n = 0;
274*1c60b9acSAndroid Build Coastguard Worker 				if (!s->boundary_real_crlf)
275*1c60b9acSAndroid Build Coastguard Worker 					n = 2;
276*1c60b9acSAndroid Build Coastguard Worker 				if (s->mp >= n) {
277*1c60b9acSAndroid Build Coastguard Worker 					memcpy(s->out + s->pos,
278*1c60b9acSAndroid Build Coastguard Worker 					       s->mime_boundary + n,
279*1c60b9acSAndroid Build Coastguard Worker 					       (unsigned int)(s->mp - n));
280*1c60b9acSAndroid Build Coastguard Worker 					s->pos += s->mp;
281*1c60b9acSAndroid Build Coastguard Worker 					s->mp = 0;
282*1c60b9acSAndroid Build Coastguard Worker 					goto retry_as_first;
283*1c60b9acSAndroid Build Coastguard Worker 				}
284*1c60b9acSAndroid Build Coastguard Worker 			}
285*1c60b9acSAndroid Build Coastguard Worker 
286*1c60b9acSAndroid Build Coastguard Worker 			s->out[s->pos++] = *in;
287*1c60b9acSAndroid Build Coastguard Worker 			in++;
288*1c60b9acSAndroid Build Coastguard Worker 			s->mp = 0;
289*1c60b9acSAndroid Build Coastguard Worker 			break;
290*1c60b9acSAndroid Build Coastguard Worker 
291*1c60b9acSAndroid Build Coastguard Worker 		case MT_HNAME:
292*1c60b9acSAndroid Build Coastguard Worker 			c =*in;
293*1c60b9acSAndroid Build Coastguard Worker 			if (c >= 'A' && c <= 'Z')
294*1c60b9acSAndroid Build Coastguard Worker 				c = (char)(c + 'a' - 'A');
295*1c60b9acSAndroid Build Coastguard Worker 			if (!s->mp)
296*1c60b9acSAndroid Build Coastguard Worker 				/* initially, any of them might match */
297*1c60b9acSAndroid Build Coastguard Worker 				s->matchable = (1 << LWS_ARRAY_SIZE(mp_hdrs)) - 1;
298*1c60b9acSAndroid Build Coastguard Worker 
299*1c60b9acSAndroid Build Coastguard Worker 			hit = -1;
300*1c60b9acSAndroid Build Coastguard Worker 			for (n = 0; n < (int)LWS_ARRAY_SIZE(mp_hdrs); n++) {
301*1c60b9acSAndroid Build Coastguard Worker 
302*1c60b9acSAndroid Build Coastguard Worker 				if (!(s->matchable & (1 << n)))
303*1c60b9acSAndroid Build Coastguard Worker 					continue;
304*1c60b9acSAndroid Build Coastguard Worker 				/* this guy is still in contention... */
305*1c60b9acSAndroid Build Coastguard Worker 
306*1c60b9acSAndroid Build Coastguard Worker 				if (s->mp >= mp_hdrs[n].hdr_len) {
307*1c60b9acSAndroid Build Coastguard Worker 					/* he went past the end of it */
308*1c60b9acSAndroid Build Coastguard Worker 					s->matchable &= (uint8_t)~(1 << n);
309*1c60b9acSAndroid Build Coastguard Worker 					continue;
310*1c60b9acSAndroid Build Coastguard Worker 				}
311*1c60b9acSAndroid Build Coastguard Worker 
312*1c60b9acSAndroid Build Coastguard Worker 				if (c != mp_hdrs[n].hdr[s->mp]) {
313*1c60b9acSAndroid Build Coastguard Worker 					/* mismatched a char */
314*1c60b9acSAndroid Build Coastguard Worker 					s->matchable &= (uint8_t)~(1 << n);
315*1c60b9acSAndroid Build Coastguard Worker 					continue;
316*1c60b9acSAndroid Build Coastguard Worker 				}
317*1c60b9acSAndroid Build Coastguard Worker 
318*1c60b9acSAndroid Build Coastguard Worker 				if (s->mp + 1 == mp_hdrs[n].hdr_len) {
319*1c60b9acSAndroid Build Coastguard Worker 					/* we have a winner... */
320*1c60b9acSAndroid Build Coastguard Worker 					hit = n;
321*1c60b9acSAndroid Build Coastguard Worker 					break;
322*1c60b9acSAndroid Build Coastguard Worker 				}
323*1c60b9acSAndroid Build Coastguard Worker 			}
324*1c60b9acSAndroid Build Coastguard Worker 
325*1c60b9acSAndroid Build Coastguard Worker 			in++;
326*1c60b9acSAndroid Build Coastguard Worker 			if (hit == -1 && !s->matchable) {
327*1c60b9acSAndroid Build Coastguard Worker 				/* We ruled them all out */
328*1c60b9acSAndroid Build Coastguard Worker 				s->state = MT_IGNORE1;
329*1c60b9acSAndroid Build Coastguard Worker 				s->mp = 0;
330*1c60b9acSAndroid Build Coastguard Worker 				continue;
331*1c60b9acSAndroid Build Coastguard Worker 			}
332*1c60b9acSAndroid Build Coastguard Worker 
333*1c60b9acSAndroid Build Coastguard Worker 			s->mp++;
334*1c60b9acSAndroid Build Coastguard Worker 			if (hit < 0)
335*1c60b9acSAndroid Build Coastguard Worker 				continue;
336*1c60b9acSAndroid Build Coastguard Worker 
337*1c60b9acSAndroid Build Coastguard Worker 			/* we matched the one in hit */
338*1c60b9acSAndroid Build Coastguard Worker 
339*1c60b9acSAndroid Build Coastguard Worker 			s->mp = 0;
340*1c60b9acSAndroid Build Coastguard Worker 			s->temp[0] = '\0';
341*1c60b9acSAndroid Build Coastguard Worker 			s->subname = 0;
342*1c60b9acSAndroid Build Coastguard Worker 
343*1c60b9acSAndroid Build Coastguard Worker 			if (hit == 2)
344*1c60b9acSAndroid Build Coastguard Worker 				s->state = MT_LOOK_BOUND_IN;
345*1c60b9acSAndroid Build Coastguard Worker 			else
346*1c60b9acSAndroid Build Coastguard Worker 				s->state += (unsigned int)hit + 1u;
347*1c60b9acSAndroid Build Coastguard Worker 			break;
348*1c60b9acSAndroid Build Coastguard Worker 
349*1c60b9acSAndroid Build Coastguard Worker 		case MT_DISP:
350*1c60b9acSAndroid Build Coastguard Worker 			/* form-data; name="file"; filename="t.txt" */
351*1c60b9acSAndroid Build Coastguard Worker 
352*1c60b9acSAndroid Build Coastguard Worker 			if (*in == '\x0d') {
353*1c60b9acSAndroid Build Coastguard Worker 				if (s->content_disp_filename[0])
354*1c60b9acSAndroid Build Coastguard Worker 					if (s->output(s->data, s->name,
355*1c60b9acSAndroid Build Coastguard Worker 						      &s->out, s->pos,
356*1c60b9acSAndroid Build Coastguard Worker 						      LWS_UFS_OPEN))
357*1c60b9acSAndroid Build Coastguard Worker 						return -1;
358*1c60b9acSAndroid Build Coastguard Worker 				s->state = MT_IGNORE2;
359*1c60b9acSAndroid Build Coastguard Worker 				goto done;
360*1c60b9acSAndroid Build Coastguard Worker 			}
361*1c60b9acSAndroid Build Coastguard Worker 			if (*in == ';') {
362*1c60b9acSAndroid Build Coastguard Worker 				s->subname = 1;
363*1c60b9acSAndroid Build Coastguard Worker 				s->temp[0] = '\0';
364*1c60b9acSAndroid Build Coastguard Worker 				s->mp = 0;
365*1c60b9acSAndroid Build Coastguard Worker 				goto done;
366*1c60b9acSAndroid Build Coastguard Worker 			}
367*1c60b9acSAndroid Build Coastguard Worker 
368*1c60b9acSAndroid Build Coastguard Worker 			if (*in == '\"') {
369*1c60b9acSAndroid Build Coastguard Worker 				s->inside_quote = !!((s->inside_quote ^ 1) & 1);
370*1c60b9acSAndroid Build Coastguard Worker 				goto done;
371*1c60b9acSAndroid Build Coastguard Worker 			}
372*1c60b9acSAndroid Build Coastguard Worker 
373*1c60b9acSAndroid Build Coastguard Worker 			if (s->subname) {
374*1c60b9acSAndroid Build Coastguard Worker 				if (*in == '=') {
375*1c60b9acSAndroid Build Coastguard Worker 					s->temp[s->mp] = '\0';
376*1c60b9acSAndroid Build Coastguard Worker 					s->subname = 0;
377*1c60b9acSAndroid Build Coastguard Worker 					s->mp = 0;
378*1c60b9acSAndroid Build Coastguard Worker 					goto done;
379*1c60b9acSAndroid Build Coastguard Worker 				}
380*1c60b9acSAndroid Build Coastguard Worker 				if (s->mp < (int)sizeof(s->temp) - 1 &&
381*1c60b9acSAndroid Build Coastguard Worker 				    (*in != ' ' || s->inside_quote))
382*1c60b9acSAndroid Build Coastguard Worker 					s->temp[s->mp++] = *in;
383*1c60b9acSAndroid Build Coastguard Worker 				goto done;
384*1c60b9acSAndroid Build Coastguard Worker 			}
385*1c60b9acSAndroid Build Coastguard Worker 
386*1c60b9acSAndroid Build Coastguard Worker 			if (!s->temp[0]) {
387*1c60b9acSAndroid Build Coastguard Worker 				if (s->mp < (int)sizeof(s->content_disp) - 1)
388*1c60b9acSAndroid Build Coastguard Worker 					s->content_disp[s->mp++] = *in;
389*1c60b9acSAndroid Build Coastguard Worker 				if (s->mp < (int)sizeof(s->content_disp))
390*1c60b9acSAndroid Build Coastguard Worker 					s->content_disp[s->mp] = '\0';
391*1c60b9acSAndroid Build Coastguard Worker 				goto done;
392*1c60b9acSAndroid Build Coastguard Worker 			}
393*1c60b9acSAndroid Build Coastguard Worker 
394*1c60b9acSAndroid Build Coastguard Worker 			if (!strcmp(s->temp, "name")) {
395*1c60b9acSAndroid Build Coastguard Worker 				if (s->mp < (int)sizeof(s->name) - 1)
396*1c60b9acSAndroid Build Coastguard Worker 					s->name[s->mp++] = *in;
397*1c60b9acSAndroid Build Coastguard Worker 				else
398*1c60b9acSAndroid Build Coastguard Worker 					s->mp = (int)sizeof(s->name) - 1;
399*1c60b9acSAndroid Build Coastguard Worker 				s->name[s->mp] = '\0';
400*1c60b9acSAndroid Build Coastguard Worker 				goto done;
401*1c60b9acSAndroid Build Coastguard Worker 			}
402*1c60b9acSAndroid Build Coastguard Worker 
403*1c60b9acSAndroid Build Coastguard Worker 			if (!strcmp(s->temp, "filename")) {
404*1c60b9acSAndroid Build Coastguard Worker 				if (s->mp < (int)sizeof(s->content_disp_filename) - 1)
405*1c60b9acSAndroid Build Coastguard Worker 					s->content_disp_filename[s->mp++] = *in;
406*1c60b9acSAndroid Build Coastguard Worker 				s->content_disp_filename[s->mp] = '\0';
407*1c60b9acSAndroid Build Coastguard Worker 				goto done;
408*1c60b9acSAndroid Build Coastguard Worker 			}
409*1c60b9acSAndroid Build Coastguard Worker done:
410*1c60b9acSAndroid Build Coastguard Worker 			in++;
411*1c60b9acSAndroid Build Coastguard Worker 			break;
412*1c60b9acSAndroid Build Coastguard Worker 
413*1c60b9acSAndroid Build Coastguard Worker 		case MT_TYPE:
414*1c60b9acSAndroid Build Coastguard Worker 			if (*in == '\x0d')
415*1c60b9acSAndroid Build Coastguard Worker 				s->state = MT_IGNORE2;
416*1c60b9acSAndroid Build Coastguard Worker 			else {
417*1c60b9acSAndroid Build Coastguard Worker 				if (s->mp < (int)sizeof(s->content_type) - 1)
418*1c60b9acSAndroid Build Coastguard Worker 					s->content_type[s->mp++] = *in;
419*1c60b9acSAndroid Build Coastguard Worker 				s->content_type[s->mp] = '\0';
420*1c60b9acSAndroid Build Coastguard Worker 			}
421*1c60b9acSAndroid Build Coastguard Worker 			in++;
422*1c60b9acSAndroid Build Coastguard Worker 			break;
423*1c60b9acSAndroid Build Coastguard Worker 
424*1c60b9acSAndroid Build Coastguard Worker 		case MT_IGNORE1:
425*1c60b9acSAndroid Build Coastguard Worker 			if (*in == '\x0d')
426*1c60b9acSAndroid Build Coastguard Worker 				s->state = MT_IGNORE2;
427*1c60b9acSAndroid Build Coastguard Worker 			if (*in == '-')
428*1c60b9acSAndroid Build Coastguard Worker 				s->state = MT_IGNORE3;
429*1c60b9acSAndroid Build Coastguard Worker 			in++;
430*1c60b9acSAndroid Build Coastguard Worker 			break;
431*1c60b9acSAndroid Build Coastguard Worker 
432*1c60b9acSAndroid Build Coastguard Worker 		case MT_IGNORE2:
433*1c60b9acSAndroid Build Coastguard Worker 			s->mp = 0;
434*1c60b9acSAndroid Build Coastguard Worker 			if (*in == '\x0a')
435*1c60b9acSAndroid Build Coastguard Worker 				s->state = MT_HNAME;
436*1c60b9acSAndroid Build Coastguard Worker 			in++;
437*1c60b9acSAndroid Build Coastguard Worker 			break;
438*1c60b9acSAndroid Build Coastguard Worker 
439*1c60b9acSAndroid Build Coastguard Worker 		case MT_IGNORE3:
440*1c60b9acSAndroid Build Coastguard Worker 			if (*in == '\x0d')
441*1c60b9acSAndroid Build Coastguard Worker 				s->state = MT_IGNORE1;
442*1c60b9acSAndroid Build Coastguard Worker 			else if (*in == '-') {
443*1c60b9acSAndroid Build Coastguard Worker 				s->state = MT_COMPLETED;
444*1c60b9acSAndroid Build Coastguard Worker 				s->wsi->http.rx_content_remain = 0;
445*1c60b9acSAndroid Build Coastguard Worker 			}
446*1c60b9acSAndroid Build Coastguard Worker 			else in++;
447*1c60b9acSAndroid Build Coastguard Worker 			break;
448*1c60b9acSAndroid Build Coastguard Worker 		case MT_COMPLETED:
449*1c60b9acSAndroid Build Coastguard Worker 			break;
450*1c60b9acSAndroid Build Coastguard Worker 		}
451*1c60b9acSAndroid Build Coastguard Worker 	}
452*1c60b9acSAndroid Build Coastguard Worker 
453*1c60b9acSAndroid Build Coastguard Worker 	return 0;
454*1c60b9acSAndroid Build Coastguard Worker }
455*1c60b9acSAndroid Build Coastguard Worker 
456*1c60b9acSAndroid Build Coastguard Worker static int
lws_urldecode_s_destroy(struct lws_spa * spa,struct lws_urldecode_stateful * s)457*1c60b9acSAndroid Build Coastguard Worker lws_urldecode_s_destroy(struct lws_spa *spa, struct lws_urldecode_stateful *s)
458*1c60b9acSAndroid Build Coastguard Worker {
459*1c60b9acSAndroid Build Coastguard Worker 	int ret = 0;
460*1c60b9acSAndroid Build Coastguard Worker 
461*1c60b9acSAndroid Build Coastguard Worker 	if (s->state != US_IDLE)
462*1c60b9acSAndroid Build Coastguard Worker 		ret = -1;
463*1c60b9acSAndroid Build Coastguard Worker 
464*1c60b9acSAndroid Build Coastguard Worker 	if (!ret)
465*1c60b9acSAndroid Build Coastguard Worker 		if (s->output(s->data, s->name, &s->out, s->pos,
466*1c60b9acSAndroid Build Coastguard Worker 			      LWS_UFS_FINAL_CONTENT))
467*1c60b9acSAndroid Build Coastguard Worker 			ret = -1;
468*1c60b9acSAndroid Build Coastguard Worker 
469*1c60b9acSAndroid Build Coastguard Worker 	if (s->output(s->data, s->name, NULL, 0, LWS_UFS_CLOSE))
470*1c60b9acSAndroid Build Coastguard Worker 		return -1;
471*1c60b9acSAndroid Build Coastguard Worker 
472*1c60b9acSAndroid Build Coastguard Worker 	if (!spa->i.ac)
473*1c60b9acSAndroid Build Coastguard Worker 		lws_free(s);
474*1c60b9acSAndroid Build Coastguard Worker 
475*1c60b9acSAndroid Build Coastguard Worker 	return ret;
476*1c60b9acSAndroid Build Coastguard Worker }
477*1c60b9acSAndroid Build Coastguard Worker 
478*1c60b9acSAndroid Build Coastguard Worker static int
lws_urldecode_spa_lookup(struct lws_spa * spa,const char * name)479*1c60b9acSAndroid Build Coastguard Worker lws_urldecode_spa_lookup(struct lws_spa *spa, const char *name)
480*1c60b9acSAndroid Build Coastguard Worker {
481*1c60b9acSAndroid Build Coastguard Worker 	const char * const *pp = spa->i.param_names;
482*1c60b9acSAndroid Build Coastguard Worker 	int n;
483*1c60b9acSAndroid Build Coastguard Worker 
484*1c60b9acSAndroid Build Coastguard Worker 	for (n = 0; n < spa->i.count_params; n++) {
485*1c60b9acSAndroid Build Coastguard Worker 		if (!strcmp(*pp, name))
486*1c60b9acSAndroid Build Coastguard Worker 			return n;
487*1c60b9acSAndroid Build Coastguard Worker 
488*1c60b9acSAndroid Build Coastguard Worker 		if (spa->i.param_names_stride)
489*1c60b9acSAndroid Build Coastguard Worker 			pp = (const char * const *)(((char *)pp) + spa->i.param_names_stride);
490*1c60b9acSAndroid Build Coastguard Worker 		else
491*1c60b9acSAndroid Build Coastguard Worker 			pp++;
492*1c60b9acSAndroid Build Coastguard Worker 	}
493*1c60b9acSAndroid Build Coastguard Worker 
494*1c60b9acSAndroid Build Coastguard Worker 	return -1;
495*1c60b9acSAndroid Build Coastguard Worker }
496*1c60b9acSAndroid Build Coastguard Worker 
497*1c60b9acSAndroid Build Coastguard Worker static int
lws_urldecode_spa_cb(struct lws_spa * spa,const char * name,char ** buf,int len,int final)498*1c60b9acSAndroid Build Coastguard Worker lws_urldecode_spa_cb(struct lws_spa *spa, const char *name, char **buf, int len,
499*1c60b9acSAndroid Build Coastguard Worker 		     int final)
500*1c60b9acSAndroid Build Coastguard Worker {
501*1c60b9acSAndroid Build Coastguard Worker 	int n;
502*1c60b9acSAndroid Build Coastguard Worker 
503*1c60b9acSAndroid Build Coastguard Worker 	if (final == LWS_UFS_CLOSE || spa->s->content_disp_filename[0]) {
504*1c60b9acSAndroid Build Coastguard Worker 		if (spa->i.opt_cb) {
505*1c60b9acSAndroid Build Coastguard Worker 			n = spa->i.opt_cb(spa->i.opt_data, name,
506*1c60b9acSAndroid Build Coastguard Worker 					spa->s->content_disp_filename,
507*1c60b9acSAndroid Build Coastguard Worker 					buf ? *buf : NULL, len, (enum lws_spa_fileupload_states)final);
508*1c60b9acSAndroid Build Coastguard Worker 
509*1c60b9acSAndroid Build Coastguard Worker 			if (n < 0)
510*1c60b9acSAndroid Build Coastguard Worker 				return -1;
511*1c60b9acSAndroid Build Coastguard Worker 		}
512*1c60b9acSAndroid Build Coastguard Worker 		return 0;
513*1c60b9acSAndroid Build Coastguard Worker 	}
514*1c60b9acSAndroid Build Coastguard Worker 	n = lws_urldecode_spa_lookup(spa, name);
515*1c60b9acSAndroid Build Coastguard Worker 	if (n == -1 || !len) /* unrecognized */
516*1c60b9acSAndroid Build Coastguard Worker 		return 0;
517*1c60b9acSAndroid Build Coastguard Worker 
518*1c60b9acSAndroid Build Coastguard Worker 	if (!spa->i.ac) {
519*1c60b9acSAndroid Build Coastguard Worker 		if (!spa->params[n])
520*1c60b9acSAndroid Build Coastguard Worker 			spa->params[n] = *buf;
521*1c60b9acSAndroid Build Coastguard Worker 
522*1c60b9acSAndroid Build Coastguard Worker 		if ((*buf) + len >= spa->end) {
523*1c60b9acSAndroid Build Coastguard Worker 			lwsl_info("%s: exceeded storage\n", __func__);
524*1c60b9acSAndroid Build Coastguard Worker 			return -1;
525*1c60b9acSAndroid Build Coastguard Worker 		}
526*1c60b9acSAndroid Build Coastguard Worker 
527*1c60b9acSAndroid Build Coastguard Worker 		/* move it on inside storage */
528*1c60b9acSAndroid Build Coastguard Worker 		(*buf) += len;
529*1c60b9acSAndroid Build Coastguard Worker 		*((*buf)++) = '\0';
530*1c60b9acSAndroid Build Coastguard Worker 
531*1c60b9acSAndroid Build Coastguard Worker 		spa->s->out_len -= len + 1;
532*1c60b9acSAndroid Build Coastguard Worker 	} else {
533*1c60b9acSAndroid Build Coastguard Worker 		spa->params[n] = lwsac_use(spa->i.ac, (unsigned int)len + 1,
534*1c60b9acSAndroid Build Coastguard Worker 					   spa->i.ac_chunk_size);
535*1c60b9acSAndroid Build Coastguard Worker 		if (!spa->params[n])
536*1c60b9acSAndroid Build Coastguard Worker 			return -1;
537*1c60b9acSAndroid Build Coastguard Worker 
538*1c60b9acSAndroid Build Coastguard Worker 		memcpy(spa->params[n], *buf, (unsigned int)len);
539*1c60b9acSAndroid Build Coastguard Worker 		spa->params[n][len] = '\0';
540*1c60b9acSAndroid Build Coastguard Worker 	}
541*1c60b9acSAndroid Build Coastguard Worker 
542*1c60b9acSAndroid Build Coastguard Worker 	spa->param_length[n] += len;
543*1c60b9acSAndroid Build Coastguard Worker 
544*1c60b9acSAndroid Build Coastguard Worker 	return 0;
545*1c60b9acSAndroid Build Coastguard Worker }
546*1c60b9acSAndroid Build Coastguard Worker 
547*1c60b9acSAndroid Build Coastguard Worker struct lws_spa *
lws_spa_create_via_info(struct lws * wsi,const lws_spa_create_info_t * i)548*1c60b9acSAndroid Build Coastguard Worker lws_spa_create_via_info(struct lws *wsi, const lws_spa_create_info_t *i)
549*1c60b9acSAndroid Build Coastguard Worker {
550*1c60b9acSAndroid Build Coastguard Worker 	struct lws_spa *spa;
551*1c60b9acSAndroid Build Coastguard Worker 
552*1c60b9acSAndroid Build Coastguard Worker 	if (i->ac)
553*1c60b9acSAndroid Build Coastguard Worker 		spa = lwsac_use_zero(i->ac, sizeof(*spa), i->ac_chunk_size);
554*1c60b9acSAndroid Build Coastguard Worker 	else
555*1c60b9acSAndroid Build Coastguard Worker 		spa = lws_zalloc(sizeof(*spa), "spa");
556*1c60b9acSAndroid Build Coastguard Worker 
557*1c60b9acSAndroid Build Coastguard Worker 	if (!spa)
558*1c60b9acSAndroid Build Coastguard Worker 		return NULL;
559*1c60b9acSAndroid Build Coastguard Worker 
560*1c60b9acSAndroid Build Coastguard Worker 	spa->i = *i;
561*1c60b9acSAndroid Build Coastguard Worker 	if (!spa->i.max_storage)
562*1c60b9acSAndroid Build Coastguard Worker 		spa->i.max_storage = 512;
563*1c60b9acSAndroid Build Coastguard Worker 
564*1c60b9acSAndroid Build Coastguard Worker 	if (i->ac)
565*1c60b9acSAndroid Build Coastguard Worker 		spa->storage = lwsac_use(i->ac, (unsigned int)spa->i.max_storage,
566*1c60b9acSAndroid Build Coastguard Worker 					 i->ac_chunk_size);
567*1c60b9acSAndroid Build Coastguard Worker 	else
568*1c60b9acSAndroid Build Coastguard Worker 		spa->storage = lws_malloc((unsigned int)spa->i.max_storage, "spa");
569*1c60b9acSAndroid Build Coastguard Worker 
570*1c60b9acSAndroid Build Coastguard Worker 	if (!spa->storage)
571*1c60b9acSAndroid Build Coastguard Worker 		goto bail2;
572*1c60b9acSAndroid Build Coastguard Worker 
573*1c60b9acSAndroid Build Coastguard Worker 	spa->end = spa->storage + i->max_storage - 1;
574*1c60b9acSAndroid Build Coastguard Worker 
575*1c60b9acSAndroid Build Coastguard Worker 	if (i->count_params) {
576*1c60b9acSAndroid Build Coastguard Worker 		if (i->ac)
577*1c60b9acSAndroid Build Coastguard Worker 			spa->params = lwsac_use_zero(i->ac,
578*1c60b9acSAndroid Build Coastguard Worker 				sizeof(char *) * (unsigned int)i->count_params, i->ac_chunk_size);
579*1c60b9acSAndroid Build Coastguard Worker 		else
580*1c60b9acSAndroid Build Coastguard Worker 			spa->params = lws_zalloc(sizeof(char *) * (unsigned int)i->count_params,
581*1c60b9acSAndroid Build Coastguard Worker 					 "spa params");
582*1c60b9acSAndroid Build Coastguard Worker 		if (!spa->params)
583*1c60b9acSAndroid Build Coastguard Worker 			goto bail3;
584*1c60b9acSAndroid Build Coastguard Worker 	}
585*1c60b9acSAndroid Build Coastguard Worker 
586*1c60b9acSAndroid Build Coastguard Worker 	spa->s = lws_urldecode_s_create(spa, wsi, spa->storage, i->max_storage,
587*1c60b9acSAndroid Build Coastguard Worker 					lws_urldecode_spa_cb);
588*1c60b9acSAndroid Build Coastguard Worker 	if (!spa->s)
589*1c60b9acSAndroid Build Coastguard Worker 		goto bail4;
590*1c60b9acSAndroid Build Coastguard Worker 
591*1c60b9acSAndroid Build Coastguard Worker 	if (i->count_params) {
592*1c60b9acSAndroid Build Coastguard Worker 		if (i->ac)
593*1c60b9acSAndroid Build Coastguard Worker 			spa->param_length = lwsac_use_zero(i->ac,
594*1c60b9acSAndroid Build Coastguard Worker 				sizeof(int) * (unsigned int)i->count_params, i->ac_chunk_size);
595*1c60b9acSAndroid Build Coastguard Worker 		else
596*1c60b9acSAndroid Build Coastguard Worker 			spa->param_length = lws_zalloc(sizeof(int) * (unsigned int)i->count_params,
597*1c60b9acSAndroid Build Coastguard Worker 						"spa param len");
598*1c60b9acSAndroid Build Coastguard Worker 		if (!spa->param_length)
599*1c60b9acSAndroid Build Coastguard Worker 			goto bail5;
600*1c60b9acSAndroid Build Coastguard Worker 	}
601*1c60b9acSAndroid Build Coastguard Worker 
602*1c60b9acSAndroid Build Coastguard Worker 	// lwsl_notice("%s: Created SPA %p\n", __func__, spa);
603*1c60b9acSAndroid Build Coastguard Worker 
604*1c60b9acSAndroid Build Coastguard Worker 	return spa;
605*1c60b9acSAndroid Build Coastguard Worker 
606*1c60b9acSAndroid Build Coastguard Worker bail5:
607*1c60b9acSAndroid Build Coastguard Worker 	lws_urldecode_s_destroy(spa, spa->s);
608*1c60b9acSAndroid Build Coastguard Worker bail4:
609*1c60b9acSAndroid Build Coastguard Worker 	if (!i->ac)
610*1c60b9acSAndroid Build Coastguard Worker 		lws_free(spa->params);
611*1c60b9acSAndroid Build Coastguard Worker bail3:
612*1c60b9acSAndroid Build Coastguard Worker 	if (!i->ac)
613*1c60b9acSAndroid Build Coastguard Worker 		lws_free(spa->storage);
614*1c60b9acSAndroid Build Coastguard Worker bail2:
615*1c60b9acSAndroid Build Coastguard Worker 	if (!i->ac)
616*1c60b9acSAndroid Build Coastguard Worker 		lws_free(spa);
617*1c60b9acSAndroid Build Coastguard Worker 
618*1c60b9acSAndroid Build Coastguard Worker 	if (i->ac)
619*1c60b9acSAndroid Build Coastguard Worker 		lwsac_free(i->ac);
620*1c60b9acSAndroid Build Coastguard Worker 
621*1c60b9acSAndroid Build Coastguard Worker 	return NULL;
622*1c60b9acSAndroid Build Coastguard Worker }
623*1c60b9acSAndroid Build Coastguard Worker 
624*1c60b9acSAndroid Build Coastguard Worker struct lws_spa *
lws_spa_create(struct lws * wsi,const char * const * param_names,int count_params,int max_storage,lws_spa_fileupload_cb opt_cb,void * opt_data)625*1c60b9acSAndroid Build Coastguard Worker lws_spa_create(struct lws *wsi, const char * const *param_names,
626*1c60b9acSAndroid Build Coastguard Worker 	       int count_params, int max_storage,
627*1c60b9acSAndroid Build Coastguard Worker 	       lws_spa_fileupload_cb opt_cb, void *opt_data)
628*1c60b9acSAndroid Build Coastguard Worker {
629*1c60b9acSAndroid Build Coastguard Worker 	lws_spa_create_info_t i;
630*1c60b9acSAndroid Build Coastguard Worker 
631*1c60b9acSAndroid Build Coastguard Worker 	memset(&i, 0, sizeof(i));
632*1c60b9acSAndroid Build Coastguard Worker 	i.count_params = count_params;
633*1c60b9acSAndroid Build Coastguard Worker 	i.max_storage = max_storage;
634*1c60b9acSAndroid Build Coastguard Worker 	i.opt_cb = opt_cb;
635*1c60b9acSAndroid Build Coastguard Worker 	i.opt_data = opt_data;
636*1c60b9acSAndroid Build Coastguard Worker 	i.param_names = param_names;
637*1c60b9acSAndroid Build Coastguard Worker 
638*1c60b9acSAndroid Build Coastguard Worker 	return lws_spa_create_via_info(wsi, &i);
639*1c60b9acSAndroid Build Coastguard Worker }
640*1c60b9acSAndroid Build Coastguard Worker 
641*1c60b9acSAndroid Build Coastguard Worker int
lws_spa_process(struct lws_spa * spa,const char * in,int len)642*1c60b9acSAndroid Build Coastguard Worker lws_spa_process(struct lws_spa *spa, const char *in, int len)
643*1c60b9acSAndroid Build Coastguard Worker {
644*1c60b9acSAndroid Build Coastguard Worker 	if (!spa) {
645*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: NULL spa\n", __func__);
646*1c60b9acSAndroid Build Coastguard Worker 		return -1;
647*1c60b9acSAndroid Build Coastguard Worker 	}
648*1c60b9acSAndroid Build Coastguard Worker 	/* we reject any junk after the last part arrived and we finalized */
649*1c60b9acSAndroid Build Coastguard Worker 	if (spa->finalized)
650*1c60b9acSAndroid Build Coastguard Worker 		return 0;
651*1c60b9acSAndroid Build Coastguard Worker 
652*1c60b9acSAndroid Build Coastguard Worker 	return lws_urldecode_s_process(spa->s, in, len);
653*1c60b9acSAndroid Build Coastguard Worker }
654*1c60b9acSAndroid Build Coastguard Worker 
655*1c60b9acSAndroid Build Coastguard Worker int
lws_spa_get_length(struct lws_spa * spa,int n)656*1c60b9acSAndroid Build Coastguard Worker lws_spa_get_length(struct lws_spa *spa, int n)
657*1c60b9acSAndroid Build Coastguard Worker {
658*1c60b9acSAndroid Build Coastguard Worker 	if (n >= spa->i.count_params)
659*1c60b9acSAndroid Build Coastguard Worker 		return 0;
660*1c60b9acSAndroid Build Coastguard Worker 
661*1c60b9acSAndroid Build Coastguard Worker 	return spa->param_length[n];
662*1c60b9acSAndroid Build Coastguard Worker }
663*1c60b9acSAndroid Build Coastguard Worker 
664*1c60b9acSAndroid Build Coastguard Worker const char *
lws_spa_get_string(struct lws_spa * spa,int n)665*1c60b9acSAndroid Build Coastguard Worker lws_spa_get_string(struct lws_spa *spa, int n)
666*1c60b9acSAndroid Build Coastguard Worker {
667*1c60b9acSAndroid Build Coastguard Worker 	if (n >= spa->i.count_params)
668*1c60b9acSAndroid Build Coastguard Worker 		return NULL;
669*1c60b9acSAndroid Build Coastguard Worker 
670*1c60b9acSAndroid Build Coastguard Worker 	return spa->params[n];
671*1c60b9acSAndroid Build Coastguard Worker }
672*1c60b9acSAndroid Build Coastguard Worker 
673*1c60b9acSAndroid Build Coastguard Worker int
lws_spa_finalize(struct lws_spa * spa)674*1c60b9acSAndroid Build Coastguard Worker lws_spa_finalize(struct lws_spa *spa)
675*1c60b9acSAndroid Build Coastguard Worker {
676*1c60b9acSAndroid Build Coastguard Worker 	if (!spa)
677*1c60b9acSAndroid Build Coastguard Worker 		return 0;
678*1c60b9acSAndroid Build Coastguard Worker 
679*1c60b9acSAndroid Build Coastguard Worker 	if (spa->s) {
680*1c60b9acSAndroid Build Coastguard Worker 		lws_urldecode_s_destroy(spa, spa->s);
681*1c60b9acSAndroid Build Coastguard Worker 		spa->s = NULL;
682*1c60b9acSAndroid Build Coastguard Worker 	}
683*1c60b9acSAndroid Build Coastguard Worker 
684*1c60b9acSAndroid Build Coastguard Worker 	spa->finalized = 1;
685*1c60b9acSAndroid Build Coastguard Worker 
686*1c60b9acSAndroid Build Coastguard Worker 	return 0;
687*1c60b9acSAndroid Build Coastguard Worker }
688*1c60b9acSAndroid Build Coastguard Worker 
689*1c60b9acSAndroid Build Coastguard Worker int
lws_spa_destroy(struct lws_spa * spa)690*1c60b9acSAndroid Build Coastguard Worker lws_spa_destroy(struct lws_spa *spa)
691*1c60b9acSAndroid Build Coastguard Worker {
692*1c60b9acSAndroid Build Coastguard Worker 	int n = 0;
693*1c60b9acSAndroid Build Coastguard Worker 
694*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("%s: destroy spa %p\n", __func__, spa);
695*1c60b9acSAndroid Build Coastguard Worker 
696*1c60b9acSAndroid Build Coastguard Worker 	if (spa->s)
697*1c60b9acSAndroid Build Coastguard Worker 		lws_urldecode_s_destroy(spa, spa->s);
698*1c60b9acSAndroid Build Coastguard Worker 
699*1c60b9acSAndroid Build Coastguard Worker 	if (spa->i.ac)
700*1c60b9acSAndroid Build Coastguard Worker 		lwsac_free(spa->i.ac);
701*1c60b9acSAndroid Build Coastguard Worker 	else {
702*1c60b9acSAndroid Build Coastguard Worker 		lws_free(spa->param_length);
703*1c60b9acSAndroid Build Coastguard Worker 		lws_free(spa->params);
704*1c60b9acSAndroid Build Coastguard Worker 		lws_free(spa->storage);
705*1c60b9acSAndroid Build Coastguard Worker 		lws_free(spa);
706*1c60b9acSAndroid Build Coastguard Worker 	}
707*1c60b9acSAndroid Build Coastguard Worker 
708*1c60b9acSAndroid Build Coastguard Worker 	return n;
709*1c60b9acSAndroid Build Coastguard Worker }
710