1 #include "uwsgi.h"
2 
3 extern struct uwsgi_server uwsgi;
4 
5 // this is like uwsgi_str_num but with security checks
get_content_length(char * buf,uint16_t size)6 static size_t get_content_length(char *buf, uint16_t size) {
7         int i;
8         size_t val = 0;
9         for (i = 0; i < size; i++) {
10                 if (buf[i] >= '0' && buf[i] <= '9') {
11                         val = (val * 10) + (buf[i] - '0');
12                         continue;
13                 }
14                 break;
15         }
16 
17         return val;
18 }
19 
20 
uwsgi_read_response(int fd,struct uwsgi_header * uh,int timeout,char ** buf)21 int uwsgi_read_response(int fd, struct uwsgi_header *uh, int timeout, char **buf) {
22 
23 	char *ptr = (char *) uh;
24 	size_t remains = 4;
25 	int ret = -1;
26 	int rlen;
27 	ssize_t len;
28 
29 	while (remains > 0) {
30 		rlen = uwsgi_waitfd(fd, timeout);
31 		if (rlen > 0) {
32 			len = read(fd, ptr, remains);
33 			if (len <= 0)
34 				break;
35 			remains -= len;
36 			ptr += len;
37 			if (remains == 0) {
38 				ret = uh->modifier2;
39 				break;
40 			}
41 			continue;
42 		}
43 		// timed out ?
44 		else if (ret == 0)
45 			ret = -2;
46 		break;
47 	}
48 
49 	if (buf && uh->pktsize > 0) {
50 		if (*buf == NULL)
51 			*buf = uwsgi_malloc(uh->pktsize);
52 		remains = uh->pktsize;
53 		ptr = *buf;
54 		ret = -1;
55 		while (remains > 0) {
56 			rlen = uwsgi_waitfd(fd, timeout);
57 			if (rlen > 0) {
58 				len = read(fd, ptr, remains);
59 				if (len <= 0)
60 					break;
61 				remains -= len;
62 				ptr += len;
63 				if (remains == 0) {
64 					ret = uh->modifier2;
65 					break;
66 				}
67 				continue;
68 			}
69 			// timed out ?
70 			else if (ret == 0)
71 				ret = -2;
72 			break;
73 		}
74 	}
75 
76 	return ret;
77 }
78 
uwsgi_parse_array(char * buffer,uint16_t size,char ** argv,uint16_t argvs[],uint8_t * argc)79 int uwsgi_parse_array(char *buffer, uint16_t size, char **argv, uint16_t argvs[], uint8_t * argc) {
80 
81 	char *ptrbuf, *bufferend;
82 	uint16_t strsize = 0;
83 
84 	uint8_t max = *argc;
85 	*argc = 0;
86 
87 	ptrbuf = buffer;
88 	bufferend = ptrbuf + size;
89 
90 	while (ptrbuf < bufferend && *argc < max) {
91 		if (ptrbuf + 2 < bufferend) {
92 			memcpy(&strsize, ptrbuf, 2);
93 #ifdef __BIG_ENDIAN__
94 			strsize = uwsgi_swap16(strsize);
95 #endif
96 
97 			ptrbuf += 2;
98 			/* item cannot be null */
99 			if (!strsize)
100 				continue;
101 
102 			if (ptrbuf + strsize <= bufferend) {
103 				// item
104 				argv[*argc] = uwsgi_cheap_string(ptrbuf, strsize);
105 				argvs[*argc] = strsize;
106 #ifdef UWSGI_DEBUG
107 				uwsgi_log("arg %s\n", argv[*argc]);
108 #endif
109 				ptrbuf += strsize;
110 				*argc = *argc + 1;
111 			}
112 			else {
113 				uwsgi_log("invalid uwsgi array. skip this var.\n");
114 				return -1;
115 			}
116 		}
117 		else {
118 			uwsgi_log("invalid uwsgi array. skip this request.\n");
119 			return -1;
120 		}
121 	}
122 
123 
124 	return 0;
125 }
126 
uwsgi_simple_parse_vars(struct wsgi_request * wsgi_req,char * ptrbuf,char * bufferend)127 int uwsgi_simple_parse_vars(struct wsgi_request *wsgi_req, char *ptrbuf, char *bufferend) {
128 
129 	uint16_t strsize;
130 
131 	while (ptrbuf < bufferend) {
132 		if (ptrbuf + 2 < bufferend) {
133 			memcpy(&strsize, ptrbuf, 2);
134 #ifdef __BIG_ENDIAN__
135 			strsize = uwsgi_swap16(strsize);
136 #endif
137 			/* key cannot be null */
138 			if (!strsize) {
139 				uwsgi_log("uwsgi key cannot be null. skip this request.\n");
140 				return -1;
141 			}
142 
143 			ptrbuf += 2;
144 			if (ptrbuf + strsize < bufferend) {
145 				// var key
146 				wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptrbuf;
147 				wsgi_req->hvec[wsgi_req->var_cnt].iov_len = strsize;
148 				ptrbuf += strsize;
149 				// value can be null (even at the end) so use <=
150 				if (ptrbuf + 2 <= bufferend) {
151 					memcpy(&strsize, ptrbuf, 2);
152 #ifdef __BIG_ENDIAN__
153 					strsize = uwsgi_swap16(strsize);
154 #endif
155 					ptrbuf += 2;
156 					if (ptrbuf + strsize <= bufferend) {
157 
158 						if (wsgi_req->var_cnt < uwsgi.vec_size - (4 + 1)) {
159 							wsgi_req->var_cnt++;
160 						}
161 						else {
162 							uwsgi_log("max vec size reached. skip this header.\n");
163 							return -1;
164 						}
165 						// var value
166 						wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptrbuf;
167 						wsgi_req->hvec[wsgi_req->var_cnt].iov_len = strsize;
168 
169 						if (wsgi_req->var_cnt < uwsgi.vec_size - (4 + 1)) {
170 							wsgi_req->var_cnt++;
171 						}
172 						else {
173 							uwsgi_log("max vec size reached. skip this var.\n");
174 							return -1;
175 						}
176 						ptrbuf += strsize;
177 					}
178 					else {
179 						uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize);
180 						return -1;
181 					}
182 				}
183 				else {
184 					uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize);
185 					return -1;
186 				}
187 			}
188 		}
189 	}
190 
191 	return 0;
192 }
193 
194 #define uwsgi_proto_key(x, y) memcmp(x, key, y)
195 
uwsgi_proto_check_5(struct wsgi_request * wsgi_req,char * key,char * buf,uint16_t len)196 static int uwsgi_proto_check_5(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
197 
198 	if (!uwsgi_proto_key("HTTPS", 5)) {
199 		wsgi_req->https = buf;
200 		wsgi_req->https_len = len;
201 		return 0;
202 	}
203 
204 	return 0;
205 }
206 
uwsgi_proto_check_9(struct wsgi_request * wsgi_req,char * key,char * buf,uint16_t len)207 static int uwsgi_proto_check_9(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
208 
209 	if (!uwsgi_proto_key("PATH_INFO", 9)) {
210 		wsgi_req->path_info = buf;
211 		wsgi_req->path_info_len = len;
212 		wsgi_req->path_info_pos = wsgi_req->var_cnt + 1;
213 #ifdef UWSGI_DEBUG
214 		uwsgi_debug("PATH_INFO=%.*s\n", wsgi_req->path_info_len, wsgi_req->path_info);
215 #endif
216 		return 0;
217 	}
218 
219 	if (!uwsgi_proto_key("HTTP_HOST", 9)) {
220 		wsgi_req->host = buf;
221 		wsgi_req->host_len = len;
222 #ifdef UWSGI_DEBUG
223 		uwsgi_debug("HTTP_HOST=%.*s\n", wsgi_req->host_len, wsgi_req->host);
224 #endif
225 		return 0;
226 	}
227 
228 	return 0;
229 }
230 
uwsgi_parse_http_range(char * buf,uint16_t len,enum uwsgi_range * parsed,int64_t * from,int64_t * to)231 static void uwsgi_parse_http_range(char *buf, uint16_t len, enum uwsgi_range *parsed, int64_t *from, int64_t *to) {
232 	*parsed = UWSGI_RANGE_INVALID;
233 	*from = 0;
234 	*to = 0;
235 	uint16_t rlen = 0;
236 	uint16_t i;
237 	for(i=0;i<len;i++) {
238 		if (buf[i] == ',') break;
239 		rlen++;
240 	}
241 
242 	// bytes=X-
243 	if (rlen < 8) return;
244 	char *equal = memchr(buf, '=', rlen);
245 	if (!equal) return;
246 	if (equal-buf != 5) return;
247 	if (memcmp(buf, "bytes", 5)) return;
248 	char *range = equal+1;
249 	rlen -= 6;
250 	char *dash = memchr(range, '-', rlen);
251 	if (!dash) return;
252 	if (dash != range) {
253 		*from = uwsgi_str_num(range, dash-range);
254 		if (dash == range+(rlen-1)) {
255 			/* RFC7233 prefix range
256 			 * `bytes=start-` is a same as `byte=start-0x7ffffffffffffff`
257 			 */
258 			*to = INT64_MAX;
259 		} else {
260 			*to = uwsgi_str_num(dash+1, rlen - ((dash+1)-range));
261 		}
262 		if (*to >= *from) {
263 			*parsed = UWSGI_RANGE_PARSED;
264 		} else {
265 			*from = 0;
266 			*to = 0;
267 		}
268 	} else {
269 		/* RFC7233 suffix-byte-range-spec: `bytes=-500` */
270 		*from = -(int64_t)uwsgi_str_num(dash+1, rlen - ((dash+1)-range));
271 		if (*from < 0) {
272 			*to = INT64_MAX;
273 			*parsed = UWSGI_RANGE_PARSED;
274 		}
275 	}
276 }
277 
uwsgi_proto_check_10(struct wsgi_request * wsgi_req,char * key,char * buf,uint16_t len)278 static int uwsgi_proto_check_10(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
279 
280 	if (uwsgi.honour_range && !uwsgi_proto_key("HTTP_IF_RANGE", 13)) {
281 		wsgi_req->if_range = buf;
282 		wsgi_req->if_range_len = len;
283 	}
284 
285 	if (uwsgi.honour_range && !uwsgi_proto_key("HTTP_RANGE", 10)) {
286 		uwsgi_parse_http_range(buf, len, &wsgi_req->range_parsed,
287 				&wsgi_req->range_from, &wsgi_req->range_to);
288 		// set deprecated fields for binary compatibility
289 		wsgi_req->__range_from = (size_t)wsgi_req->range_from;
290 		wsgi_req->__range_to = (size_t)wsgi_req->range_to;
291 		return 0;
292 	}
293 
294 	if (!uwsgi_proto_key("UWSGI_FILE", 10)) {
295 		wsgi_req->file = buf;
296 		wsgi_req->file_len = len;
297 		wsgi_req->dynamic = 1;
298 		return 0;
299 	}
300 
301 	if (!uwsgi_proto_key("UWSGI_HOME", 10)) {
302 		wsgi_req->home = buf;
303 		wsgi_req->home_len = len;
304 		return 0;
305 	}
306 
307 	return 0;
308 }
309 
uwsgi_proto_check_11(struct wsgi_request * wsgi_req,char * key,char * buf,uint16_t len)310 static int uwsgi_proto_check_11(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
311 
312 	if (!uwsgi_proto_key("SCRIPT_NAME", 11)) {
313 		wsgi_req->script_name = buf;
314 		wsgi_req->script_name_len = len;
315 		wsgi_req->script_name_pos = wsgi_req->var_cnt + 1;
316 #ifdef UWSGI_DEBUG
317 		uwsgi_debug("SCRIPT_NAME=%.*s\n", wsgi_req->script_name_len, wsgi_req->script_name);
318 #endif
319 		return 0;
320 	}
321 
322 	if (!uwsgi_proto_key("REQUEST_URI", 11)) {
323 		wsgi_req->uri = buf;
324 		wsgi_req->uri_len = len;
325 		return 0;
326 	}
327 
328 	if (!uwsgi_proto_key("REMOTE_USER", 11)) {
329 		wsgi_req->remote_user = buf;
330 		wsgi_req->remote_user_len = len;
331 		return 0;
332 	}
333 
334 	if (wsgi_req->host_len == 0 && !uwsgi_proto_key("SERVER_NAME", 11)) {
335 		wsgi_req->host = buf;
336 		wsgi_req->host_len = len;
337 #ifdef UWSGI_DEBUG
338 		uwsgi_debug("SERVER_NAME=%.*s\n", wsgi_req->host_len, wsgi_req->host);
339 #endif
340 		return 0;
341 	}
342 
343 	if (wsgi_req->remote_addr_len == 0 && !uwsgi_proto_key("REMOTE_ADDR", 11)) {
344 		wsgi_req->remote_addr = buf;
345                 wsgi_req->remote_addr_len = len;
346 		return 0;
347 	}
348 
349 	if (!uwsgi_proto_key("HTTP_COOKIE", 11)) {
350 		wsgi_req->cookie = buf;
351 		wsgi_req->cookie_len = len;
352 		return 0;
353 	}
354 
355 
356 	if (!uwsgi_proto_key("UWSGI_APPID", 11)) {
357 		wsgi_req->appid = buf;
358 		wsgi_req->appid_len = len;
359 		return 0;
360 	}
361 
362 	if (!uwsgi_proto_key("UWSGI_CHDIR", 11)) {
363 		wsgi_req->chdir = buf;
364 		wsgi_req->chdir_len = len;
365 		return 0;
366 	}
367 
368 	if (!uwsgi_proto_key("HTTP_ORIGIN", 11)) {
369                 wsgi_req->http_origin = buf;
370                 wsgi_req->http_origin_len = len;
371                 return 0;
372         }
373 
374 	return 0;
375 }
376 
uwsgi_proto_check_12(struct wsgi_request * wsgi_req,char * key,char * buf,uint16_t len)377 static int uwsgi_proto_check_12(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
378 	if (!uwsgi_proto_key("QUERY_STRING", 12)) {
379 		wsgi_req->query_string = buf;
380 		wsgi_req->query_string_len = len;
381 		return 0;
382 	}
383 
384 	if (!uwsgi_proto_key("CONTENT_TYPE", 12)) {
385 		wsgi_req->content_type = buf;
386 		wsgi_req->content_type_len = len;
387 		return 0;
388 	}
389 
390 	if (!uwsgi_proto_key("HTTP_REFERER", 12)) {
391                 wsgi_req->referer = buf;
392                 wsgi_req->referer_len = len;
393                 return 0;
394         }
395 
396 	if (!uwsgi_proto_key("UWSGI_SCHEME", 12)) {
397 		wsgi_req->scheme = buf;
398 		wsgi_req->scheme_len = len;
399 		return 0;
400 	}
401 
402 	if (!uwsgi_proto_key("UWSGI_SCRIPT", 12)) {
403 		wsgi_req->script = buf;
404 		wsgi_req->script_len = len;
405 		wsgi_req->dynamic = 1;
406 		return 0;
407 	}
408 
409 	if (!uwsgi_proto_key("UWSGI_MODULE", 12)) {
410 		wsgi_req->module = buf;
411 		wsgi_req->module_len = len;
412 		wsgi_req->dynamic = 1;
413 		return 0;
414 	}
415 
416 	if (!uwsgi_proto_key("UWSGI_PYHOME", 12)) {
417 		wsgi_req->home = buf;
418 		wsgi_req->home_len = len;
419 		return 0;
420 	}
421 
422 	if (!uwsgi_proto_key("UWSGI_SETENV", 12)) {
423 		char *env_value = memchr(buf, '=', len);
424 		if (env_value) {
425 			env_value[0] = 0;
426 			env_value = uwsgi_concat2n(env_value + 1, len - ((env_value + 1) - buf), "", 0);
427 			if (setenv(buf, env_value, 1)) {
428 				uwsgi_error("setenv()");
429 			}
430 			free(env_value);
431 		}
432 		return 0;
433 	}
434 	return 0;
435 }
436 
uwsgi_proto_check_13(struct wsgi_request * wsgi_req,char * key,char * buf,uint16_t len)437 static int uwsgi_proto_check_13(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
438 	if (!uwsgi_proto_key("DOCUMENT_ROOT", 13)) {
439 		wsgi_req->document_root = buf;
440 		wsgi_req->document_root_len = len;
441 		return 0;
442 	}
443 	return 0;
444 }
445 
uwsgi_proto_check_14(struct wsgi_request * wsgi_req,char * key,char * buf,uint16_t len)446 static int uwsgi_proto_check_14(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
447 	if (!uwsgi_proto_key("REQUEST_METHOD", 14)) {
448 		wsgi_req->method = buf;
449 		wsgi_req->method_len = len;
450 		return 0;
451 	}
452 
453 	if (!uwsgi_proto_key("CONTENT_LENGTH", 14)) {
454 		wsgi_req->post_cl = get_content_length(buf, len);
455 		if (uwsgi.limit_post) {
456 			if (wsgi_req->post_cl > uwsgi.limit_post) {
457 				uwsgi_log("Invalid (too big) CONTENT_LENGTH. skip.\n");
458 				return -1;
459 			}
460 		}
461 		return 0;
462 	}
463 
464 	if (!uwsgi_proto_key("UWSGI_POSTFILE", 14)) {
465 		char *postfile = uwsgi_concat2n(buf, len, "", 0);
466 		wsgi_req->post_file = fopen(postfile, "r");
467 		if (!wsgi_req->post_file) {
468 			uwsgi_error_open(postfile);
469 		}
470 		free(postfile);
471 		return 0;
472 	}
473 
474 	if (!uwsgi_proto_key("UWSGI_CALLABLE", 14)) {
475 		wsgi_req->callable = buf;
476 		wsgi_req->callable_len = len;
477 		wsgi_req->dynamic = 1;
478 		return 0;
479 	}
480 
481 	return 0;
482 }
483 
484 
uwsgi_proto_check_15(struct wsgi_request * wsgi_req,char * key,char * buf,uint16_t len)485 static int uwsgi_proto_check_15(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
486 	if (!uwsgi_proto_key("SERVER_PROTOCOL", 15)) {
487 		wsgi_req->protocol = buf;
488 		wsgi_req->protocol_len = len;
489 		return 0;
490 	}
491 
492 	if (!uwsgi_proto_key("HTTP_USER_AGENT", 15)) {
493 		wsgi_req->user_agent = buf;
494 		wsgi_req->user_agent_len = len;
495 		return 0;
496 	}
497 
498 	if (uwsgi.caches && !uwsgi_proto_key("UWSGI_CACHE_GET", 15)) {
499 		wsgi_req->cache_get = buf;
500 		wsgi_req->cache_get_len = len;
501 		return 0;
502 	}
503 
504 	return 0;
505 }
506 
uwsgi_proto_check_18(struct wsgi_request * wsgi_req,char * key,char * buf,uint16_t len)507 static int uwsgi_proto_check_18(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
508 	if (!uwsgi_proto_key("HTTP_AUTHORIZATION", 18)) {
509 		wsgi_req->authorization = buf;
510 		wsgi_req->authorization_len = len;
511 		return 0;
512 	}
513 
514 	if (!uwsgi_proto_key("UWSGI_TOUCH_RELOAD", 18)) {
515 		wsgi_req->touch_reload = buf;
516 		wsgi_req->touch_reload_len = len;
517 		return 0;
518 	}
519 
520 	return 0;
521 }
522 
523 
uwsgi_proto_check_20(struct wsgi_request * wsgi_req,char * key,char * buf,uint16_t len)524 static int uwsgi_proto_check_20(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
525 	if (uwsgi.logging_options.log_x_forwarded_for && !uwsgi_proto_key("HTTP_X_FORWARDED_FOR", 20)) {
526 		wsgi_req->remote_addr = buf;
527 		wsgi_req->remote_addr_len = len;
528 		return 0;
529 	}
530 
531 	if (!uwsgi_proto_key("HTTP_X_FORWARDED_SSL", 20)) {
532 		wsgi_req->https = buf;
533                 wsgi_req->https_len = len;
534 	}
535 
536 	if (!uwsgi_proto_key("HTTP_ACCEPT_ENCODING", 20)) {
537 		wsgi_req->encoding = buf;
538 		wsgi_req->encoding_len = len;
539 		return 0;
540 	}
541 
542 	return 0;
543 }
544 
uwsgi_proto_check_22(struct wsgi_request * wsgi_req,char * key,char * buf,uint16_t len)545 static int uwsgi_proto_check_22(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
546 	if (!uwsgi_proto_key("HTTP_IF_MODIFIED_SINCE", 22)) {
547 		wsgi_req->if_modified_since = buf;
548 		wsgi_req->if_modified_since_len = len;
549 		return 0;
550 	}
551 
552 	if (!uwsgi_proto_key("HTTP_SEC_WEBSOCKET_KEY", 22)) {
553 		wsgi_req->http_sec_websocket_key = buf;
554 		wsgi_req->http_sec_websocket_key_len = len;
555 		return 0;
556 	}
557 
558 	if (!uwsgi_proto_key("HTTP_X_FORWARDED_PROTO", 22)) {
559                 wsgi_req->scheme = buf;
560                 wsgi_req->scheme_len = len;
561         }
562 
563 	return 0;
564 }
565 
uwsgi_proto_check_27(struct wsgi_request * wsgi_req,char * key,char * buf,uint16_t len)566 static int uwsgi_proto_check_27(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
567 
568         if (!uwsgi_proto_key("HTTP_SEC_WEBSOCKET_PROTOCOL", 27)) {
569                 wsgi_req->http_sec_websocket_protocol = buf;
570                 wsgi_req->http_sec_websocket_protocol_len = len;
571                 return 0;
572         }
573 
574         return 0;
575 }
576 
577 
uwsgi_proto_hooks_setup()578 void uwsgi_proto_hooks_setup() {
579 	int i = 0;
580 	for(i=0;i<UWSGI_PROTO_MAX_CHECK;i++) {
581 		uwsgi.proto_hooks[i] = NULL;
582 	}
583 
584 	uwsgi.proto_hooks[5] = uwsgi_proto_check_5;
585 	uwsgi.proto_hooks[9] = uwsgi_proto_check_9;
586 	uwsgi.proto_hooks[10] = uwsgi_proto_check_10;
587 	uwsgi.proto_hooks[11] = uwsgi_proto_check_11;
588 	uwsgi.proto_hooks[12] = uwsgi_proto_check_12;
589 	uwsgi.proto_hooks[13] = uwsgi_proto_check_13;
590 	uwsgi.proto_hooks[14] = uwsgi_proto_check_14;
591 	uwsgi.proto_hooks[15] = uwsgi_proto_check_15;
592 	uwsgi.proto_hooks[18] = uwsgi_proto_check_18;
593 	uwsgi.proto_hooks[20] = uwsgi_proto_check_20;
594 	uwsgi.proto_hooks[22] = uwsgi_proto_check_22;
595 	uwsgi.proto_hooks[27] = uwsgi_proto_check_27;
596 }
597 
598 
uwsgi_parse_vars(struct wsgi_request * wsgi_req)599 int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
600 
601 	char *buffer = wsgi_req->buffer;
602 
603 	char *ptrbuf, *bufferend;
604 
605 	uint16_t strsize = 0;
606 	struct uwsgi_dyn_dict *udd;
607 
608 	ptrbuf = buffer;
609 	bufferend = ptrbuf + wsgi_req->uh->pktsize;
610 	int i;
611 
612 	/* set an HTTP 500 status as default */
613 	wsgi_req->status = 500;
614 
615 	// skip if already parsed
616 	if (wsgi_req->parsed)
617 		return 0;
618 
619 	// has the protocol already parsed the request ?
620 	if (wsgi_req->uri_len > 0) {
621 		wsgi_req->parsed = 1;
622 		i = uwsgi_simple_parse_vars(wsgi_req, ptrbuf, bufferend);
623 		if (i == 0)
624 			goto next;
625 		return i;
626 	}
627 
628 	wsgi_req->parsed = 1;
629 	wsgi_req->script_name_pos = -1;
630 	wsgi_req->path_info_pos = -1;
631 
632 	while (ptrbuf < bufferend) {
633 		if (ptrbuf + 2 < bufferend) {
634 			memcpy(&strsize, ptrbuf, 2);
635 #ifdef __BIG_ENDIAN__
636 			strsize = uwsgi_swap16(strsize);
637 #endif
638 			/* key cannot be null */
639 			if (!strsize) {
640 				uwsgi_log("uwsgi key cannot be null. skip this var.\n");
641 				return -1;
642 			}
643 
644 			ptrbuf += 2;
645 			if (ptrbuf + strsize < bufferend) {
646 				// var key
647 				wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptrbuf;
648 				wsgi_req->hvec[wsgi_req->var_cnt].iov_len = strsize;
649 				ptrbuf += strsize;
650 				// value can be null (even at the end) so use <=
651 				if (ptrbuf + 2 <= bufferend) {
652 					memcpy(&strsize, ptrbuf, 2);
653 #ifdef __BIG_ENDIAN__
654 					strsize = uwsgi_swap16(strsize);
655 #endif
656 					ptrbuf += 2;
657 					if (ptrbuf + strsize <= bufferend) {
658 						if (wsgi_req->hvec[wsgi_req->var_cnt].iov_len > UWSGI_PROTO_MIN_CHECK &&
659 							wsgi_req->hvec[wsgi_req->var_cnt].iov_len < UWSGI_PROTO_MAX_CHECK &&
660 								uwsgi.proto_hooks[wsgi_req->hvec[wsgi_req->var_cnt].iov_len]) {
661 							if (uwsgi.proto_hooks[wsgi_req->hvec[wsgi_req->var_cnt].iov_len](wsgi_req, wsgi_req->hvec[wsgi_req->var_cnt].iov_base, ptrbuf, strsize)) {
662 								return -1;
663 							}
664 						}
665 						//uwsgi_log("uwsgi %.*s = %.*s\n", wsgi_req->hvec[wsgi_req->var_cnt].iov_len, wsgi_req->hvec[wsgi_req->var_cnt].iov_base, strsize, ptrbuf);
666 
667 						if (wsgi_req->var_cnt < uwsgi.vec_size - (4 + 1)) {
668 							wsgi_req->var_cnt++;
669 						}
670 						else {
671 							uwsgi_log("max vec size reached. skip this var.\n");
672 							return -1;
673 						}
674 						// var value
675 						wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptrbuf;
676 						wsgi_req->hvec[wsgi_req->var_cnt].iov_len = strsize;
677 						//uwsgi_log("%.*s = %.*s\n", wsgi_req->hvec[wsgi_req->var_cnt-1].iov_len, wsgi_req->hvec[wsgi_req->var_cnt-1].iov_base, wsgi_req->hvec[wsgi_req->var_cnt].iov_len, wsgi_req->hvec[wsgi_req->var_cnt].iov_base);
678 						if (wsgi_req->var_cnt < uwsgi.vec_size - (4 + 1)) {
679 							wsgi_req->var_cnt++;
680 						}
681 						else {
682 							uwsgi_log("max vec size reached. skip this var.\n");
683 							return -1;
684 						}
685 						ptrbuf += strsize;
686 					}
687 					else {
688 						uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize);
689 						return -1;
690 					}
691 				}
692 				else {
693 					uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize);
694 					return -1;
695 				}
696 			}
697 		}
698 		else {
699 			uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize);
700 			return -1;
701 		}
702 	}
703 
704 next:
705 
706 	// manage post buffering (if needed as post_file could be created before)
707 	if (uwsgi.post_buffering > 0 && !wsgi_req->post_file) {
708 		// read to disk if post_cl > post_buffering (it will eventually do upload progress...)
709 		if (wsgi_req->post_cl >= uwsgi.post_buffering) {
710 			if (uwsgi_postbuffer_do_in_disk(wsgi_req)) {
711 				return -1;
712 			}
713 		}
714 		// on tiny post use memory
715 		else {
716 			if (uwsgi_postbuffer_do_in_mem(wsgi_req)) {
717 				return -1;
718 			}
719 		}
720 	}
721 
722 
723 	// check if data are available in the local cache
724 	if (wsgi_req->cache_get_len > 0) {
725 		uint64_t cache_value_size;
726 		char *cache_value = uwsgi_cache_magic_get(wsgi_req->cache_get, wsgi_req->cache_get_len, &cache_value_size, NULL, NULL);
727 		if (cache_value && cache_value_size > 0) {
728 			uwsgi_response_write_body_do(wsgi_req, cache_value, cache_value_size);
729 			free(cache_value);
730 			return -1;
731 		}
732 	}
733 
734 	if (uwsgi.check_cache && wsgi_req->uri_len && wsgi_req->method_len == 3 && wsgi_req->method[0] == 'G' && wsgi_req->method[1] == 'E' && wsgi_req->method[2] == 'T') {
735 
736 		uint64_t cache_value_size;
737 		char *cache_value = uwsgi_cache_magic_get(wsgi_req->uri, wsgi_req->uri_len, &cache_value_size, NULL, NULL);
738 		if (cache_value && cache_value_size > 0) {
739 			uwsgi_response_write_body_do(wsgi_req, cache_value, cache_value_size);
740 			free(cache_value);
741 			return -1;
742 		}
743 	}
744 
745 	if (uwsgi.manage_script_name) {
746 		if (uwsgi_apps_cnt > 0 && wsgi_req->path_info_len > 1 && wsgi_req->path_info_pos != -1) {
747 			// starts with 1 as the 0 app is the default (/) one
748 			int best_found = 0;
749 			char *orig_path_info = wsgi_req->path_info;
750 			int orig_path_info_len = wsgi_req->path_info_len;
751 			// if SCRIPT_NAME is not allocated, add a slot for it
752 			if (wsgi_req->script_name_pos == -1) {
753 				if (wsgi_req->var_cnt >= uwsgi.vec_size - (4 + 2)) {
754 					uwsgi_log("max vec size reached. skip this var.\n");
755 					return -1;
756 				}
757 				wsgi_req->hvec[wsgi_req->var_cnt].iov_base = "SCRIPT_NAME";
758 				wsgi_req->hvec[wsgi_req->var_cnt].iov_len = 11;
759 				wsgi_req->var_cnt++;
760 				wsgi_req->script_name_pos = wsgi_req->var_cnt;
761 				wsgi_req->hvec[wsgi_req->script_name_pos].iov_base = "";
762 				wsgi_req->hvec[wsgi_req->script_name_pos].iov_len = 0;
763 				wsgi_req->var_cnt++;
764 			}
765 
766 			for (i = 0; i < uwsgi_apps_cnt; i++) {
767 				char* mountpoint = uwsgi_apps[i].mountpoint;
768 				int mountpoint_len = uwsgi_apps[i].mountpoint_len;
769 
770 				// Ignore trailing mountpoint slashes
771 				if (mountpoint_len > 0 && mountpoint[mountpoint_len - 1] == '/') {
772 					mountpoint_len -= 1;
773 				}
774 
775 				//uwsgi_log("app mountpoint = %.*s\n", uwsgi_apps[i].mountpoint_len, uwsgi_apps[i].mountpoint);
776 
777 				// Check if mountpoint could be a possible candidate
778 				if (orig_path_info_len < mountpoint_len || // it should be shorter than or equal to path_info
779 					mountpoint_len <= best_found || // it should be better than the previous found
780 					// should have the same prefix of path_info
781 					uwsgi_startswith(orig_path_info, mountpoint, mountpoint_len) ||
782 					// and should not be "misleading"
783 					(orig_path_info_len > mountpoint_len && orig_path_info[mountpoint_len] != '/' )) {
784 					continue;
785 				}
786 
787 				best_found = mountpoint_len;
788 				wsgi_req->script_name = uwsgi_apps[i].mountpoint;
789 				wsgi_req->script_name_len = uwsgi_apps[i].mountpoint_len;
790 				wsgi_req->path_info = orig_path_info + wsgi_req->script_name_len;
791 				wsgi_req->path_info_len = orig_path_info_len - wsgi_req->script_name_len;
792 
793 				wsgi_req->hvec[wsgi_req->script_name_pos].iov_base = wsgi_req->script_name;
794 				wsgi_req->hvec[wsgi_req->script_name_pos].iov_len = wsgi_req->script_name_len;
795 
796 				wsgi_req->hvec[wsgi_req->path_info_pos].iov_base = wsgi_req->path_info;
797 				wsgi_req->hvec[wsgi_req->path_info_pos].iov_len = wsgi_req->path_info_len;
798 #ifdef UWSGI_DEBUG
799 				uwsgi_log("managed SCRIPT_NAME = %.*s PATH_INFO = %.*s\n", wsgi_req->script_name_len, wsgi_req->script_name, wsgi_req->path_info_len, wsgi_req->path_info);
800 #endif
801 			}
802 		}
803 	}
804 
805 
806 	/* CHECK FOR STATIC FILES */
807 
808 	// skip extensions
809 	struct uwsgi_string_list *sse = uwsgi.static_skip_ext;
810 	while (sse) {
811 		if (wsgi_req->path_info_len >= sse->len) {
812 			if (!uwsgi_strncmp(wsgi_req->path_info + (wsgi_req->path_info_len - sse->len), sse->len, sse->value, sse->len)) {
813 				return 0;
814 			}
815 		}
816 		sse = sse->next;
817 	}
818 
819 	// check if a file named uwsgi.check_static+env['PATH_INFO'] exists
820 	udd = uwsgi.check_static;
821 	while (udd) {
822 		// need to build the path ?
823 		if (udd->value == NULL) {
824 			if (uwsgi.threads > 1)
825 				pthread_mutex_lock(&uwsgi.lock_static);
826 			udd->value = uwsgi_malloc(PATH_MAX + 1);
827 			if (!realpath(udd->key, udd->value)) {
828 				free(udd->value);
829 				udd->value = NULL;
830 			}
831 			if (uwsgi.threads > 1)
832 				pthread_mutex_unlock(&uwsgi.lock_static);
833 			if (!udd->value)
834 				goto nextcs;
835 			udd->vallen = strlen(udd->value);
836 		}
837 
838 		if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info, wsgi_req->path_info_len, 0)) {
839 			return -1;
840 		}
841 nextcs:
842 		udd = udd->next;
843 	}
844 
845 	// check static-map
846 	udd = uwsgi.static_maps;
847 	while (udd) {
848 #ifdef UWSGI_DEBUG
849 		uwsgi_log("checking for %.*s <-> %.*s %.*s\n", (int)wsgi_req->path_info_len, wsgi_req->path_info, (int)udd->keylen, udd->key, (int) udd->vallen, udd->value);
850 #endif
851 		if (udd->status == 0) {
852 			if (uwsgi.threads > 1)
853 				pthread_mutex_lock(&uwsgi.lock_static);
854 			char *real_docroot = uwsgi_malloc(PATH_MAX + 1);
855 			if (!realpath(udd->value, real_docroot)) {
856 				free(real_docroot);
857 				real_docroot = NULL;
858 				udd->value = NULL;
859 			}
860 			if (uwsgi.threads > 1)
861 				pthread_mutex_unlock(&uwsgi.lock_static);
862 			if (!real_docroot)
863 				goto nextsm;
864 			udd->value = real_docroot;
865 			udd->vallen = strlen(udd->value);
866 			udd->status = 1 + uwsgi_is_file(real_docroot);
867 		}
868 
869 		if (!uwsgi_starts_with(wsgi_req->path_info, wsgi_req->path_info_len, udd->key, udd->keylen)) {
870 			if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info + udd->keylen, wsgi_req->path_info_len - udd->keylen, udd->status - 1)) {
871 				return -1;
872 			}
873 		}
874 nextsm:
875 		udd = udd->next;
876 	}
877 
878 	// check for static_maps in append mode
879 	udd = uwsgi.static_maps2;
880 	while (udd) {
881 #ifdef UWSGI_DEBUG
882 		uwsgi_log("checking for %.*s <-> %.*s\n", wsgi_req->path_info_len, wsgi_req->path_info, udd->keylen, udd->key);
883 #endif
884 		if (udd->status == 0) {
885 			if (uwsgi.threads > 1)
886 				pthread_mutex_lock(&uwsgi.lock_static);
887 			char *real_docroot = uwsgi_malloc(PATH_MAX + 1);
888 			if (!realpath(udd->value, real_docroot)) {
889 				free(real_docroot);
890 				real_docroot = NULL;
891 				udd->value = NULL;
892 			}
893 			if (uwsgi.threads > 1)
894 				pthread_mutex_unlock(&uwsgi.lock_static);
895 			if (!real_docroot)
896 				goto nextsm2;
897 			udd->value = real_docroot;
898 			udd->vallen = strlen(udd->value);
899 			udd->status = 1 + uwsgi_is_file(real_docroot);
900 		}
901 
902 		if (!uwsgi_starts_with(wsgi_req->path_info, wsgi_req->path_info_len, udd->key, udd->keylen)) {
903 			if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info, wsgi_req->path_info_len, udd->status - 1)) {
904 				return -1;
905 			}
906 		}
907 nextsm2:
908 		udd = udd->next;
909 	}
910 
911 
912 	// finally check for docroot
913 	if (uwsgi.check_static_docroot && wsgi_req->document_root_len > 0) {
914 		char *real_docroot = uwsgi_expand_path(wsgi_req->document_root, wsgi_req->document_root_len, NULL);
915 		if (!real_docroot) {
916 			return -1;
917 		}
918 		if (!uwsgi_file_serve(wsgi_req, real_docroot, strlen(real_docroot), wsgi_req->path_info, wsgi_req->path_info_len, 0)) {
919 			free(real_docroot);
920 			return -1;
921 		}
922 		free(real_docroot);
923 	}
924 
925 	return 0;
926 }
927 
uwsgi_hooked_parse(char * buffer,size_t len,void (* hook)(char *,uint16_t,char *,uint16_t,void *),void * data)928 int uwsgi_hooked_parse(char *buffer, size_t len, void (*hook) (char *, uint16_t, char *, uint16_t, void *), void *data) {
929 
930 	char *ptrbuf, *bufferend;
931 	uint16_t keysize = 0, valsize = 0;
932 	char *key;
933 
934 	ptrbuf = buffer;
935 	bufferend = buffer + len;
936 
937 	while (ptrbuf < bufferend) {
938 		if (ptrbuf + 2 >= bufferend)
939 			return -1;
940 		memcpy(&keysize, ptrbuf, 2);
941 #ifdef __BIG_ENDIAN__
942 		keysize = uwsgi_swap16(keysize);
943 #endif
944 		/* key cannot be null */
945 		if (!keysize)
946 			return -1;
947 
948 		ptrbuf += 2;
949 		if (ptrbuf + keysize > bufferend)
950 			return -1;
951 
952 		// key
953 		key = ptrbuf;
954 		ptrbuf += keysize;
955 		// value can be null
956 		if (ptrbuf + 2 > bufferend)
957 			return -1;
958 
959 		memcpy(&valsize, ptrbuf, 2);
960 #ifdef __BIG_ENDIAN__
961 		valsize = uwsgi_swap16(valsize);
962 #endif
963 		ptrbuf += 2;
964 		if (ptrbuf + valsize > bufferend)
965 			return -1;
966 
967 		// now call the hook
968 		hook(key, keysize, ptrbuf, valsize, data);
969 		ptrbuf += valsize;
970 	}
971 
972 	return 0;
973 
974 }
975 
uwsgi_hooked_parse_array(char * buffer,size_t len,void (* hook)(uint16_t,char *,uint16_t,void *),void * data)976 int uwsgi_hooked_parse_array(char *buffer, size_t len, void (*hook) (uint16_t, char *, uint16_t, void *), void *data) {
977 
978         char *ptrbuf, *bufferend;
979         uint16_t valsize = 0;
980         char *value;
981 	uint16_t pos = 0;
982 
983         ptrbuf = buffer;
984         bufferend = buffer + len;
985 
986         while (ptrbuf < bufferend) {
987                 if (ptrbuf + 2 > bufferend)
988                         return -1;
989                 memcpy(&valsize, ptrbuf, 2);
990 #ifdef __BIG_ENDIAN__
991                 valsize = uwsgi_swap16(valsize);
992 #endif
993                 ptrbuf += 2;
994                 if (ptrbuf + valsize > bufferend)
995                         return -1;
996 
997                 // key
998                 value = ptrbuf;
999                 // now call the hook
1000                 hook(pos, value, valsize, data);
1001                 ptrbuf += valsize;
1002 		pos++;
1003         }
1004 
1005         return 0;
1006 
1007 }
1008 
1009 
1010 // this functions transform a raw HTTP response to a uWSGI-managed response
uwsgi_blob_to_response(struct wsgi_request * wsgi_req,char * body,size_t len)1011 int uwsgi_blob_to_response(struct wsgi_request *wsgi_req, char *body, size_t len) {
1012 	char *line = body;
1013 	size_t line_len = 0;
1014 	size_t i;
1015 	int status_managed = 0;
1016 	for(i=0;i<len;i++) {
1017 		if (body[i] == '\n') {
1018 			// invalid line
1019 			if (line_len < 1) {
1020 				return -1;
1021 			}
1022 			if (line[line_len-1] != '\r') {
1023 				return -1;
1024 			}
1025 			// end of the headers
1026 			if (line_len == 1) {
1027 				break;
1028 			}
1029 
1030 			if (status_managed) {
1031 				char *colon = memchr(line, ':', line_len-1);
1032 				if (!colon) return -1;
1033 				if (colon[1] != ' ') return -1;
1034 				if (uwsgi_response_add_header(wsgi_req, line, colon-line, colon+2, (line_len-1) - ((colon+2)-line))) return -1;
1035 			}
1036 			else {
1037 				char *space = memchr(line, ' ', line_len-1);
1038 				if (!space) return -1;
1039 				if ((line_len-1) - ((space+1)-line) < 3) return -1;
1040 				if (uwsgi_response_prepare_headers(wsgi_req, space+1, (line_len-1) - ((space+1)-line))) return -1;
1041 				status_managed = 1;
1042 			}
1043 			line = NULL;
1044 			line_len = 0;
1045 		}
1046 		else {
1047 			if (!line) {
1048 				line = body + i;
1049 			}
1050 			line_len++;
1051 		}
1052 	}
1053 
1054 	if ((i+1) < len) {
1055 		if (uwsgi_response_write_body_do(wsgi_req, body + (i + 1), len-(i+1))) {
1056 			return -1;
1057 		}
1058 	}
1059 
1060 	return 0;
1061 }
1062 
1063 /*
1064 
1065 the following functions need to take in account that POST data could be already available in wsgi_req->buffer (generally when uwsgi protocol is in use)
1066 
1067 In such a case, allocate a proto_parser_buf and move data there
1068 
1069 */
1070 
uwsgi_req_append(struct wsgi_request * wsgi_req,char * key,uint16_t keylen,char * val,uint16_t vallen)1071 char *uwsgi_req_append(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, char *val, uint16_t vallen) {
1072 
1073 	if (!wsgi_req->proto_parser_buf) {
1074 		if (wsgi_req->proto_parser_remains > 0) {
1075 			wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_remains);
1076 			memcpy(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains);
1077 			wsgi_req->proto_parser_remains_buf = wsgi_req->proto_parser_buf;
1078 		}
1079 	}
1080 
1081 	if ((wsgi_req->uh->pktsize + (2 + keylen + 2 + vallen)) > uwsgi.buffer_size) {
1082 		uwsgi_log("not enough buffer space to add %.*s variable, consider increasing it with the --buffer-size option\n", keylen, key);
1083 		return NULL;
1084 	}
1085 
1086 	if (wsgi_req->var_cnt >= uwsgi.vec_size - (4 + 2)) {
1087         	uwsgi_log("max vec size reached. skip this header.\n");
1088 		return NULL;
1089 	}
1090 
1091 	char *ptr = wsgi_req->buffer + wsgi_req->uh->pktsize;
1092 
1093 	*ptr++ = (uint8_t) (keylen & 0xff);
1094 	*ptr++ = (uint8_t) ((keylen >> 8) & 0xff);
1095 
1096 	memcpy(ptr, key, keylen);
1097 	wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptr;
1098         wsgi_req->hvec[wsgi_req->var_cnt].iov_len = keylen;
1099 	wsgi_req->var_cnt++;
1100 	ptr += keylen;
1101 
1102 
1103 
1104 	*ptr++ = (uint8_t) (vallen & 0xff);
1105 	*ptr++ = (uint8_t) ((vallen >> 8) & 0xff);
1106 
1107 	memcpy(ptr, val, vallen);
1108 	wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptr;
1109         wsgi_req->hvec[wsgi_req->var_cnt].iov_len = vallen;
1110 	wsgi_req->var_cnt++;
1111 
1112 	wsgi_req->uh->pktsize += (2 + keylen + 2 + vallen);
1113 
1114 	return ptr;
1115 }
1116 
uwsgi_req_append_path_info_with_index(struct wsgi_request * wsgi_req,char * index,uint16_t index_len)1117 int uwsgi_req_append_path_info_with_index(struct wsgi_request *wsgi_req, char *index, uint16_t index_len) {
1118 
1119 	if (!wsgi_req->proto_parser_buf) {
1120                 if (wsgi_req->proto_parser_remains > 0) {
1121                         wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_remains);
1122                         memcpy(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains);
1123                         wsgi_req->proto_parser_remains_buf = wsgi_req->proto_parser_buf;
1124                 }
1125         }
1126 
1127 	uint8_t need_slash = 0;
1128 	if (wsgi_req->path_info_len > 0) {
1129 		if (wsgi_req->path_info[wsgi_req->path_info_len-1] != '/') {
1130 			need_slash = 1;
1131 		}
1132 	}
1133 
1134 	wsgi_req->path_info_len += need_slash + index_len;
1135 
1136 	// 2 + 9 + 2
1137 	if ((wsgi_req->uh->pktsize + (13 + wsgi_req->path_info_len)) > uwsgi.buffer_size) {
1138                 uwsgi_log("not enough buffer space to transform the PATH_INFO variable, consider increasing it with the --buffer-size option\n");
1139                 return -1;
1140         }
1141 
1142 	if (wsgi_req->var_cnt >= uwsgi.vec_size - (4 + 2)) {
1143                 uwsgi_log("max vec size reached for PATH_INFO + index. skip this request.\n");
1144                 return -1;
1145         }
1146 
1147 	uint16_t keylen = 9;
1148 	char *ptr = wsgi_req->buffer + wsgi_req->uh->pktsize;
1149 	*ptr++ = (uint8_t) (keylen & 0xff);
1150         *ptr++ = (uint8_t) ((keylen >> 8) & 0xff);
1151 
1152 	memcpy(ptr, "PATH_INFO", keylen);
1153 	wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptr;
1154 	wsgi_req->hvec[wsgi_req->var_cnt].iov_len = keylen;
1155 	wsgi_req->var_cnt++;
1156         ptr += keylen;
1157 
1158 	*ptr++ = (uint8_t) (wsgi_req->path_info_len & 0xff);
1159         *ptr++ = (uint8_t) ((wsgi_req->path_info_len >> 8) & 0xff);
1160 
1161 	char *new_path_info = ptr;
1162 
1163 	memcpy(ptr, wsgi_req->path_info, wsgi_req->path_info_len - (need_slash + index_len));
1164 	ptr+=wsgi_req->path_info_len - (need_slash + index_len);
1165 	if (need_slash) {
1166 		*ptr ++= '/';
1167 	}
1168 	memcpy(ptr, index, index_len);
1169 
1170 	wsgi_req->hvec[wsgi_req->var_cnt].iov_base = new_path_info;
1171         wsgi_req->hvec[wsgi_req->var_cnt].iov_len = wsgi_req->path_info_len;
1172         wsgi_req->var_cnt++;
1173 
1174 	wsgi_req->uh->pktsize += 13 + wsgi_req->path_info_len;
1175 	wsgi_req->path_info = new_path_info;
1176 
1177 	return 0;
1178 }
1179