xref: /lighttpd1.4/src/http-header-glue.c (revision 49e9f0ac)
1 #include "first.h"
2 
3 #include "base.h"
4 #include "array.h"
5 #include "buffer.h"
6 #include "fdevent.h"
7 #include "log.h"
8 #include "etag.h"
9 #include "http_chunk.h"
10 #include "http_header.h"
11 #include "response.h"
12 #include "sock_addr.h"
13 #include "stat_cache.h"
14 
15 #include <stdlib.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 
20 #include <time.h>
21 
22 #include "sys-strings.h"
23 #include "sys-socket.h"
24 #include <unistd.h>
25 
26 
27 int http_response_buffer_append_authority(server *srv, connection *con, buffer *o) {
28 	if (!buffer_string_is_empty(con->uri.authority)) {
29 		buffer_append_string_buffer(o, con->uri.authority);
30 	} else {
31 		/* get the name of the currently connected socket */
32 		sock_addr our_addr;
33 		socklen_t our_addr_len;
34 
35 		our_addr.plain.sa_family = 0;
36 		our_addr_len = sizeof(our_addr);
37 
38 		if (-1 == getsockname(con->fd, (struct sockaddr *)&our_addr, &our_addr_len)
39 		    || our_addr_len > (socklen_t)sizeof(our_addr)) {
40 			con->http_status = 500;
41 			log_error_write(srv, __FILE__, __LINE__, "ss",
42 					"can't get sockname", strerror(errno));
43 			return -1;
44 		}
45 
46 		if (our_addr.plain.sa_family == AF_INET
47 		    && our_addr.ipv4.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
48 			static char lhost[32];
49 			static size_t lhost_len = 0;
50 			if (0 != lhost_len) {
51 				buffer_append_string_len(o, lhost, lhost_len);
52 			}
53 			else {
54 				size_t olen = buffer_string_length(o);
55 				if (0 == sock_addr_nameinfo_append_buffer(srv, o, &our_addr)) {
56 					lhost_len = buffer_string_length(o) - olen;
57 					if (lhost_len < sizeof(lhost)) {
58 						memcpy(lhost, o->ptr+olen, lhost_len+1); /*(+1 for '\0')*/
59 					}
60 					else {
61 						lhost_len = 0;
62 					}
63 				}
64 				else {
65 					lhost_len = sizeof("localhost")-1;
66 					memcpy(lhost, "localhost", lhost_len+1); /*(+1 for '\0')*/
67 					buffer_append_string_len(o, lhost, lhost_len);
68 				}
69 			}
70 		} else if (!buffer_string_is_empty(con->server_name)) {
71 			buffer_append_string_buffer(o, con->server_name);
72 		} else
73 		/* Lookup name: secondly try to get hostname for bind address */
74 		if (0 != sock_addr_nameinfo_append_buffer(srv, o, &our_addr)) {
75 			con->http_status = 500;
76 			return -1;
77 		}
78 
79 		{
80 			unsigned short listen_port = sock_addr_get_port(&our_addr);
81 			unsigned short default_port = 80;
82 			if (buffer_is_equal_string(con->uri.scheme, CONST_STR_LEN("https"))) {
83 				default_port = 443;
84 			}
85 			if (0 == listen_port) listen_port = srv->srvconf.port;
86 			if (default_port != listen_port) {
87 				buffer_append_string_len(o, CONST_STR_LEN(":"));
88 				buffer_append_int(o, listen_port);
89 			}
90 		}
91 	}
92 	return 0;
93 }
94 
95 int http_response_redirect_to_directory(server *srv, connection *con, int status) {
96 	buffer *o = srv->tmp_buf;
97 	buffer_copy_buffer(o, con->uri.scheme);
98 	buffer_append_string_len(o, CONST_STR_LEN("://"));
99 	if (0 != http_response_buffer_append_authority(srv, con, o)) {
100 		return -1;
101 	}
102 	buffer_append_string_encoded(o, CONST_BUF_LEN(con->uri.path), ENCODING_REL_URI);
103 	buffer_append_string_len(o, CONST_STR_LEN("/"));
104 	if (!buffer_string_is_empty(con->uri.query)) {
105 		buffer_append_string_len(o, CONST_STR_LEN("?"));
106 		buffer_append_string_buffer(o, con->uri.query);
107 	}
108 
109 	if (status >= 300) {
110 		http_header_response_set(con, HTTP_HEADER_LOCATION, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
111 		con->http_status = status;
112 		con->file_finished = 1;
113 	}
114 	else {
115 		http_header_response_set(con, HTTP_HEADER_CONTENT_LOCATION, CONST_STR_LEN("Content-Location"), CONST_BUF_LEN(o));
116 	}
117 
118 	return 0;
119 }
120 
121 buffer * strftime_cache_get(server *srv, time_t last_mod) {
122 	static int i;
123 	struct tm *tm;
124 
125 	for (int j = 0; j < FILE_CACHE_MAX; ++j) {
126 		if (srv->mtime_cache[j].mtime == last_mod)
127 			return srv->mtime_cache[j].str; /* found cache-entry */
128 	}
129 
130 	if (++i == FILE_CACHE_MAX) {
131 		i = 0;
132 	}
133 
134 	srv->mtime_cache[i].mtime = last_mod;
135 	tm = gmtime(&(srv->mtime_cache[i].mtime));
136 	buffer_clear(srv->mtime_cache[i].str);
137 	buffer_append_strftime(srv->mtime_cache[i].str, "%a, %d %b %Y %H:%M:%S GMT", tm);
138 
139 	return srv->mtime_cache[i].str;
140 }
141 
142 
143 int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
144 	buffer *vb;
145 	int head_or_get =
146 		(  HTTP_METHOD_GET  == con->request.http_method
147 		|| HTTP_METHOD_HEAD == con->request.http_method);
148 	UNUSED(srv);
149 
150 	/*
151 	 * 14.26 If-None-Match
152 	 *    [...]
153 	 *    If none of the entity tags match, then the server MAY perform the
154 	 *    requested method as if the If-None-Match header field did not exist,
155 	 *    but MUST also ignore any If-Modified-Since header field(s) in the
156 	 *    request. That is, if no entity tags match, then the server MUST NOT
157 	 *    return a 304 (Not Modified) response.
158 	 */
159 
160 	if ((vb = http_header_request_get(con, HTTP_HEADER_IF_NONE_MATCH, CONST_STR_LEN("If-None-Match")))) {
161 		/* use strong etag checking for now: weak comparison must not be used
162 		 * for ranged requests
163 		 */
164 		if (etag_is_equal(con->physical.etag, vb->ptr, 0)) {
165 			if (head_or_get) {
166 				con->http_status = 304;
167 				return HANDLER_FINISHED;
168 			} else {
169 				con->http_status = 412;
170 				con->mode = DIRECT;
171 				return HANDLER_FINISHED;
172 			}
173 		}
174 	} else if (head_or_get
175 		   && (vb = http_header_request_get(con, HTTP_HEADER_IF_MODIFIED_SINCE, CONST_STR_LEN("If-Modified-Since")))) {
176 		/* last-modified handling */
177 		size_t used_len;
178 		char *semicolon;
179 
180 		if (NULL == (semicolon = strchr(vb->ptr, ';'))) {
181 			used_len = buffer_string_length(vb);
182 		} else {
183 			used_len = semicolon - vb->ptr;
184 		}
185 
186 		if (buffer_is_equal_string(mtime, vb->ptr, used_len)) {
187 			if ('\0' == mtime->ptr[used_len]) con->http_status = 304;
188 			return HANDLER_FINISHED;
189 		} else {
190 			char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
191 			time_t t_header, t_file;
192 			struct tm tm;
193 
194 			/* convert to timestamp */
195 			if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
196 
197 			memcpy(buf, vb->ptr, used_len);
198 			buf[used_len] = '\0';
199 
200 			if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) {
201 				/**
202 				 * parsing failed, let's get out of here
203 				 */
204 				return HANDLER_GO_ON;
205 			}
206 			tm.tm_isdst = 0;
207 			t_header = mktime(&tm);
208 
209 			strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
210 			tm.tm_isdst = 0;
211 			t_file = mktime(&tm);
212 
213 			if (t_file > t_header) return HANDLER_GO_ON;
214 
215 			con->http_status = 304;
216 			return HANDLER_FINISHED;
217 		}
218 	}
219 
220 	return HANDLER_GO_ON;
221 }
222 
223 
224 void http_response_body_clear (connection *con, int preserve_length) {
225     con->response.send_chunked = 0;
226     if (con->response.htags & HTTP_HEADER_TRANSFER_ENCODING) {
227         http_header_response_unset(con, HTTP_HEADER_TRANSFER_ENCODING, CONST_STR_LEN("Transfer-Encoding"));
228     }
229     if (!preserve_length) { /* preserve for HEAD responses and no-content responses (204, 205, 304) */
230         con->response.content_length = -1;
231         if (con->response.htags & HTTP_HEADER_CONTENT_LENGTH) {
232             http_header_response_unset(con, HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length"));
233         }
234     }
235     chunkqueue_reset(con->write_queue);
236 }
237 
238 
239 static int http_response_parse_range(server *srv, connection *con, buffer *path, stat_cache_entry *sce, const char *range) {
240 	int multipart = 0;
241 	int error;
242 	off_t start, end;
243 	const char *s, *minus;
244 	static const char boundary[] = "fkj49sn38dcn3";
245 	buffer *content_type = http_header_response_get(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"));
246 
247 	start = 0;
248 	end = sce->st.st_size - 1;
249 
250 	con->response.content_length = 0;
251 
252 	for (s = range, error = 0;
253 	     !error && *s && NULL != (minus = strchr(s, '-')); ) {
254 		char *err;
255 		off_t la = 0, le;
256 		*((const char **)&err) = s; /*(quiet clang --analyze)*/
257 
258 		if (s != minus) {
259 			la = strtoll(s, &err, 10);
260 			if (err != minus) {
261 				/* should not have multiple range-unit in Range, but
262 				 * handle just in case multiple Range headers merged */
263 				while (*s == ' ' || *s == '\t') ++s;
264 				if (0 != strncmp(s, "bytes=", 6)) return -1;
265 				s += 6;
266 				if (s != minus) {
267 					la = strtoll(s, &err, 10);
268 					if (err != minus) return -1;
269 				}
270 			}
271 		}
272 
273 		if (s == minus) {
274 			/* -<stop> */
275 
276 			le = strtoll(s, &err, 10);
277 
278 			if (le == 0) {
279 				/* RFC 2616 - 14.35.1 */
280 
281 				con->http_status = 416;
282 				error = 1;
283 			} else if (*err == '\0') {
284 				/* end */
285 				s = err;
286 
287 				end = sce->st.st_size - 1;
288 				start = sce->st.st_size + le;
289 			} else if (*err == ',') {
290 				multipart = 1;
291 				s = err + 1;
292 
293 				end = sce->st.st_size - 1;
294 				start = sce->st.st_size + le;
295 			} else {
296 				error = 1;
297 			}
298 
299 		} else if (*(minus+1) == '\0' || *(minus+1) == ',') {
300 			/* <start>- */
301 
302 				/* ok */
303 
304 				if (*(err + 1) == '\0') {
305 					s = err + 1;
306 
307 					end = sce->st.st_size - 1;
308 					start = la;
309 
310 				} else if (*(err + 1) == ',') {
311 					multipart = 1;
312 					s = err + 2;
313 
314 					end = sce->st.st_size - 1;
315 					start = la;
316 				} else {
317 					error = 1;
318 				}
319 		} else {
320 			/* <start>-<stop> */
321 
322 				le = strtoll(minus+1, &err, 10);
323 
324 				/* RFC 2616 - 14.35.1 */
325 				if (la > le) {
326 					error = 1;
327 				}
328 
329 				if (*err == '\0') {
330 					/* ok, end*/
331 					s = err;
332 
333 					end = le;
334 					start = la;
335 				} else if (*err == ',') {
336 					multipart = 1;
337 					s = err + 1;
338 
339 					end = le;
340 					start = la;
341 				} else {
342 					/* error */
343 
344 					error = 1;
345 				}
346 		}
347 
348 		if (!error) {
349 			if (start < 0) start = 0;
350 
351 			/* RFC 2616 - 14.35.1 */
352 			if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
353 
354 			if (start > sce->st.st_size - 1) {
355 				error = 1;
356 
357 				con->http_status = 416;
358 			}
359 		}
360 
361 		if (!error) {
362 			if (multipart) {
363 				/* write boundary-header */
364 				buffer *b = srv->tmp_buf;
365 				buffer_copy_string_len(b, CONST_STR_LEN("\r\n--"));
366 				buffer_append_string_len(b, boundary, sizeof(boundary)-1);
367 
368 				/* write Content-Range */
369 				buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Range: bytes "));
370 				buffer_append_int(b, start);
371 				buffer_append_string_len(b, CONST_STR_LEN("-"));
372 				buffer_append_int(b, end);
373 				buffer_append_string_len(b, CONST_STR_LEN("/"));
374 				buffer_append_int(b, sce->st.st_size);
375 
376 				if (content_type) {
377 					buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Type: "));
378 					buffer_append_string_buffer(b, content_type);
379 				}
380 
381 				/* write END-OF-HEADER */
382 				buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
383 
384 				con->response.content_length += buffer_string_length(b);
385 				chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(b));
386 			}
387 
388 			chunkqueue_append_file(con->write_queue, path, start, end - start + 1);
389 			con->response.content_length += end - start + 1;
390 		}
391 	}
392 
393 	/* something went wrong */
394 	if (error) return -1;
395 
396 	if (multipart) {
397 		/* add boundary end */
398 		buffer *b = srv->tmp_buf;
399 		buffer_copy_string_len(b, "\r\n--", 4);
400 		buffer_append_string_len(b, boundary, sizeof(boundary)-1);
401 		buffer_append_string_len(b, "--\r\n", 4);
402 
403 		con->response.content_length += buffer_string_length(b);
404 		chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(b));
405 
406 		/* set header-fields */
407 
408 		buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("multipart/byteranges; boundary="));
409 		buffer_append_string_len(srv->tmp_buf, boundary, sizeof(boundary)-1);
410 
411 		/* overwrite content-type */
412 		http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(srv->tmp_buf));
413 	} else {
414 		/* add Content-Range-header */
415 
416 		buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("bytes "));
417 		buffer_append_int(srv->tmp_buf, start);
418 		buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("-"));
419 		buffer_append_int(srv->tmp_buf, end);
420 		buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/"));
421 		buffer_append_int(srv->tmp_buf, sce->st.st_size);
422 
423 		http_header_response_set(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(srv->tmp_buf));
424 	}
425 
426 	/* ok, the file is set-up */
427 	return 0;
428 }
429 
430 
431 void http_response_send_file (server *srv, connection *con, buffer *path) {
432 	stat_cache_entry *sce = NULL;
433 	buffer *mtime = NULL;
434 	buffer *vb;
435 	int allow_caching = (0 == con->http_status || 200 == con->http_status);
436 
437 	if (HANDLER_ERROR == stat_cache_get_entry(srv, con, path, &sce)) {
438 		con->http_status = (errno == ENOENT) ? 404 : 403;
439 
440 		log_error_write(srv, __FILE__, __LINE__, "sbsb",
441 				"not a regular file:", con->uri.path,
442 				"->", path);
443 
444 		return;
445 	}
446 
447 	if (!con->conf.follow_symlink
448 	    && 0 != stat_cache_path_contains_symlink(srv, path)) {
449 		con->http_status = 403;
450 
451 		if (con->conf.log_request_handling) {
452 			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
453 			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", path);
454 		}
455 
456 		return;
457 	}
458 
459 	/* we only handle regular files */
460 	if (!S_ISREG(sce->st.st_mode)) {
461 		con->http_status = 403;
462 
463 		if (con->conf.log_file_not_found) {
464 			log_error_write(srv, __FILE__, __LINE__, "sbsb",
465 					"not a regular file:", con->uri.path,
466 					"->", sce->name);
467 		}
468 
469 		return;
470 	}
471 
472 	/*(Note: O_NOFOLLOW affects only the final path segment,
473 	 * the target file, not any intermediate symlinks along path)*/
474 	const int fd = fdevent_open_cloexec(path->ptr, con->conf.follow_symlink, O_RDONLY, 0);
475 	if (fd < 0) {
476 		con->http_status = (errno == ENOENT) ? 404 : 403;
477 		if (con->conf.log_request_handling) {
478 			log_error_write(srv, __FILE__, __LINE__,  "sbs", "file open failed:", path, strerror(errno));
479 		}
480 		return;
481 	}
482 
483 	/* mod_compress might set several data directly, don't overwrite them */
484 
485 	/* set response content-type, if not set already */
486 
487 	if (NULL == http_header_response_get(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"))) {
488 		stat_cache_content_type_get(srv, con, path, sce);
489 		if (buffer_string_is_empty(sce->content_type)) {
490 			/* we are setting application/octet-stream, but also announce that
491 			 * this header field might change in the seconds few requests
492 			 *
493 			 * This should fix the aggressive caching of FF and the script download
494 			 * seen by the first installations
495 			 */
496 			http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("application/octet-stream"));
497 
498 			allow_caching = 0;
499 		} else {
500 			http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
501 		}
502 	}
503 
504 	if (con->conf.range_requests) {
505 		http_header_response_append(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
506 	}
507 
508 	if (allow_caching) {
509 		if (con->etag_flags != 0 && !buffer_string_is_empty(stat_cache_etag_get(sce, con->etag_flags))) {
510 			if (NULL == http_header_response_get(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"))) {
511 				/* generate e-tag */
512 				etag_mutate(con->physical.etag, sce->etag);
513 
514 				http_header_response_set(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
515 			}
516 		}
517 
518 		/* prepare header */
519 		if (NULL == (mtime = http_header_response_get(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified")))) {
520 			mtime = strftime_cache_get(srv, sce->st.st_mtime);
521 			http_header_response_set(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
522 		}
523 
524 		if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
525 			close(fd);
526 			return;
527 		}
528 	}
529 
530 	if (con->conf.range_requests
531 	    && (200 == con->http_status || 0 == con->http_status)
532 	    && NULL != (vb = http_header_request_get(con, HTTP_HEADER_RANGE, CONST_STR_LEN("Range")))
533 	    && NULL == http_header_response_get(con, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding"))) {
534 		buffer *range = vb;
535 		int do_range_request = 1;
536 		/* check if we have a conditional GET */
537 
538 		if (NULL != (vb = http_header_request_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("If-Range")))) {
539 			/* if the value is the same as our ETag, we do a Range-request,
540 			 * otherwise a full 200 */
541 
542 			if (vb->ptr[0] == '"') {
543 				/**
544 				 * client wants a ETag
545 				 */
546 				if (!con->physical.etag) {
547 					do_range_request = 0;
548 				} else if (!buffer_is_equal(vb, con->physical.etag)) {
549 					do_range_request = 0;
550 				}
551 			} else if (!mtime) {
552 				/**
553 				 * we don't have a Last-Modified and can match the If-Range:
554 				 *
555 				 * sending all
556 				 */
557 				do_range_request = 0;
558 			} else if (!buffer_is_equal(vb, mtime)) {
559 				do_range_request = 0;
560 			}
561 		}
562 
563 		if (do_range_request
564 		    && !buffer_string_is_empty(range)
565 		    && 0 == strncmp(range->ptr, "bytes=", 6)) {
566 			/* support only "bytes" byte-unit */
567 			/* content prepared, I'm done */
568 			con->file_finished = 1;
569 
570 			if (0 == http_response_parse_range(srv, con, path, sce, range->ptr+6)) {
571 				con->http_status = 206;
572 			}
573 			close(fd);
574 			return;
575 		}
576 	}
577 
578 	/* if we are still here, prepare body */
579 
580 	/* we add it here for all requests
581 	 * the HEAD request will drop it afterwards again
582 	 */
583 
584 	http_chunk_append_file_fd(srv, con, path, fd, sce->st.st_size);
585 	con->http_status = 200;
586 	con->file_finished = 1;
587 }
588 
589 
590 static void http_response_xsendfile (server *srv, connection *con, buffer *path, const array *xdocroot) {
591 	const int status = con->http_status;
592 	int valid = 1;
593 
594 	/* reset Content-Length, if set by backend
595 	 * Content-Length might later be set to size of X-Sendfile static file,
596 	 * determined by open(), fstat() to reduces race conditions if the file
597 	 * is modified between stat() (stat_cache_get_entry()) and open(). */
598 	if (con->response.htags & HTTP_HEADER_CONTENT_LENGTH) {
599 		http_header_response_unset(con, HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length"));
600 		con->response.content_length = -1;
601 	}
602 
603 	buffer_urldecode_path(path);
604 	if (!buffer_is_valid_UTF8(path)) {
605 		log_error_write(srv, __FILE__, __LINE__, "sb",
606 				"X-Sendfile invalid UTF-8 after url-decode:", path);
607 		if (con->http_status < 400) {
608 			con->http_status = 502;
609 			con->mode = DIRECT;
610 		}
611 		return;
612 	}
613 	buffer_path_simplify(path, path);
614 	if (con->conf.force_lowercase_filenames) {
615 		buffer_to_lower(path);
616 	}
617 
618 	/* check that path is under xdocroot(s)
619 	 * - xdocroot should have trailing slash appended at config time
620 	 * - con->conf.force_lowercase_filenames is not a server-wide setting,
621 	 *   and so can not be definitively applied to xdocroot at config time*/
622 	if (xdocroot->used) {
623 		size_t i, xlen = buffer_string_length(path);
624 		for (i = 0; i < xdocroot->used; ++i) {
625 			data_string *ds = (data_string *)xdocroot->data[i];
626 			size_t dlen = buffer_string_length(ds->value);
627 			if (dlen <= xlen
628 			    && (!con->conf.force_lowercase_filenames
629 				? 0 == memcmp(path->ptr, ds->value->ptr, dlen)
630 				: 0 == strncasecmp(path->ptr, ds->value->ptr, dlen))) {
631 				break;
632 			}
633 		}
634 		if (i == xdocroot->used) {
635 			log_error_write(srv, __FILE__, __LINE__, "SBs",
636 					"X-Sendfile (", path,
637 					") not under configured x-sendfile-docroot(s)");
638 			con->http_status = 403;
639 			valid = 0;
640 		}
641 	}
642 
643 	if (valid) http_response_send_file(srv, con, path);
644 
645 	if (con->http_status >= 400 && status < 300) {
646 		con->mode = DIRECT;
647 	} else if (0 != status && 200 != status) {
648 		con->http_status = status;
649 	}
650 }
651 
652 
653 static void http_response_xsendfile2(server *srv, connection *con, const buffer *value, const array *xdocroot) {
654     const char *pos = value->ptr;
655     buffer *b = srv->tmp_buf;
656     const int status = con->http_status;
657 
658     /* reset Content-Length, if set by backend */
659     if (con->response.htags & HTTP_HEADER_CONTENT_LENGTH) {
660         http_header_response_unset(con, HTTP_HEADER_CONTENT_LENGTH, CONST_STR_LEN("Content-Length"));
661         con->response.content_length = -1;
662     }
663 
664     while (*pos) {
665         const char *filename, *range;
666         stat_cache_entry *sce;
667         off_t begin_range, end_range, range_len;
668 
669         while (' ' == *pos) pos++;
670         if (!*pos) break;
671 
672         filename = pos;
673         if (NULL == (range = strchr(pos, ' '))) {
674             /* missing range */
675             log_error_write(srv, __FILE__, __LINE__, "ss",
676                             "Couldn't find range after filename:", filename);
677             con->http_status = 502;
678             break;
679         }
680         buffer_copy_string_len(b, filename, range - filename);
681 
682         /* find end of range */
683         for (pos = ++range; *pos && *pos != ' ' && *pos != ','; pos++) ;
684 
685         buffer_urldecode_path(b);
686         if (!buffer_is_valid_UTF8(b)) {
687             log_error_write(srv, __FILE__, __LINE__, "sb",
688                             "X-Sendfile2 invalid UTF-8 after url-decode:", b);
689             con->http_status = 502;
690             break;
691         }
692         buffer_path_simplify(b, b);
693         if (con->conf.force_lowercase_filenames) {
694             buffer_to_lower(b);
695         }
696         if (xdocroot->used) {
697             size_t i, xlen = buffer_string_length(b);
698             for (i = 0; i < xdocroot->used; ++i) {
699                 data_string *ds = (data_string *)xdocroot->data[i];
700                 size_t dlen = buffer_string_length(ds->value);
701                 if (dlen <= xlen
702                     && (!con->conf.force_lowercase_filenames
703                     ? 0 == memcmp(b->ptr, ds->value->ptr, dlen)
704                     : 0 == strncasecmp(b->ptr, ds->value->ptr, dlen))) {
705                     break;
706                 }
707             }
708             if (i == xdocroot->used) {
709                 log_error_write(srv, __FILE__, __LINE__, "SBs",
710                                 "X-Sendfile2 (", b,
711                                 ") not under configured x-sendfile-docroot(s)");
712                 con->http_status = 403;
713                 break;
714             }
715         }
716 
717         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, b, &sce)) {
718             log_error_write(srv, __FILE__, __LINE__, "sb", "send-file error: "
719                             "couldn't get stat_cache entry for X-Sendfile2:",
720                             b);
721             con->http_status = 404;
722             break;
723         } else if (!S_ISREG(sce->st.st_mode)) {
724             log_error_write(srv, __FILE__, __LINE__, "sb",
725                             "send-file error: wrong filetype for X-Sendfile2:",
726                             b);
727             con->http_status = 502;
728             break;
729         }
730         /* found the file */
731 
732         /* parse range */
733         end_range = sce->st.st_size - 1;
734         {
735             char *rpos = NULL;
736             errno = 0;
737             begin_range = strtoll(range, &rpos, 10);
738             if (errno != 0 || begin_range < 0 || rpos == range)
739                 goto range_failed;
740             if ('-' != *rpos++) goto range_failed;
741             if (rpos != pos) {
742                 range = rpos;
743                 end_range = strtoll(range, &rpos, 10);
744                 if (errno != 0 || end_range < 0 || rpos == range)
745                     goto range_failed;
746             }
747             if (rpos != pos) goto range_failed;
748 
749             goto range_success;
750 
751 range_failed:
752             log_error_write(srv, __FILE__, __LINE__, "ss",
753                             "Couldn't decode range after filename:", filename);
754             con->http_status = 502;
755             break;
756 
757 range_success: ;
758         }
759 
760         /* no parameters accepted */
761 
762         while (*pos == ' ') pos++;
763         if (*pos != '\0' && *pos != ',') {
764             con->http_status = 502;
765             break;
766         }
767 
768         range_len = end_range - begin_range + 1;
769         if (range_len < 0) {
770             con->http_status = 502;
771             break;
772         }
773         if (range_len != 0) {
774             if (0 != http_chunk_append_file_range(srv, con, b,
775                                                   begin_range, range_len)) {
776                 con->http_status = 502;
777                 break;
778             }
779         }
780 
781         if (*pos == ',') pos++;
782     }
783 
784     if (con->http_status >= 400 && status < 300) {
785         con->mode = DIRECT;
786     } else if (0 != status && 200 != status) {
787         con->http_status = status;
788     }
789 }
790 
791 
792 void http_response_backend_error (server *srv, connection *con) {
793 	UNUSED(srv);
794 	if (con->file_started) {
795 		/*(response might have been already started, kill the connection)*/
796 		/*(mode == DIRECT to avoid later call to http_response_backend_done())*/
797 		con->mode = DIRECT;  /*(avoid sending final chunked block)*/
798 		con->keep_alive = 0; /*(no keep-alive; final chunked block not sent)*/
799 		con->file_finished = 1;
800 	} /*(else error status set later by http_response_backend_done())*/
801 }
802 
803 void http_response_backend_done (server *srv, connection *con) {
804 	/* (not CON_STATE_ERROR and not CON_STATE_RESPONSE_END,
805 	 *  i.e. not called from handle_connection_close or connection_reset
806 	 *  hooks, except maybe from errdoc handler, which later resets state)*/
807 	switch (con->state) {
808 	case CON_STATE_HANDLE_REQUEST:
809 	case CON_STATE_READ_POST:
810 		if (!con->file_started) {
811 			/* Send an error if we haven't sent any data yet */
812 			con->http_status = 500;
813 			con->mode = DIRECT;
814 			break;
815 		} /* else fall through */
816 	case CON_STATE_WRITE:
817 		if (!con->file_finished) {
818 			http_chunk_close(srv, con);
819 			con->file_finished = 1;
820 		}
821 	default:
822 		break;
823 	}
824 }
825 
826 
827 void http_response_upgrade_read_body_unknown(server *srv, connection *con) {
828     /* act as transparent proxy */
829     UNUSED(srv);
830     if (!(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST))
831         con->conf.stream_request_body |=
832           (FDEVENT_STREAM_REQUEST_BUFMIN | FDEVENT_STREAM_REQUEST);
833     if (!(con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE))
834         con->conf.stream_response_body |=
835           (FDEVENT_STREAM_RESPONSE_BUFMIN | FDEVENT_STREAM_RESPONSE);
836     con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN;
837     con->request.content_length = -2;
838     con->keep_alive = 0;
839 }
840 
841 
842 static handler_t http_response_process_local_redir(server *srv, connection *con, size_t blen) {
843     /* [RFC3875] The Common Gateway Interface (CGI) Version 1.1
844      * [RFC3875] 6.2.2 Local Redirect Response
845      *
846      *    The CGI script can return a URI path and query-string
847      *    ('local-pathquery') for a local resource in a Location header field.
848      *    This indicates to the server that it should reprocess the request
849      *    using the path specified.
850      *
851      *      local-redir-response = local-Location NL
852      *
853      *    The script MUST NOT return any other header fields or a message-body,
854      *    and the server MUST generate the response that it would have produced
855      *    in response to a request containing the URL
856      *
857      *      scheme "://" server-name ":" server-port local-pathquery
858      *
859      * (Might not have begun to receive body yet, but do skip local-redir
860      *  if we already have started receiving a response body (blen > 0))
861      * (Also, while not required by the RFC, do not send local-redir back
862      *  to same URL, since CGI should have handled it internally if it
863      *  really wanted to do that internally)
864      */
865 
866     /* con->http_status >= 300 && con->http_status < 400) */
867     size_t ulen = buffer_string_length(con->uri.path);
868     buffer *vb = http_header_response_get(con, HTTP_HEADER_LOCATION, CONST_STR_LEN("Location"));
869     if (NULL != vb
870         && vb->ptr[0] == '/'
871         && (0 != strncmp(vb->ptr, con->uri.path->ptr, ulen)
872             || (   vb->ptr[ulen] != '\0'
873                 && vb->ptr[ulen] != '/'
874                 && vb->ptr[ulen] != '?'))
875         && 0 == blen
876         && !(con->response.htags & HTTP_HEADER_STATUS) /*no "Status" or NPH response*/
877         && 1 == con->response.headers->used) {
878         if (++con->loops_per_request > 5) {
879             log_error_write(srv, __FILE__, __LINE__, "sb",
880                             "too many internal loops while processing request:",
881                             con->request.orig_uri);
882             con->http_status = 500; /* Internal Server Error */
883             con->mode = DIRECT;
884             return HANDLER_FINISHED;
885         }
886 
887         buffer_copy_buffer(con->request.uri, vb);
888 
889         if (con->request.content_length) {
890             if (con->request.content_length
891                 != con->request_content_queue->bytes_in) {
892                 con->keep_alive = 0;
893             }
894             con->request.content_length = 0;
895             chunkqueue_reset(con->request_content_queue);
896         }
897 
898         if (con->http_status != 307 && con->http_status != 308) {
899             /* Note: request body (if any) sent to initial dynamic handler
900              * and is not available to the internal redirect */
901             con->request.http_method = HTTP_METHOD_GET;
902         }
903 
904         /*(caller must reset request as follows)*/
905         /*connection_response_reset(srv, con);*/ /*(sets con->http_status = 0)*/
906         /*plugins_call_connection_reset(srv, con);*/
907 
908         return HANDLER_COMEBACK;
909     }
910 
911     return HANDLER_GO_ON;
912 }
913 
914 
915 static int http_response_process_headers(server *srv, connection *con, http_response_opts *opts, buffer *hdrs) {
916     char *ns;
917     const char *s;
918     int line = 0;
919     int status_is_set = 0;
920 
921     for (s = hdrs->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1, ++line) {
922         const char *key, *value;
923         int key_len;
924         enum http_header_e id;
925 
926         /* strip the \n */
927         ns[0] = '\0';
928         if (ns > s && ns[-1] == '\r') ns[-1] = '\0';
929 
930         if (0 == line && 0 == strncmp(s, "HTTP/1.", 7)) {
931             /* non-parsed headers ... we parse them anyway */
932             if ((s[7] == '1' || s[7] == '0') && s[8] == ' ') {
933                 /* after the space should be a status code for us */
934                 int status = strtol(s+9, NULL, 10);
935                 if (status >= 100 && status < 1000) {
936                     status_is_set = 1;
937                     con->response.htags |= HTTP_HEADER_STATUS;
938                     con->http_status = status;
939                 } /* else we expected 3 digits and didn't get them */
940             }
941 
942             if (0 == con->http_status) {
943                 log_error_write(srv, __FILE__, __LINE__, "ss",
944                                 "invalid HTTP status line:", s);
945                 con->http_status = 502; /* Bad Gateway */
946                 con->mode = DIRECT;
947                 return -1;
948             }
949 
950             continue;
951         }
952 
953         /* parse the headers */
954         key = s;
955         if (NULL == (value = strchr(s, ':'))) {
956             /* we expect: "<key>: <value>\r\n" */
957             continue;
958         }
959 
960         key_len = value - key;
961         do { ++value; } while (*value == ' ' || *value == '\t'); /* skip LWS */
962         id = http_header_hkey_get(key, key_len);
963 
964         if (opts->authorizer) {
965             if (0 == con->http_status || 200 == con->http_status) {
966                 if (id == HTTP_HEADER_STATUS) {
967                     int status = strtol(value, NULL, 10);
968                     if (status >= 100 && status < 1000) {
969                         con->http_status = status;
970                     } else {
971                         con->http_status = 502; /* Bad Gateway */
972                         break;
973                     }
974                 } else if (id == HTTP_HEADER_OTHER && key_len > 9
975                            && 0==strncasecmp(key, CONST_STR_LEN("Variable-"))) {
976                     http_header_env_append(con, key + 9, key_len - 9, value, strlen(value));
977                 }
978                 continue;
979             }
980         }
981 
982         switch (id) {
983           case HTTP_HEADER_STATUS:
984             {
985                 int status;
986                 if (opts->backend == BACKEND_PROXY) break; /*(pass w/o parse)*/
987                 status = strtol(value, NULL, 10);
988                 if (status >= 100 && status < 1000) {
989                     con->http_status = status;
990                     status_is_set = 1;
991                 } else {
992                     con->http_status = 502;
993                     con->mode = DIRECT;
994                 }
995                 continue; /* do not send Status to client */
996             }
997             break;
998           case HTTP_HEADER_UPGRADE:
999             /*(technically, should also verify Connection: upgrade)*/
1000             /*(flag only for mod_proxy and mod_cgi (for now))*/
1001             if (opts->backend != BACKEND_PROXY
1002                 && opts->backend != BACKEND_CGI) {
1003                 id = HTTP_HEADER_OTHER;
1004             }
1005             break;
1006           case HTTP_HEADER_CONNECTION:
1007             if (opts->backend == BACKEND_PROXY) continue;
1008             /*(should parse for tokens and do case-insensitive match for "close"
1009              * but this is an imperfect though simplistic attempt to honor
1010              * backend request to close)*/
1011             if (NULL != strstr(value, "lose")) con->keep_alive = 0;
1012             break;
1013           case HTTP_HEADER_CONTENT_LENGTH:
1014             con->response.content_length = strtoul(value, NULL, 10);
1015             break;
1016           case HTTP_HEADER_TRANSFER_ENCODING:
1017             if (opts->backend == BACKEND_PROXY) {
1018                 log_error_write(srv, __FILE__, __LINE__, "s",
1019                                 "proxy backend sent invalid response header "
1020                                 "(Transfer-Encoding) to HTTP/1.0 request");
1021                 con->http_status = 502; /* Bad Gateway */
1022                 con->mode = DIRECT;
1023                 return -1;
1024             }
1025             break;
1026           default:
1027             break;
1028         }
1029 
1030         http_header_response_insert(con, id, key, key_len, value, strlen(value));
1031     }
1032 
1033     /* CGI/1.1 rev 03 - 7.2.1.2 */
1034     /* (proxy requires Status-Line, so never true for proxy)*/
1035     if (!status_is_set && (con->response.htags & HTTP_HEADER_LOCATION)) {
1036         con->http_status = 302;
1037     }
1038 
1039     return 0;
1040 }
1041 
1042 
1043 handler_t http_response_parse_headers(server *srv, connection *con, http_response_opts *opts, buffer *b) {
1044     /**
1045      * possible formats of response headers:
1046      *
1047      * proxy or NPH (non-parsed headers):
1048      *
1049      *   HTTP/1.0 200 Ok\n
1050      *   Header: Value\n
1051      *   \n
1052      *
1053      * CGI:
1054      *
1055      *   Header: Value\n
1056      *   Status: 200\n
1057      *   \n
1058      *
1059      * and different mixes of \n and \r\n combinations
1060      *
1061      * Some users also forget about CGI and just send a response
1062      * and hope we handle it. No headers, no header-content separator
1063      */
1064 
1065     int is_nph = (0 == strncmp(b->ptr, "HTTP/1.", 7)); /*nph (non-parsed hdrs)*/
1066     int is_header_end = 0;
1067     size_t last_eol = 0;
1068     size_t i = 0, header_len = buffer_string_length(b);
1069     const char *bstart;
1070     size_t blen;
1071 
1072     if (b->ptr[0] == '\n' || (b->ptr[0] == '\r' && b->ptr[1] == '\n')) {
1073         /* no HTTP headers */
1074         i = (b->ptr[0] == '\n') ? 0 : 1;
1075         is_header_end = 1;
1076     } else if (is_nph || b->ptr[(i = strcspn(b->ptr, ":\n"))] == ':') {
1077         /* HTTP headers */
1078         ++i;
1079         for (char *c; NULL != (c = strchr(b->ptr+i, '\n')); ++i) {
1080             i = (uintptr_t)(c - b->ptr);
1081             /**
1082              * check if we saw a \n(\r)?\n sequence
1083              */
1084             if (last_eol > 0 &&
1085                 ((i - last_eol == 1) ||
1086                  (i - last_eol == 2 && b->ptr[i - 1] == '\r'))) {
1087                 is_header_end = 1;
1088                 break;
1089             }
1090 
1091             last_eol = i;
1092         }
1093     } else if (i == header_len) { /* (no newline yet; partial header line?) */
1094     } else if (opts->backend == BACKEND_CGI) {
1095         /* no HTTP headers, but a body (special-case for CGI compat) */
1096         /* no colon found; does not appear to be HTTP headers */
1097         if (0 != http_chunk_append_buffer(srv, con, b)) {
1098             return HANDLER_ERROR;
1099         }
1100         con->http_status = 200; /* OK */
1101         con->file_started = 1;
1102         return HANDLER_GO_ON;
1103     } else {
1104         /* invalid response headers */
1105         con->http_status = 502; /* Bad Gateway */
1106         con->mode = DIRECT;
1107         return HANDLER_FINISHED;
1108     }
1109 
1110     if (!is_header_end) {
1111         /*(reuse MAX_HTTP_REQUEST_HEADER as max size
1112          * for response headers from backends)*/
1113         if (header_len > MAX_HTTP_REQUEST_HEADER) {
1114             log_error_write(srv, __FILE__, __LINE__, "sb",
1115                             "response headers too large for", con->uri.path);
1116             con->http_status = 502; /* Bad Gateway */
1117             con->mode = DIRECT;
1118             return HANDLER_FINISHED;
1119         }
1120         return HANDLER_GO_ON;
1121     }
1122 
1123     /* the body starts after the EOL */
1124     bstart = b->ptr + (i + 1);
1125     blen = header_len - (i + 1);
1126 
1127     /* strip the last \r?\n */
1128     if (i > 0 && (b->ptr[i - 1] == '\r')) {
1129         i--;
1130     }
1131 
1132     buffer_string_set_length(b, i);
1133 
1134     if (opts->backend == BACKEND_PROXY && !is_nph) {
1135         /* invalid response Status-Line from HTTP proxy */
1136         con->http_status = 502; /* Bad Gateway */
1137         con->mode = DIRECT;
1138         return HANDLER_FINISHED;
1139     }
1140 
1141     if (0 != http_response_process_headers(srv, con, opts, b)) {
1142         return HANDLER_ERROR;
1143     }
1144 
1145     con->file_started = 1;
1146 
1147     if (opts->authorizer
1148         && (con->http_status == 0 || con->http_status == 200)) {
1149         return HANDLER_GO_ON;
1150     }
1151 
1152     if (con->mode == DIRECT) {
1153         return HANDLER_FINISHED;
1154     }
1155 
1156     if (opts->local_redir && con->http_status >= 300 && con->http_status < 400){
1157         /*(con->response.htags & HTTP_HEADER_LOCATION)*/
1158         handler_t rc = http_response_process_local_redir(srv, con, blen);
1159         if (con->mode == DIRECT) con->file_started = 0;
1160         if (rc != HANDLER_GO_ON) return rc;
1161     }
1162 
1163     if (opts->xsendfile_allow) {
1164         buffer *vb;
1165         /* X-Sendfile2 is deprecated; historical for fastcgi */
1166         if (opts->backend == BACKEND_FASTCGI
1167             && NULL != (vb = http_header_response_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("X-Sendfile2")))) {
1168             http_response_xsendfile2(srv, con, vb, opts->xsendfile_docroot);
1169             /* http_header_response_unset() shortcut for HTTP_HEADER_OTHER */
1170             buffer_clear(vb); /*(do not send to client)*/
1171             if (con->mode == DIRECT) con->file_started = 0;
1172             return HANDLER_FINISHED;
1173         } else if (NULL != (vb = http_header_response_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("X-Sendfile")))
1174                    || (opts->backend == BACKEND_FASTCGI /* X-LIGHTTPD-send-file is deprecated; historical for fastcgi */
1175                        && NULL != (vb = http_header_response_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("X-LIGHTTPD-send-file"))))) {
1176             http_response_xsendfile(srv, con, vb, opts->xsendfile_docroot);
1177             /* http_header_response_unset() shortcut for HTTP_HEADER_OTHER */
1178             buffer_clear(vb); /*(do not send to client)*/
1179             if (con->mode == DIRECT) con->file_started = 0;
1180             return HANDLER_FINISHED;
1181         }
1182     }
1183 
1184     if (blen > 0) {
1185         if (0 != http_chunk_append_mem(srv, con, bstart, blen)) {
1186             return HANDLER_ERROR;
1187         }
1188     }
1189 
1190     /* (callback for response headers complete) */
1191     return (opts->headers) ? opts->headers(srv, con, opts) : HANDLER_GO_ON;
1192 }
1193 
1194 
1195 handler_t http_response_read(server *srv, connection *con, http_response_opts *opts, buffer *b, fdnode *fdn) {
1196     const int fd = fdn->fd;
1197     while (1) {
1198         ssize_t n;
1199         size_t avail = buffer_string_space(b);
1200         unsigned int toread = 0;
1201 
1202         if (0 == fdevent_ioctl_fionread(fd, opts->fdfmt, (int *)&toread)) {
1203             if (avail < toread) {
1204                 size_t blen = buffer_string_length(b);
1205                 if (toread + blen < 4096)
1206                     toread = 4095 - blen;
1207                 else if (toread > MAX_READ_LIMIT)
1208                     toread = MAX_READ_LIMIT;
1209             }
1210             else if (0 == toread) {
1211               #if 0
1212                 return (fdevent_fdnode_interest(fdn) & FDEVENT_IN)
1213                   ? HANDLER_FINISHED  /* read finished */
1214                   : HANDLER_GO_ON;    /* optimistic read; data not ready */
1215               #else
1216                 if (!(fdevent_fdnode_interest(fdn) & FDEVENT_IN)) {
1217                     if (!(con->conf.stream_response_body
1218                           & FDEVENT_STREAM_RESPONSE_POLLRDHUP))
1219                         return HANDLER_GO_ON;/*optimistic read; data not ready*/
1220                 }
1221                 if (0 == avail) /* let read() below indicate if EOF or EAGAIN */
1222                     toread = 1024;
1223               #endif
1224             }
1225         }
1226         else if (avail < 1024) {
1227             toread = 4095 - avail;
1228         }
1229 
1230         if (con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) {
1231             off_t cqlen = chunkqueue_length(con->write_queue);
1232             if (cqlen + (off_t)toread > 65536 - 4096) {
1233                 if (!con->is_writable) {
1234                     /*(defer removal of FDEVENT_IN interest since
1235                      * connection_state_machine() might be able to send data
1236                      * immediately, unless !con->is_writable, where
1237                      * connection_state_machine() might not loop back to call
1238                      * mod_proxy_handle_subrequest())*/
1239                     fdevent_fdnode_event_clr(srv->ev, fdn, FDEVENT_IN);
1240                 }
1241                 if (cqlen >= 65536-1) return HANDLER_GO_ON;
1242                 toread = 65536 - 1 - (unsigned int)cqlen;
1243                 /* Note: heuristic is fuzzy in that it limits how much to read
1244                  * from backend based on how much is pending to write to client.
1245                  * Modules where data from backend is framed (e.g. FastCGI) may
1246                  * want to limit how much is buffered from backend while waiting
1247                  * for a complete data frame or data packet from backend. */
1248             }
1249         }
1250 
1251         if (avail < toread) {
1252             /*(add avail+toread to reduce allocations when ioctl EOPNOTSUPP)*/
1253             avail = avail ? avail - 1 + toread : toread;
1254             buffer_string_prepare_append(b, avail);
1255         }
1256 
1257         n = read(fd, b->ptr+buffer_string_length(b), avail);
1258 
1259         if (n < 0) {
1260             switch (errno) {
1261               case EAGAIN:
1262              #ifdef EWOULDBLOCK
1263              #if EWOULDBLOCK != EAGAIN
1264               case EWOULDBLOCK:
1265              #endif
1266              #endif
1267               case EINTR:
1268                 return HANDLER_GO_ON;
1269               default:
1270                 log_error_write(srv, __FILE__, __LINE__, "ssdd",
1271                                 "read():", strerror(errno), con->fd, fd);
1272                 return HANDLER_ERROR;
1273             }
1274         }
1275 
1276         buffer_commit(b, (size_t)n);
1277 
1278         if (NULL != opts->parse) {
1279             handler_t rc = opts->parse(srv, con, opts, b, (size_t)n);
1280             if (rc != HANDLER_GO_ON) return rc;
1281         } else if (0 == n) {
1282             /* note: no further data is sent to backend after read EOF on socket
1283              * (not checking for half-closed TCP socket)
1284              * (backend should read all data desired prior to closing socket,
1285              *  though might send app-level close data frame, if applicable) */
1286             return HANDLER_FINISHED; /* read finished */
1287         } else if (0 == con->file_started) {
1288             /* split header from body */
1289             handler_t rc = http_response_parse_headers(srv, con, opts, b);
1290             if (rc != HANDLER_GO_ON) return rc;
1291             /* accumulate response in b until headers completed (or error) */
1292             if (con->file_started) buffer_clear(b);
1293         } else {
1294             if (0 != http_chunk_append_buffer(srv, con, b)) {
1295                 /* error writing to tempfile;
1296                  * truncate response or send 500 if nothing sent yet */
1297                 return HANDLER_ERROR;
1298             }
1299             buffer_clear(b);
1300         }
1301 
1302         if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)
1303             && chunkqueue_length(con->write_queue) > 65536 - 4096) {
1304             if (!con->is_writable) {
1305                 /*(defer removal of FDEVENT_IN interest since
1306                  * connection_state_machine() might be able to send
1307                  * data immediately, unless !con->is_writable, where
1308                  * connection_state_machine() might not loop back to
1309                  * call the subrequest handler)*/
1310                 fdevent_fdnode_event_clr(srv->ev, fdn, FDEVENT_IN);
1311             }
1312             break;
1313         }
1314 
1315         if ((size_t)n < avail)
1316             break; /* emptied kernel read buffer or partial read */
1317     }
1318 
1319     return HANDLER_GO_ON;
1320 }
1321 
1322 
1323 int http_cgi_headers (server *srv, connection *con, http_cgi_opts *opts, http_cgi_header_append_cb cb, void *vdata) {
1324 
1325     /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
1326 
1327     int rc = 0;
1328     server_socket *srv_sock = con->srv_socket;
1329     const char *s;
1330     size_t n;
1331     char buf[LI_ITOSTRING_LENGTH];
1332     sock_addr *addr;
1333     sock_addr addrbuf;
1334     char b2[INET6_ADDRSTRLEN + 1];
1335 
1336     /* (CONTENT_LENGTH must be first for SCGI) */
1337     if (!opts->authorizer) {
1338         li_itostrn(buf, sizeof(buf), con->request.content_length);
1339         rc |= cb(vdata, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
1340     }
1341 
1342     if (!buffer_string_is_empty(con->uri.query)) {
1343         rc |= cb(vdata, CONST_STR_LEN("QUERY_STRING"),
1344                         CONST_BUF_LEN(con->uri.query));
1345     } else {
1346         rc |= cb(vdata, CONST_STR_LEN("QUERY_STRING"),
1347                         CONST_STR_LEN(""));
1348     }
1349     if (!buffer_string_is_empty(opts->strip_request_uri)) {
1350         /**
1351          * /app1/index/list
1352          *
1353          * stripping /app1 or /app1/ should lead to
1354          *
1355          * /index/list
1356          *
1357          */
1358         size_t len = buffer_string_length(opts->strip_request_uri);
1359         if ('/' == opts->strip_request_uri->ptr[len-1]) {
1360             --len;
1361         }
1362 
1363         if (buffer_string_length(con->request.orig_uri) >= len
1364             && 0 == memcmp(con->request.orig_uri->ptr,
1365                            opts->strip_request_uri->ptr, len)
1366             && con->request.orig_uri->ptr[len] == '/') {
1367             rc |= cb(vdata, CONST_STR_LEN("REQUEST_URI"),
1368                             con->request.orig_uri->ptr+len,
1369                             buffer_string_length(con->request.orig_uri) - len);
1370         } else {
1371             rc |= cb(vdata, CONST_STR_LEN("REQUEST_URI"),
1372                             CONST_BUF_LEN(con->request.orig_uri));
1373         }
1374     } else {
1375         rc |= cb(vdata, CONST_STR_LEN("REQUEST_URI"),
1376                         CONST_BUF_LEN(con->request.orig_uri));
1377     }
1378     if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
1379         rc |= cb(vdata, CONST_STR_LEN("REDIRECT_URI"),
1380                         CONST_BUF_LEN(con->request.uri));
1381     }
1382     /* set REDIRECT_STATUS for php compiled with --force-redirect
1383      * (if REDIRECT_STATUS has not already been set by error handler) */
1384     if (0 == con->error_handler_saved_status) {
1385         rc |= cb(vdata, CONST_STR_LEN("REDIRECT_STATUS"),
1386                         CONST_STR_LEN("200"));
1387     }
1388 
1389     /*
1390      * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
1391      * http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
1392      * (6.1.14, 6.1.6, 6.1.7)
1393      */
1394     if (!opts->authorizer) {
1395         rc |= cb(vdata, CONST_STR_LEN("SCRIPT_NAME"),
1396                         CONST_BUF_LEN(con->uri.path));
1397         if (!buffer_string_is_empty(con->request.pathinfo)) {
1398             rc |= cb(vdata, CONST_STR_LEN("PATH_INFO"),
1399                             CONST_BUF_LEN(con->request.pathinfo));
1400             /* PATH_TRANSLATED is only defined if PATH_INFO is set */
1401             if (!buffer_string_is_empty(opts->docroot)) {
1402                 buffer_copy_buffer(srv->tmp_buf, opts->docroot);
1403             } else {
1404                 buffer_copy_buffer(srv->tmp_buf, con->physical.basedir);
1405             }
1406             buffer_append_string_buffer(srv->tmp_buf, con->request.pathinfo);
1407             rc |= cb(vdata, CONST_STR_LEN("PATH_TRANSLATED"),
1408                             CONST_BUF_LEN(srv->tmp_buf));
1409         }
1410     }
1411 
1412    /*
1413     * SCRIPT_FILENAME and DOCUMENT_ROOT for php
1414     * The PHP manual http://www.php.net/manual/en/reserved.variables.php
1415     * treatment of PATH_TRANSLATED is different from the one of CGI specs.
1416     * (see php.ini cgi.fix_pathinfo = 1 config parameter)
1417     */
1418 
1419     if (!buffer_string_is_empty(opts->docroot)) {
1420         /* alternate docroot, e.g. for remote FastCGI or SCGI server */
1421         buffer_copy_buffer(srv->tmp_buf, opts->docroot);
1422         buffer_append_string_buffer(srv->tmp_buf, con->uri.path);
1423         rc |= cb(vdata, CONST_STR_LEN("SCRIPT_FILENAME"),
1424                         CONST_BUF_LEN(srv->tmp_buf));
1425         rc |= cb(vdata, CONST_STR_LEN("DOCUMENT_ROOT"),
1426                         CONST_BUF_LEN(opts->docroot));
1427     } else {
1428         if (opts->break_scriptfilename_for_php) {
1429             /* php.ini config cgi.fix_pathinfo = 1 need a broken SCRIPT_FILENAME
1430              * to find out what PATH_INFO is itself
1431              *
1432              * see src/sapi/cgi_main.c, init_request_info()
1433              */
1434             buffer_copy_buffer(srv->tmp_buf, con->physical.path);
1435             buffer_append_string_buffer(srv->tmp_buf, con->request.pathinfo);
1436             rc |= cb(vdata, CONST_STR_LEN("SCRIPT_FILENAME"),
1437                             CONST_BUF_LEN(srv->tmp_buf));
1438         } else {
1439             rc |= cb(vdata, CONST_STR_LEN("SCRIPT_FILENAME"),
1440                             CONST_BUF_LEN(con->physical.path));
1441         }
1442         rc |= cb(vdata, CONST_STR_LEN("DOCUMENT_ROOT"),
1443                         CONST_BUF_LEN(con->physical.basedir));
1444     }
1445 
1446     s = get_http_method_name(con->request.http_method);
1447     force_assert(s);
1448     rc |= cb(vdata, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
1449 
1450     s = get_http_version_name(con->request.http_version);
1451     force_assert(s);
1452     rc |= cb(vdata, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
1453 
1454     rc |= cb(vdata, CONST_STR_LEN("SERVER_SOFTWARE"),
1455                     CONST_BUF_LEN(con->conf.server_tag));
1456 
1457     rc |= cb(vdata, CONST_STR_LEN("GATEWAY_INTERFACE"),
1458                     CONST_STR_LEN("CGI/1.1"));
1459 
1460     rc |= cb(vdata, CONST_STR_LEN("REQUEST_SCHEME"),
1461                     CONST_BUF_LEN(con->uri.scheme));
1462 
1463     if (buffer_is_equal_string(con->uri.scheme, CONST_STR_LEN("https"))) {
1464         rc |= cb(vdata, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
1465     }
1466 
1467     addr = &srv_sock->addr;
1468     li_utostrn(buf, sizeof(buf), sock_addr_get_port(addr));
1469     rc |= cb(vdata, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
1470 
1471     switch (addr->plain.sa_family) {
1472     case AF_INET:
1473     case AF_INET6:
1474         if (sock_addr_is_addr_wildcard(addr)) {
1475             socklen_t addrlen = sizeof(addrbuf);
1476             if (0 == getsockname(con->fd,(struct sockaddr *)&addrbuf,&addrlen)){
1477                 addr = &addrbuf;
1478             } else {
1479                 s = "";
1480                 break;
1481             }
1482         }
1483         s = sock_addr_inet_ntop(addr, b2, sizeof(b2)-1);
1484         if (NULL == s) s = "";
1485         break;
1486     default:
1487         s = "";
1488         break;
1489     }
1490     force_assert(s);
1491     rc |= cb(vdata, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
1492 
1493     if (!buffer_string_is_empty(con->server_name)) {
1494         size_t len = buffer_string_length(con->server_name);
1495 
1496         if (con->server_name->ptr[0] == '[') {
1497             const char *colon = strstr(con->server_name->ptr, "]:");
1498             if (colon) len = (colon + 1) - con->server_name->ptr;
1499         } else {
1500             const char *colon = strchr(con->server_name->ptr, ':');
1501             if (colon) len = colon - con->server_name->ptr;
1502         }
1503 
1504         rc |= cb(vdata, CONST_STR_LEN("SERVER_NAME"),
1505                         con->server_name->ptr, len);
1506     } else {
1507         /* set to be same as SERVER_ADDR (above) */
1508         rc |= cb(vdata, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
1509     }
1510 
1511     rc |= cb(vdata, CONST_STR_LEN("REMOTE_ADDR"),
1512                     CONST_BUF_LEN(con->dst_addr_buf));
1513 
1514     li_utostrn(buf, sizeof(buf), sock_addr_get_port(&con->dst_addr));
1515     rc |= cb(vdata, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
1516 
1517     for (n = 0; n < con->request.headers->used; n++) {
1518         data_string *ds = (data_string *)con->request.headers->data[n];
1519         if (!buffer_string_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
1520             /* Security: Do not emit HTTP_PROXY in environment.
1521              * Some executables use HTTP_PROXY to configure
1522              * outgoing proxy.  See also https://httpoxy.org/ */
1523             if (buffer_is_equal_caseless_string(ds->key,
1524                                                 CONST_STR_LEN("Proxy"))) {
1525                 continue;
1526             }
1527             buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf,
1528                                                     CONST_BUF_LEN(ds->key), 1);
1529             rc |= cb(vdata, CONST_BUF_LEN(srv->tmp_buf),
1530                             CONST_BUF_LEN(ds->value));
1531         }
1532     }
1533 
1534     srv->request_env(srv, con);
1535 
1536     for (n = 0; n < con->environment->used; n++) {
1537         data_string *ds = (data_string *)con->environment->data[n];
1538         if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
1539             buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf,
1540                                                     CONST_BUF_LEN(ds->key), 0);
1541             rc |= cb(vdata, CONST_BUF_LEN(srv->tmp_buf),
1542                             CONST_BUF_LEN(ds->value));
1543         }
1544     }
1545 
1546     return rc;
1547 }
1548