3 #include "sys-socket.h"
5 #include "connections.h"
10 const char *connection_get_state(connection_state_t state
) {
12 case CON_STATE_CONNECT
: return "connect";
13 case CON_STATE_READ
: return "read";
14 case CON_STATE_READ_POST
: return "readpost";
15 case CON_STATE_WRITE
: return "write";
16 case CON_STATE_CLOSE
: return "close";
17 case CON_STATE_ERROR
: return "error";
18 case CON_STATE_HANDLE_REQUEST
: return "handle-req";
19 case CON_STATE_REQUEST_START
: return "req-start";
20 case CON_STATE_REQUEST_END
: return "req-end";
21 case CON_STATE_RESPONSE_START
: return "resp-start";
22 case CON_STATE_RESPONSE_END
: return "resp-end";
23 default: return "(unknown)";
27 const char *connection_get_short_state(connection_state_t state
) {
29 case CON_STATE_CONNECT
: return ".";
30 case CON_STATE_READ
: return "r";
31 case CON_STATE_READ_POST
: return "R";
32 case CON_STATE_WRITE
: return "W";
33 case CON_STATE_CLOSE
: return "C";
34 case CON_STATE_ERROR
: return "E";
35 case CON_STATE_HANDLE_REQUEST
: return "h";
36 case CON_STATE_REQUEST_START
: return "q";
37 case CON_STATE_REQUEST_END
: return "Q";
38 case CON_STATE_RESPONSE_START
: return "s";
39 case CON_STATE_RESPONSE_END
: return "S";
44 int connection_set_state(server
*srv
, connection
*con
, connection_state_t state
) {
52 static int connection_handle_read_post_cq_compact(chunkqueue
*cq
) {
53 /* combine first mem chunk with next non-empty mem chunk
54 * (loop if next chunk is empty) */
56 while (NULL
!= (c
= cq
->first
) && NULL
!= c
->next
) {
57 buffer
*mem
= c
->next
->mem
;
58 off_t offset
= c
->next
->offset
;
59 size_t blen
= buffer_string_length(mem
) - (size_t)offset
;
60 force_assert(c
->type
== MEM_CHUNK
);
61 force_assert(c
->next
->type
== MEM_CHUNK
);
62 buffer_append_string_len(c
->mem
, mem
->ptr
+offset
, blen
);
63 c
->next
->offset
= c
->offset
;
64 c
->next
->mem
= c
->mem
;
66 c
->offset
= offset
+ (off_t
)blen
;
67 chunkqueue_remove_finished_chunks(cq
);
68 if (0 != blen
) return 1;
73 static int connection_handle_read_post_chunked_crlf(chunkqueue
*cq
) {
74 /* caller might check chunkqueue_length(cq) >= 2 before calling here
75 * to limit return value to either 1 for good or -1 for error */
81 /* caller must have called chunkqueue_remove_finished_chunks(cq), so if
82 * chunkqueue is not empty, it contains chunk with at least one char */
83 if (chunkqueue_is_empty(cq
)) return 0;
88 if (p
[0] != '\r') return -1; /* error */
89 if (p
[1] == '\n') return 1;
90 len
= buffer_string_length(b
) - (size_t)c
->offset
;
91 if (1 != len
) return -1; /* error */
93 while (NULL
!= (c
= c
->next
)) {
95 len
= buffer_string_length(b
) - (size_t)c
->offset
;
96 if (0 == len
) continue;
98 return (p
[0] == '\n') ? 1 : -1; /* error if not '\n' */
103 handler_t
connection_handle_read_post_error(server
*srv
, connection
*con
, int http_status
) {
108 /*(do not change status if response headers already set and possibly sent)*/
109 if (0 != con
->bytes_header
) return HANDLER_ERROR
;
111 con
->http_status
= http_status
;
113 chunkqueue_reset(con
->write_queue
);
114 return HANDLER_FINISHED
;
117 static handler_t
connection_handle_read_post_chunked(server
*srv
, connection
*con
, chunkqueue
*cq
, chunkqueue
*dst_cq
) {
119 /* con->conf.max_request_size is in kBytes */
120 const off_t max_request_size
= (off_t
)con
->conf
.max_request_size
<< 10;
121 off_t te_chunked
= con
->request
.te_chunked
;
123 off_t len
= cq
->bytes_in
- cq
->bytes_out
;
125 while (0 == te_chunked
) {
127 chunk
*c
= cq
->first
;
128 if (NULL
== c
) break;
129 force_assert(c
->type
== MEM_CHUNK
);
130 p
= strchr(c
->mem
->ptr
+c
->offset
, '\n');
131 if (NULL
!= p
) { /* found HTTP chunked header line */
132 off_t hsz
= p
+ 1 - (c
->mem
->ptr
+c
->offset
);
133 unsigned char *s
= (unsigned char *)c
->mem
->ptr
+c
->offset
;
134 for (unsigned char u
;(u
=(unsigned char)hex2int(*s
))!=0xFF;++s
) {
135 if (te_chunked
> (~((off_t
)-1) >> 4)) {
136 log_error_write(srv
, __FILE__
, __LINE__
, "s",
137 "chunked data size too large -> 400");
138 /* 400 Bad Request */
139 return connection_handle_read_post_error(srv
, con
, 400);
144 while (*s
== ' ' || *s
== '\t') ++s
;
145 if (*s
!= '\r' && *s
!= ';') {
146 log_error_write(srv
, __FILE__
, __LINE__
, "s",
147 "chunked header invalid chars -> 400");
148 /* 400 Bad Request */
149 return connection_handle_read_post_error(srv
, con
, 400);
153 /* prevent theoretical integer overflow
154 * casting to (size_t) and adding 2 (for "\r\n") */
155 log_error_write(srv
, __FILE__
, __LINE__
, "s",
156 "chunked header line too long -> 400");
157 /* 400 Bad Request */
158 return connection_handle_read_post_error(srv
, con
, 400);
161 if (0 == te_chunked
) {
162 /* do not consume final chunked header until
163 * (optional) trailers received along with
164 * request-ending blank line "\r\n" */
165 if (p
[0] == '\r' && p
[1] == '\n') {
166 /*(common case with no trailers; final \r\n received)*/
170 /* trailers or final CRLF crosses into next cq chunk */
174 p
= strstr(c
->mem
->ptr
+c
->offset
+hsz
, "\r\n\r\n");
176 && connection_handle_read_post_cq_compact(cq
));
178 /*(effectively doubles max request field size
179 * potentially received by backend, if in the future
180 * these trailers are added to request headers)*/
181 if ((off_t
)buffer_string_length(c
->mem
) - c
->offset
182 < srv
->srvconf
.max_request_field_size
) {
186 /* ignore excessively long trailers;
187 * disable keep-alive on connection */
191 hsz
= p
+ 4 - (c
->mem
->ptr
+c
->offset
);
192 /* trailers currently ignored, but could be processed
193 * here if 0 == con->conf.stream_request_body, taking
194 * care to reject any fields forbidden in trailers,
195 * making trailers available to CGI and other backends*/
197 chunkqueue_mark_written(cq
, (size_t)hsz
);
198 con
->request
.content_length
= dst_cq
->bytes_in
;
199 break; /* done reading HTTP chunked request body */
202 /* consume HTTP chunked header */
203 chunkqueue_mark_written(cq
, (size_t)hsz
);
204 len
= cq
->bytes_in
- cq
->bytes_out
;
206 if (0 !=max_request_size
207 && (max_request_size
< te_chunked
208 || max_request_size
- te_chunked
< dst_cq
->bytes_in
)) {
209 log_error_write(srv
, __FILE__
, __LINE__
, "sos",
210 "request-size too long:",
211 dst_cq
->bytes_in
+ te_chunked
, "-> 413");
212 /* 413 Payload Too Large */
213 return connection_handle_read_post_error(srv
, con
, 413);
216 te_chunked
+= 2; /*(for trailing "\r\n" after chunked data)*/
218 break; /* read HTTP chunked header */
221 /*(likely better ways to handle chunked header crossing chunkqueue
222 * chunks, but this situation is not expected to occur frequently)*/
223 if ((off_t
)buffer_string_length(c
->mem
) - c
->offset
>= 1024) {
224 log_error_write(srv
, __FILE__
, __LINE__
, "s",
225 "chunked header line too long -> 400");
226 /* 400 Bad Request */
227 return connection_handle_read_post_error(srv
, con
, 400);
229 else if (!connection_handle_read_post_cq_compact(cq
)) {
233 if (0 == te_chunked
) break;
235 if (te_chunked
> 2) {
236 if (len
> te_chunked
-2) len
= te_chunked
-2;
237 if (dst_cq
->bytes_in
+ te_chunked
<= 64*1024) {
238 /* avoid buffering request bodies <= 64k on disk */
239 chunkqueue_steal(dst_cq
, cq
, len
);
241 else if (0 != chunkqueue_steal_with_tempfiles(srv
,dst_cq
,cq
,len
)) {
242 /* 500 Internal Server Error */
243 return connection_handle_read_post_error(srv
, con
, 500);
246 len
= cq
->bytes_in
- cq
->bytes_out
;
249 if (len
< te_chunked
) break;
251 if (2 == te_chunked
) {
252 if (-1 == connection_handle_read_post_chunked_crlf(cq
)) {
253 log_error_write(srv
, __FILE__
, __LINE__
, "s",
254 "chunked data missing end CRLF -> 400");
255 /* 400 Bad Request */
256 return connection_handle_read_post_error(srv
, con
, 400);
258 chunkqueue_mark_written(cq
, 2);/*consume \r\n at end of chunk data*/
262 } while (!chunkqueue_is_empty(cq
));
264 con
->request
.te_chunked
= te_chunked
;
265 return HANDLER_GO_ON
;
268 static handler_t
connection_handle_read_body_unknown(server
*srv
, connection
*con
, chunkqueue
*cq
, chunkqueue
*dst_cq
) {
269 /* con->conf.max_request_size is in kBytes */
270 const off_t max_request_size
= (off_t
)con
->conf
.max_request_size
<< 10;
271 chunkqueue_append_chunkqueue(dst_cq
, cq
);
272 if (0 != max_request_size
&& dst_cq
->bytes_in
> max_request_size
) {
273 log_error_write(srv
, __FILE__
, __LINE__
, "sos",
274 "request-size too long:", dst_cq
->bytes_in
, "-> 413");
275 /* 413 Payload Too Large */
276 return connection_handle_read_post_error(srv
, con
, 413);
278 return HANDLER_GO_ON
;
281 static off_t
connection_write_throttle(server
*srv
, connection
*con
, off_t max_bytes
) {
283 if (con
->conf
.global_kbytes_per_second
) {
284 off_t limit
= con
->conf
.global_kbytes_per_second
* 1024 - *(con
->conf
.global_bytes_per_second_cnt_ptr
);
286 /* we reached the global traffic limit */
287 con
->traffic_limit_reached
= 1;
291 if (max_bytes
> limit
) max_bytes
= limit
;
295 if (con
->conf
.kbytes_per_second
) {
296 off_t limit
= con
->conf
.kbytes_per_second
* 1024 - con
->bytes_written_cur_second
;
298 /* we reached the traffic limit */
299 con
->traffic_limit_reached
= 1;
303 if (max_bytes
> limit
) max_bytes
= limit
;
310 int connection_write_chunkqueue(server
*srv
, connection
*con
, chunkqueue
*cq
, off_t max_bytes
) {
317 max_bytes
= connection_write_throttle(srv
, con
, max_bytes
);
318 if (0 == max_bytes
) return 1;
320 written
= cq
->bytes_out
;
323 /* Linux: put a cork into socket as we want to combine write() calls
324 * but only if we really have multiple chunks including non-MEM_CHUNK,
325 * and only if TCP socket
327 if (cq
->first
&& cq
->first
->next
) {
328 const int sa_family
= sock_addr_get_family(&con
->srv_socket
->addr
);
329 if (sa_family
== AF_INET
|| sa_family
== AF_INET6
) {
330 chunk
*c
= cq
->first
;
331 while (c
->type
== MEM_CHUNK
&& NULL
!= (c
= c
->next
)) ;
334 (void)setsockopt(con
->fd
, IPPROTO_TCP
, TCP_CORK
, &corked
, sizeof(corked
));
340 ret
= con
->network_write(srv
, con
, cq
, max_bytes
);
342 chunkqueue_remove_finished_chunks(cq
);
343 ret
= chunkqueue_is_empty(cq
) ? 0 : 1;
349 (void)setsockopt(con
->fd
, IPPROTO_TCP
, TCP_CORK
, &corked
, sizeof(corked
));
353 written
= cq
->bytes_out
- written
;
354 con
->bytes_written
+= written
;
355 con
->bytes_written_cur_second
+= written
;
356 *(con
->conf
.global_bytes_per_second_cnt_ptr
) += written
;
361 static int connection_write_100_continue(server
*srv
, connection
*con
) {
362 /* Make best effort to send all or none of "HTTP/1.1 100 Continue" */
363 /* (Note: also choosing not to update con->write_request_ts
364 * which differs from connections.c:connection_handle_write()) */
365 static const char http_100_continue
[] = "HTTP/1.1 100 Continue\r\n\r\n";
371 connection_write_throttle(srv
, con
, sizeof(http_100_continue
)-1);
372 if (max_bytes
< (off_t
)sizeof(http_100_continue
)-1) {
373 return 1; /* success; skip sending if throttled to partial */
376 cq
= con
->write_queue
;
377 written
= cq
->bytes_out
;
379 chunkqueue_append_mem(cq
,http_100_continue
,sizeof(http_100_continue
)-1);
380 rc
= con
->network_write(srv
, con
, cq
, sizeof(http_100_continue
)-1);
382 written
= cq
->bytes_out
- written
;
383 con
->bytes_written
+= written
;
384 con
->bytes_written_cur_second
+= written
;
385 *(con
->conf
.global_bytes_per_second_cnt_ptr
) += written
;
388 connection_set_state(srv
, con
, CON_STATE_ERROR
);
389 return 0; /* error */
392 if (written
== sizeof(http_100_continue
)-1) {
393 chunkqueue_remove_finished_chunks(cq
);
394 } else if (0 == written
) {
395 /* skip sending 100 Continue if send would block */
396 chunkqueue_mark_written(cq
, sizeof(http_100_continue
)-1);
397 con
->is_writable
= 0;
399 /* else partial write (unlikely), which can cause corrupt
400 * response if response is later cleared, e.g. sending errdoc.
401 * However, situation of partial write can occur here only on
402 * keep-alive request where client has sent pipelined request,
403 * and more than 0 chars were written, but fewer than 25 chars */
405 return 1; /* success; sent all or none of "HTTP/1.1 100 Continue" */
408 handler_t
connection_handle_read_post_state(server
*srv
, connection
*con
) {
409 chunkqueue
*cq
= con
->read_queue
;
410 chunkqueue
*dst_cq
= con
->request_content_queue
;
414 if (con
->is_readable
) {
415 con
->read_idle_ts
= srv
->cur_ts
;
417 switch(con
->network_read(srv
, con
, con
->read_queue
, MAX_READ_LIMIT
)) {
419 connection_set_state(srv
, con
, CON_STATE_ERROR
);
420 return HANDLER_ERROR
;
429 chunkqueue_remove_finished_chunks(cq
);
431 /* Check for Expect: 100-continue in request headers
432 * if no request body received yet */
433 if (chunkqueue_is_empty(cq
) && 0 == dst_cq
->bytes_in
434 && con
->request
.http_version
!= HTTP_VERSION_1_0
435 && chunkqueue_is_empty(con
->write_queue
) && con
->is_writable
) {
436 data_string
*ds
= (data_string
*)array_get_element(con
->request
.headers
, "Expect");
437 if (NULL
!= ds
&& 0 == buffer_caseless_compare(CONST_BUF_LEN(ds
->value
), CONST_STR_LEN("100-continue"))) {
438 buffer_reset(ds
->value
); /* unset value in request headers */
439 if (!connection_write_100_continue(srv
, con
)) {
440 return HANDLER_ERROR
;
445 if (con
->request
.content_length
< 0) {
446 /*(-1: Transfer-Encoding: chunked, -2: unspecified length)*/
447 handler_t rc
= (-1 == con
->request
.content_length
)
448 ? connection_handle_read_post_chunked(srv
, con
, cq
, dst_cq
)
449 : connection_handle_read_body_unknown(srv
, con
, cq
, dst_cq
);
450 if (HANDLER_GO_ON
!= rc
) return rc
;
452 else if (con
->request
.content_length
<= 64*1024) {
453 /* don't buffer request bodies <= 64k on disk */
454 chunkqueue_steal(dst_cq
, cq
, (off_t
)con
->request
.content_length
- dst_cq
->bytes_in
);
456 else if (0 != chunkqueue_steal_with_tempfiles(srv
, dst_cq
, cq
, (off_t
)con
->request
.content_length
- dst_cq
->bytes_in
)) {
457 /* writing to temp file failed */
458 return connection_handle_read_post_error(srv
, con
, 500); /* Internal Server Error */
461 chunkqueue_remove_finished_chunks(cq
);
463 if (dst_cq
->bytes_in
== (off_t
)con
->request
.content_length
) {
464 /* Content is ready */
465 con
->conf
.stream_request_body
&= ~FDEVENT_STREAM_REQUEST_POLLIN
;
466 if (con
->state
== CON_STATE_READ_POST
) {
467 connection_set_state(srv
, con
, CON_STATE_HANDLE_REQUEST
);
469 return HANDLER_GO_ON
;
470 } else if (is_closed
) {
472 return connection_handle_read_post_error(srv
, con
, 400); /* Bad Request */
474 return HANDLER_ERROR
;
476 con
->conf
.stream_request_body
|= FDEVENT_STREAM_REQUEST_POLLIN
;
477 return (con
->conf
.stream_request_body
& FDEVENT_STREAM_REQUEST
)
479 : HANDLER_WAIT_FOR_EVENT
;
483 void connection_response_reset(server
*srv
, connection
*con
) {
487 con
->http_status
= 0;
488 con
->is_writable
= 1;
489 con
->file_finished
= 0;
490 con
->file_started
= 0;
491 con
->parsed_response
= 0;
492 con
->response
.keep_alive
= 0;
493 con
->response
.content_length
= -1;
494 con
->response
.transfer_encoding
= 0;
495 if (con
->physical
.path
) { /*(skip for mod_fastcgi authorizer)*/
496 buffer_reset(con
->physical
.doc_root
);
497 buffer_reset(con
->physical
.path
);
498 buffer_reset(con
->physical
.basedir
);
499 buffer_reset(con
->physical
.rel_path
);
500 buffer_reset(con
->physical
.etag
);
502 array_reset(con
->response
.headers
);
503 chunkqueue_reset(con
->write_queue
);