root/cherokee/trunk/cherokee/connection.c

Revision 2492, 54.6 kB (checked in by alo, 1 week ago)

--

Line 
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* Cherokee
4  *
5  * Authors:
6  *      Alvaro Lopez Ortega <alvaro@alobbs.com>
7  *
8  * Copyright (C) 2001-2008 Alvaro Lopez Ortega
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of version 2 of the GNU General Public
12  * License as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22  * USA
23  */
24
25 #include "common-internal.h"
26 #include "connection.h"
27 #include "connection-protected.h"
28 #include "bogotime.h"
29
30 #include <errno.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <time.h>
35 #include <sys/types.h>
36
37 #ifdef HAVE_PWD_H
38 # include <pwd.h>
39 #endif
40
41 #ifdef HAVE_SYS_UIO_H
42 # include <sys/uio.h>
43 #endif
44
45 #ifdef HAVE_SYS_SOCKET_H
46 # include <sys/socket.h>
47 #endif
48
49 #ifdef HAVE_ARPA_INET_H
50 # include <arpa/inet.h>
51 #endif
52
53 #ifdef HAVE_NETINET_IN_H
54 # include <netinet/in.h>
55 #endif
56
57 #ifdef HAVE_NETINET_TCP_H
58 # include <netinet/tcp.h>
59 #endif
60
61 #ifdef HAVE_STRINGS_H
62 # include <strings.h>
63 #endif
64
65 #include "util.h"
66 #include "list.h"
67 #include "http.h"
68 #include "handler.h"
69 #include "thread.h"
70 #include "handler_error.h"
71 #include "buffer.h"
72 #include "config_entry.h"
73 #include "server-protected.h"
74 #include "access.h"
75 #include "virtual_server.h"
76 #include "socket.h"
77 #include "header.h"
78 #include "header-protected.h"
79 #include "iocache.h"
80 #include "dtm.h"
81
82 #define ENTRIES "core,connection"
83
84
85 ret_t
86 cherokee_connection_new  (cherokee_connection_t **conn)
87 {
88         CHEROKEE_NEW_STRUCT(n, connection);
89            
90         INIT_LIST_HEAD (&n->list_node);
91
92         n->error_code           = http_ok;
93         n->phase                = phase_reading_header;
94         n->auth_type            = http_auth_nothing;
95         n->req_auth_type        = http_auth_nothing;
96         n->upgrade              = http_upgrade_nothing;
97         n->options              = conn_op_log_at_end;
98         n->handler              = NULL;
99         n->encoder              = NULL;
100         n->logger_ref           = NULL;
101         n->keepalive            = 0;
102         n->range_start          = 0;
103         n->range_end            = 0;
104         n->vserver              = NULL;
105         n->arguments            = NULL;
106         n->realm_ref            = NULL;
107         n->mmaped               = NULL;
108         n->mmaped_len           = 0;
109         n->io_entry_ref         = NULL;
110         n->thread               = NULL;
111         n->rx                   = 0;   
112         n->tx                   = 0;
113         n->rx_partial           = 0;
114         n->tx_partial           = 0;
115         n->traffic_next         = 0;
116         n->validator            = NULL;
117         n->timeout              = -1;
118         n->polling_fd           = -1;
119         n->polling_multiple     = false;
120         n->polling_mode         = FDPOLL_MODE_NONE;
121         n->expiration           = cherokee_expiration_none;
122         n->expiration_time      = 0;
123         n->respins              = 0;
124
125         cherokee_buffer_init (&n->buffer);
126         cherokee_buffer_init (&n->header_buffer);
127         cherokee_buffer_init (&n->incoming_header);
128         cherokee_buffer_init (&n->encoder_buffer);
129
130         cherokee_buffer_init (&n->local_directory);
131         cherokee_buffer_init (&n->web_directory);
132         cherokee_buffer_init (&n->effective_directory);
133         cherokee_buffer_init (&n->userdir);
134         cherokee_buffer_init (&n->request);
135         cherokee_buffer_init (&n->pathinfo);
136         cherokee_buffer_init (&n->redirect);
137         cherokee_buffer_init (&n->host);
138         cherokee_buffer_init (&n->self_trace);
139
140         cherokee_buffer_init (&n->query_string);
141         cherokee_buffer_init (&n->request_original);
142
143         cherokee_socket_init (&n->socket);
144         cherokee_header_init (&n->header, header_type_request);
145         cherokee_post_init (&n->post);
146
147         memset (n->regex_ovector, OVECTOR_LEN * sizeof(int), 0);
148         n->regex_ovecsize = 0;
149
150         n->chunked_encoding     = false;
151         n->chunked_sent         = 0;
152         n->chunked_last_package = false;
153         cherokee_buffer_init (&n->chunked_len);
154
155         *conn = n;
156         return ret_ok;
157 }
158
159
160 ret_t
161 cherokee_connection_free (cherokee_connection_t  *conn)
162 {
163         cherokee_header_mrproper (&conn->header);
164         cherokee_socket_mrproper (&conn->socket);
165        
166         if (conn->handler != NULL) {
167                 cherokee_handler_free (conn->handler);
168                 conn->handler = NULL;
169         }
170
171         if (conn->encoder != NULL) {
172                 cherokee_encoder_free (conn->encoder);
173                 conn->encoder = NULL;
174         }
175
176         cherokee_post_mrproper (&conn->post);
177        
178         cherokee_buffer_mrproper (&conn->request);
179         cherokee_buffer_mrproper (&conn->request_original);
180
181         cherokee_buffer_mrproper (&conn->pathinfo);
182         cherokee_buffer_mrproper (&conn->buffer);
183         cherokee_buffer_mrproper (&conn->header_buffer);
184         cherokee_buffer_mrproper (&conn->incoming_header);
185         cherokee_buffer_mrproper (&conn->query_string);
186         cherokee_buffer_mrproper (&conn->encoder_buffer);
187
188         cherokee_buffer_mrproper (&conn->local_directory);
189         cherokee_buffer_mrproper (&conn->web_directory);
190         cherokee_buffer_mrproper (&conn->effective_directory);
191         cherokee_buffer_mrproper (&conn->userdir);
192         cherokee_buffer_mrproper (&conn->redirect);
193         cherokee_buffer_mrproper (&conn->host);
194         cherokee_buffer_mrproper (&conn->self_trace);
195         cherokee_buffer_mrproper (&conn->chunked_len);
196
197         if (conn->validator != NULL) {
198                 cherokee_validator_free (conn->validator);
199                 conn->validator = NULL;
200         }
201
202         if (conn->arguments != NULL) {
203                 cherokee_avl_free (conn->arguments, free);
204                 conn->arguments = NULL;
205         }
206
207         if (conn->polling_fd != -1) {
208                 close (conn->polling_fd);
209                 conn->polling_fd   = -1;
210                 conn->polling_mode = FDPOLL_MODE_NONE;
211         }
212        
213         free (conn);
214         return ret_ok;
215 }
216
217
218 ret_t
219 cherokee_connection_clean (cherokee_connection_t *conn)
220 {         
221         uint32_t header_len;
222         size_t   crlf_len;
223
224         /* I/O cache entry reference
225          */
226         if (conn->io_entry_ref != NULL) {
227                 cherokee_iocache_entry_unref (&conn->io_entry_ref);
228                 conn->io_entry_ref = NULL;
229         }
230
231         /* TCP cork
232          */
233         if (conn->options & conn_op_tcp_cork) {
234                 cherokee_connection_set_cork (conn, false);
235                 BIT_UNSET (conn->options, conn_op_tcp_cork);           
236         }
237
238         conn->timeout              = -1;
239         conn->phase                = phase_reading_header;
240         conn->auth_type            = http_auth_nothing;
241         conn->req_auth_type        = http_auth_nothing;
242         conn->upgrade              = http_upgrade_nothing;
243         conn->options              = conn_op_log_at_end;
244         conn->error_code           = http_ok;
245         conn->range_start          = 0;
246         conn->range_end            = 0;
247         conn->logger_ref           = NULL;
248         conn->realm_ref            = NULL;
249         conn->mmaped               = NULL;
250         conn->mmaped_len           = 0;
251         conn->rx                   = 0;
252         conn->tx                   = 0;
253         conn->rx_partial           = 0;
254         conn->tx_partial           = 0;
255         conn->traffic_next         = 0;
256         conn->polling_multiple     = false;
257         conn->polling_mode         = FDPOLL_MODE_NONE;
258         conn->expiration           = cherokee_expiration_none;
259         conn->expiration_time      = 0;
260         conn->chunked_encoding     = false;
261         conn->chunked_sent         = 0;
262         conn->chunked_last_package = false;
263         conn->respins              = 0;
264
265         memset (conn->regex_ovector, OVECTOR_LEN * sizeof(int), 0);
266         conn->regex_ovecsize = 0;
267
268         if (conn->handler != NULL) {
269                 cherokee_handler_free (conn->handler);
270                 conn->handler = NULL;
271         }
272        
273         if (conn->encoder != NULL) {
274                 cherokee_encoder_free (conn->encoder);
275                 conn->encoder = NULL;
276         }
277
278         if (conn->polling_fd != -1) {
279                 close (conn->polling_fd);
280                 conn->polling_fd = -1;
281         }
282
283         cherokee_post_mrproper (&conn->post);
284         cherokee_buffer_mrproper (&conn->encoder_buffer);
285
286         cherokee_buffer_clean (&conn->request);
287         cherokee_buffer_clean (&conn->request_original);
288
289         cherokee_buffer_clean (&conn->pathinfo);
290         cherokee_buffer_clean (&conn->local_directory);
291         cherokee_buffer_clean (&conn->web_directory);
292         cherokee_buffer_clean (&conn->effective_directory);
293         cherokee_buffer_clean (&conn->userdir);
294         cherokee_buffer_clean (&conn->redirect);
295         cherokee_buffer_clean (&conn->host);
296         cherokee_buffer_clean (&conn->query_string);
297         cherokee_buffer_clean (&conn->self_trace);
298         cherokee_buffer_clean (&conn->chunked_len);
299        
300         if (conn->validator != NULL) {
301                 cherokee_validator_free (conn->validator);
302                 conn->validator = NULL;
303         }
304
305         if (conn->arguments != NULL) {
306                 cherokee_avl_free (conn->arguments, free);
307                 conn->arguments = NULL;
308         }
309
310         /* Drop out the last incoming header
311          */
312         cherokee_header_get_length (&conn->header, &header_len);
313
314         cherokee_header_clean (&conn->header);
315         cherokee_buffer_clean (&conn->buffer);
316         cherokee_buffer_clean (&conn->header_buffer);
317        
318         /* Skip trailing CRLF (which may be sent by some HTTP clients)
319          * only if the number of CRLFs is within the predefine count
320          * limit otherwise ignore trailing CRLFs so that they will be
321          * handled in next request.  This may avoid a subsequent real
322          * move_to_begin of the contents left in the buffer.
323          */
324         crlf_len = cherokee_buffer_cnt_spn (&conn->incoming_header, header_len, CRLF);
325         header_len += (crlf_len <= MAX_HEADER_CRLF) ? crlf_len : 0;
326
327         cherokee_buffer_move_to_begin (&conn->incoming_header, header_len);
328
329         /* If the connection has incoming headers to be processed,
330          * then increment the pending counter from the thread
331          */     
332         if (! cherokee_buffer_is_empty (&conn->incoming_header)) {
333                 CONN_THREAD(conn)->pending_conns_num++;
334         }
335
336         TRACE (ENTRIES, "conn %p, has headers %d\n", conn,
337                !cherokee_buffer_is_empty (&conn->incoming_header));
338
339         return ret_ok;
340 }
341
342
343 ret_t
344 cherokee_connection_clean_close (cherokee_connection_t *conn)
345 {
346         /* Close and clean the socket
347          */
348         cherokee_socket_close (&conn->socket);
349         cherokee_socket_clean (&conn->socket);
350
351         /* Make sure the connection Keep-Alive is disabled
352          */
353         conn->keepalive = 0;
354         cherokee_buffer_clean (&conn->incoming_header);
355
356         /* Clean the connection object
357          */
358         cherokee_connection_clean (conn);
359         return ret_ok;
360 }
361
362
363 ret_t
364 cherokee_connection_setup_error_handler (cherokee_connection_t *conn)
365 {
366         ret_t                       ret;
367         cherokee_server_t          *srv;
368         cherokee_virtual_server_t  *vsrv;
369         cherokee_config_entry_t    *entry;     
370
371         srv   = CONN_SRV(conn);
372         vsrv  = CONN_VSRV(conn);
373         entry = vsrv->error_handler;
374
375         /* It has a common handler. It has to be freed.
376          */
377         if (conn->handler != NULL) {
378                 cherokee_handler_free (conn->handler);
379                 conn->handler = NULL;
380         }
381
382         /* Create a new error handler
383          */
384         if ((entry != NULL) && (entry->handler_new_func != NULL)) {
385                 ret = entry->handler_new_func ((void **) &conn->handler, conn, entry->handler_properties);
386                 if (ret == ret_ok)
387                         goto out;
388         }
389
390         /* If something was wrong, try with the default error handler
391          */
392         ret = cherokee_handler_error_new (&conn->handler, conn, NULL);
393
394 out:
395 #ifdef TRACE_ENABLED
396         {
397                 const char *name = NULL;
398
399                 cherokee_module_get_name (MODULE(conn->handler), &name);
400                 TRACE(ENTRIES, "New handler %s\n", name);
401         }
402 #endif
403
404         /* Only 3xx errors can keep the connection alive
405          */
406         if ((! (http_type_300 (conn->error_code))) ||
407             (! (conn->handler->support & hsupport_length)))
408         {
409                 conn->keepalive = 0;
410         }
411
412         /* Nothing should be mmaped any longer
413          */
414         if (conn->io_entry_ref != NULL) {
415                 cherokee_iocache_entry_unref (&conn->io_entry_ref);
416         }
417
418         conn->io_entry_ref = NULL;
419         conn->mmaped       = NULL;
420         conn->mmaped_len   = 0;
421
422         /* It does not matter whether the previous handler wanted to
423          * use Chunked encoding.
424          */
425         conn->chunked_encoding = false;
426
427         return ret_ok;
428 }
429
430
431 static void
432 build_response_header_authentication (cherokee_connection_t *conn, cherokee_buffer_t *buffer)
433 {
434         ret_t ret;
435
436         /* Basic Authenticatiom
437          * Eg: WWW-Authenticate: Basic realm=""
438          */
439         if (conn->auth_type & http_auth_basic) {
440                 cherokee_buffer_add_str (buffer, "WWW-Authenticate: Basic realm=\"");
441                 cherokee_buffer_add_buffer (buffer, conn->realm_ref);
442                 cherokee_buffer_add_str (buffer, "\""CRLF);
443         }
444
445         /* Digest Authentication, Eg:
446          * WWW-Authenticate: Digest realm="", qop="auth,auth-int",
447          *                   nonce="", opaque=""
448          */
449         if (conn->auth_type & http_auth_digest) {
450                 cherokee_thread_t *thread = CONN_THREAD(conn);
451                 cherokee_buffer_t *new_nonce = THREAD_TMP_BUF1(thread);
452
453                 /* Realm
454                  */
455                 cherokee_buffer_add_str (buffer, "WWW-Authenticate: Digest realm=\"");
456                 cherokee_buffer_add_buffer (buffer, conn->realm_ref);
457                 cherokee_buffer_add_str (buffer, "\", ");
458
459                 /* Nonce:
460                  * "nonce=\"%s\", "
461                  */
462                 ret = ret_not_found;
463
464                 if ((conn->validator != NULL) &&
465                     (! cherokee_buffer_is_empty (&conn->validator->nonce)))
466                 {
467                         ret = cherokee_nonce_table_check (CONN_SRV(conn)->nonces,
468                                                           &conn->validator->nonce);
469                 }
470
471                 cherokee_buffer_add_str (buffer, "nonce=\"");                   
472                 if (ret != ret_ok) {
473                         cherokee_nonce_table_generate (CONN_SRV(conn)->nonces, conn, new_nonce);
474                         cherokee_buffer_add_buffer (buffer, new_nonce);
475                 } else {
476                         cherokee_buffer_add_buffer (buffer, &conn->validator->nonce);
477                 }
478                 cherokee_buffer_add_str (buffer, "\", ");
479
480                                
481                 /* Quality of protection: auth, auth-int, auth-conf
482                  * Algorithm: MD5
483                  */
484                 cherokee_buffer_add_str (buffer, "qop=\"auth\", algorithm=\"MD5\""CRLF);
485         }
486 }
487
488
489 static void
490 build_response_header_expiration (cherokee_connection_t *conn, cherokee_buffer_t *buffer)
491 {
492         time_t    exp_time;
493         struct tm exp_tm;
494         size_t    szlen = 0;
495         char      bufstr[DTM_SIZE_GMTTM_STR + 2];
496
497         switch (conn->expiration) {
498         case cherokee_expiration_epoch:
499                 cherokee_buffer_add_str (buffer, "Expires: Tue, 01 Jan 1970 00:00:01 GMT" CRLF);
500                 cherokee_buffer_add_str (buffer, "Cache-Control: no-cache" CRLF);
501                 break;
502         case cherokee_expiration_max:
503                 cherokee_buffer_add_str (buffer, "Expires: Thu, 31 Dec 2037 23:55:55 GMT" CRLF);
504                 cherokee_buffer_add_str (buffer, "Cache-Control: max-age=315360000" CRLF);
505                 break;
506         case cherokee_expiration_time:
507                 exp_time = (cherokee_bogonow_now + conn->expiration_time);
508                 cherokee_gmtime (&exp_time, &exp_tm);
509                 szlen = cherokee_dtm_gmttm2str (bufstr, sizeof(bufstr), &exp_tm);
510
511                 cherokee_buffer_add_str (buffer, "Expires: ");
512                 cherokee_buffer_add (buffer, bufstr, szlen);
513                 cherokee_buffer_add_str (buffer, CRLF);
514
515                 cherokee_buffer_add_str (buffer, "Cache-Contro: max-age=");
516                 cherokee_buffer_add_long10 (buffer, conn->expiration_time);
517                 cherokee_buffer_add_str (buffer, CRLF);
518                 break;
519         default:
520                 SHOULDNT_HAPPEN;
521         }
522 }
523
524
525 static void
526 build_response_header (cherokee_connection_t *conn, cherokee_buffer_t *buffer)
527 {       
528         /* Build the response header.
529          */
530         cherokee_buffer_clean (buffer);
531
532         /* Add protocol string + error_code
533          */
534         switch (conn->header.version) {
535         case http_version_10:
536                 cherokee_buffer_add_str (buffer, "HTTP/1.0 ");
537                 break;
538         case http_version_11:
539         default:
540                 cherokee_buffer_add_str (buffer, "HTTP/1.1 ");
541                 break;
542         }
543        
544         cherokee_http_code_copy (conn->error_code, buffer);
545         cherokee_buffer_add_str (buffer, CRLF);
546
547         /* Add the "Connection:" header
548          */
549         if (conn->upgrade != http_upgrade_nothing) {
550                 cherokee_buffer_add_str (buffer, "Connection: Upgrade"CRLF);
551
552         } else if (conn->handler && (conn->keepalive > 0)) {
553                 cherokee_buffer_add_str (buffer, "Connection: Keep-Alive"CRLF);
554                 cherokee_buffer_add_buffer (buffer, &CONN_SRV(conn)->timeout_header);
555         } else {
556                 cherokee_buffer_add_str (buffer, "Connection: close"CRLF);
557         }
558
559         /* Chunked transfer
560          */
561         if (conn->chunked_encoding) {
562                 cherokee_buffer_add_str (buffer, "Transfer-Encoding: chunked" CRLF);
563         }
564
565         /* Exit now if the handler already added all the headers
566          */
567         if (HANDLER_SUPPORTS (conn->handler, hsupport_full_headers))
568                 return;
569
570         /* Date
571          */
572         cherokee_buffer_add_str (buffer, "Date: ");
573         cherokee_buffer_add_buffer (buffer, &cherokee_bogonow_strgmt);
574         cherokee_buffer_add_str (buffer, CRLF);
575
576         /* Add the Server header
577          */
578         cherokee_buffer_add_str (buffer, "Server: ");
579         cherokee_buffer_add_buffer (buffer, &CONN_SRV(conn)->server_string);
580         cherokee_buffer_add_str (buffer, CRLF);
581
582         /* Authentication
583          */
584         if ((conn->realm_ref != NULL) && (conn->error_code == http_unauthorized)) {
585                 build_response_header_authentication (conn, buffer);
586         }
587
588         /* Expiration
589          */
590         if (conn->expiration != cherokee_expiration_none) {
591                 build_response_header_expiration (conn, buffer);
592         }
593
594         /* Redirected connections
595          */
596         if (conn->redirect.len >= 1) {
597                 cherokee_buffer_add_str (buffer, "Location: ");
598                 cherokee_buffer_add_buffer (buffer, &conn->redirect);
599                 cherokee_buffer_add_str (buffer, CRLF);
600         }
601
602         /* Encoder headers
603          */
604         if (conn->encoder) {
605                 cherokee_encoder_add_headers (conn->encoder, buffer);
606         }
607
608         /* Unusual methods
609          */
610         if (conn->header.method == http_options) {
611                 cherokee_buffer_add_str (buffer, "Allow: GET, HEAD, POST, OPTIONS"CRLF);
612         }
613 }
614
615
616 ret_t
617 cherokee_connection_build_header (cherokee_connection_t *conn)
618 {
619         ret_t              ret;
620         cherokee_boolean_t try_chunked = false;
621        
622         /* If the handler requires not to add headers, exit.
623          */
624         if (HANDLER_SUPPORTS (conn->handler, hsupport_skip_headers))
625                 return ret_ok;
626
627         /* Try to get the headers from the handler
628          */
629         ret = cherokee_handler_add_headers (conn->handler, &conn->header_buffer);
630         if (unlikely (ret != ret_ok)) {
631                 switch (ret) {
632                 case ret_eof:
633                 case ret_error:
634                 case ret_eagain:
635                         return ret;
636                 default:
637                         RET_UNKNOWN(ret);
638                         return ret_error;
639                 }
640         }
641
642         /* If the connection is using Kee-Alive, it must either know
643          * the length or use chunked encoding. Otherwise, Keep-Alive
644          * has to be turned off.
645          */
646         if ((conn->keepalive != 0) &&
647             (http_method_with_body (conn->error_code)))
648         {               
649                 if (HANDLER_SUPPORTS (conn->handler, hsupport_maybe_length)) {
650                         if (! strcasestr (conn->header_buffer.buf, "Content-Length: ")) {
651                                 try_chunked = true;
652                         }
653                 } else if (! HANDLER_SUPPORTS (conn->handler, hsupport_length)) {
654                         try_chunked = true;
655                 }               
656
657                 if (try_chunked) {
658                         /* Turn chunked encoding on, if possible
659                          */
660                         conn->chunked_encoding = ((CONN_SRV(conn)->chunked_encoding) &&
661                                                   (conn->header.version == http_version_11));
662
663                         if (! conn->chunked_encoding)
664                                 conn->keepalive = 0;
665                 }
666         }
667
668         /* Add the server headers       
669          */
670         build_response_header (conn, &conn->buffer);
671
672         /* Add handler headers end EOH
673          */
674         cherokee_buffer_add_buffer (&conn->buffer, &conn->header_buffer);
675         cherokee_buffer_add_str (&conn->buffer, CRLF);
676
677         return ret_ok;
678 }
679
680
681 ret_t
682 cherokee_connection_send_header_and_mmaped (cherokee_connection_t *conn)
683 {
684         size_t  re = 0;
685         ret_t   ret;
686         int16_t nvec = 1;
687         struct iovec bufs[2];
688
689         /* 1.- Special case: There is not header to send
690          * because it has been sent by writev() (see below)
691          */
692         if (cherokee_buffer_is_empty (&conn->buffer)) {
693                 ret = cherokee_socket_write (&conn->socket, conn->mmaped, conn->mmaped_len, &re);
694                 if (unlikely (ret != ret_ok) ) {
695                         switch (ret) {
696                         case ret_eof:
697                         case ret_eagain:
698                                 return ret;
699
700                         case ret_error:
701                                 conn->keepalive = 0;
702                                 return ret;
703
704                         default:
705                                 conn->keepalive = 0;
706                                 RET_UNKNOWN(ret);
707                                 return ret_error;
708                         }
709                 }               
710                 cherokee_connection_tx_add (conn, re);
711
712                 /* NOTE: conn->mmaped is a ptr. to void
713                  * so we have to apply ptr. math carefully.
714                  */
715                 conn->mmaped      = (void *) ( ((char *)conn->mmaped) + re );
716                 conn->mmaped_len -= (off_t) re;
717
718                 return (conn->mmaped_len > 0) ? ret_eagain : ret_ok;
719         }
720
721         /* 2.- There are header and mmaped content to send
722          */
723         bufs[0].iov_base = conn->buffer.buf;
724         bufs[0].iov_len  = conn->buffer.len;
725         if (likely (conn->mmaped_len > 0)) {
726                 bufs[1].iov_base = conn->mmaped;
727                 bufs[1].iov_len  = conn->mmaped_len;
728                 nvec = 2;
729         }
730         ret = cherokee_socket_writev (&conn->socket, bufs, nvec, &re);
731         if (unlikely (ret != ret_ok)) {
732                 switch (ret) {
733
734                 case ret_eof:
735                 case ret_eagain:
736                         return ret;
737
738                 case ret_error:
739                         conn->keepalive = 0;
740                         return ret_error;
741
742                 default:
743                         RET_UNKNOWN(ret);
744                         return ret_error;
745                 }
746         }
747         /* Add to the connection traffic counter
748          */
749         cherokee_connection_tx_add (conn, re);
750
751         /* writev() may not have sent all headers data.
752          */
753         if (unlikely (re < (size_t) conn->buffer.len)) {
754                 /* Partial header data sent.
755                  */
756                 cherokee_buffer_move_to_begin (&conn->buffer, re);
757                 return ret_eagain;
758         }
759
760         /* OK, all headers have been sent,
761          * subtract from amount sent and clean header buffer.
762          */
763         re -= (size_t) conn->buffer.len;
764         cherokee_buffer_clean (&conn->buffer);
765
766         /* NOTE: conn->mmaped is a ptr. to void
767          * so we have to apply ptr. math carefully.
768          */
769         conn->mmaped      = (void *) ( ((char *)conn->mmaped) + re );
770         conn->mmaped_len -= (off_t) re;
771
772         return (conn->mmaped_len > 0) ? ret_eagain : ret_ok;
773 }
774
775
776 void
777 cherokee_connection_rx_add (cherokee_connection_t *conn, ssize_t rx)
778 {
779         conn->rx += rx;
780         conn->rx_partial += rx;
781 }
782
783
784 void
785 cherokee_connection_tx_add (cherokee_connection_t *conn, ssize_t tx)
786 {
787         conn->tx += tx;
788         conn->tx_partial += tx;
789 }
790
791
792 ret_t
793 cherokee_connection_recv (cherokee_connection_t *conn, cherokee_buffer_t *buffer, off_t *len)
794 {
795         ret_t  ret;
796         size_t cnt_read = 0;
797        
798         ret = cherokee_socket_bufread (&conn->socket, buffer, DEFAULT_RECV_SIZE, &cnt_read);
799         switch (ret) {
800         case ret_ok:
801                 cherokee_connection_rx_add (conn, cnt_read);
802                 *len = cnt_read;
803                 return ret_ok;
804
805         case ret_eof:
806         case ret_error:
807                 return ret;
808
809         case ret_eagain:
810                 if (cherokee_socket_pending_read (&conn->socket)) {
811                         CONN_THREAD(conn)->pending_read_num += 1;
812                 }
813                 return ret_eagain;
814
815         default:
816                 RET_UNKNOWN(ret);               
817                 return ret_error;
818         }
819         /* NOTREACHED */
820 }
821
822
823 ret_t
824 cherokee_connection_reading_check (cherokee_connection_t *conn)
825 {
826         /* Check for too long headers
827          */
828         if (conn->incoming_header.len > MAX_HEADER_LEN) {
829                 conn->error_code = http_request_entity_too_large;
830                 return ret_error;
831         }
832
833         return ret_ok;
834 }
835
836
837 ret_t
838 cherokee_connection_set_cork (cherokee_connection_t *conn,
839                               cherokee_boolean_t     enable)
840 {
841         ret_t ret;
842
843         ret = cherokee_socket_set_cork (&conn->socket, enable);
844         if (unlikely (ret != ret_ok)) {
845                 return ret;
846         }
847
848         if (enable)
849                 BIT_SET (conn->options, conn_op_tcp_cork);
850         else
851                 BIT_UNSET (conn->options, conn_op_tcp_cork);
852
853         return ret_ok;
854 }
855
856
857 ret_t
858 cherokee_connection_send_header (cherokee_connection_t *conn)
859 {
860         ret_t  ret;
861         size_t sent = 0;
862
863         if (cherokee_buffer_is_empty (&conn->buffer))
864                 return ret_ok;
865
866         /* Send the buffer content
867          */
868         ret = cherokee_socket_bufwrite (&conn->socket, &conn->buffer, &sent);
869         if (unlikely(ret != ret_ok)) return ret;
870        
871         /* Add to the connection traffic counter
872          */
873         cherokee_connection_tx_add (conn, sent);
874
875         /* Drop out the sent data
876          */
877         if (sent == conn->buffer.len) {
878                 cherokee_buffer_clean (&conn->buffer);
879                 return ret_ok;
880         }
881
882         /* There is still some data waiting to be sent
883          */
884         cherokee_buffer_move_to_begin (&conn->buffer, sent);
885         return ret_eagain;
886 }
887
888
889 ret_t
890 cherokee_connection_send (cherokee_connection_t *conn)
891 {
892         ret_t  ret;
893         size_t sent = 0;
894
895         /* Use writev to send the chunk-begin mark
896          */
897         if (conn->chunked_encoding)
898         {
899                 struct iovec tmp[3];
900
901                 tmp[0].iov_base = conn->chunked_len.buf;
902                 tmp[0].iov_len  = conn->chunked_len.len;
903                 tmp[1].iov_base = conn->buffer.buf;
904                 tmp[1].iov_len  = conn->buffer.len;
905
906                 if (conn->chunked_last_package) {
907                         tmp[2].iov_base = CRLF "0" CRLF CRLF;
908                         tmp[2].iov_len  = 7;
909                 } else {
910                         tmp[2].iov_base = CRLF;
911                         tmp[2].iov_len  = 2;
912                 }
913
914                 cherokee_iovec_skip_sent (tmp, 3,
915                                           conn->chunks, &conn->chunksn,
916                                           conn->chunked_sent);
917
918                 ret = cherokee_socket_writev (&conn->socket, conn->chunks, conn->chunksn, &sent);
919                 if (unlikely (ret != ret_ok)) {
920                         switch (ret) {
921                         case ret_eof:
922                         case ret_eagain:
923                                 return ret;
924                                
925                         case ret_error:
926                                 conn->keepalive = 0;
927                                 return ret_error;
928                                
929                         default:
930                                 RET_UNKNOWN(ret);
931                                 return ret_error;
932                         }
933                 }
934
935                 conn->chunked_sent += sent;
936
937                 /* Clean the information buffer only when everything
938                  * has been sent.
939                  */
940                 ret = cherokee_iovec_was_sent (tmp, 3, conn->chunked_sent);
941                 if (ret == ret_ok) {
942                         cherokee_buffer_clean (&conn->chunked_len);
943                         cherokee_buffer_clean (&conn->buffer);
944                         ret = ret_ok;
945                 } else {
946                         ret = ret_eagain;
947                 }
948
949                 goto out;
950         }
951
952         /* Send the buffer content
953          */
954         ret = cherokee_socket_bufwrite (&conn->socket, &conn->buffer, &sent);
955         if (unlikely(ret != ret_ok)) return ret;
956
957         /* Drop out the sent info
958          */
959         if (sent == conn->buffer.len) {
960                 cherokee_buffer_clean (&conn->buffer);
961                 ret = ret_ok;
962         } else if (sent != 0) {
963                 cherokee_buffer_move_to_begin (&conn->buffer, sent);
964                 ret = ret_eagain;
965         }
966
967 out:
968         /* Add to the connection traffic counter
969          */
970         cherokee_connection_tx_add (conn, sent);
971
972         /* If this connection has a handler without Content-Length support
973          * it has to count the bytes sent
974          */
975         if (!HANDLER_SUPPORTS (conn->handler, hsupport_length)) {
976                 conn->range_end += sent;
977         }
978
979         return ret;
980 }
981
982
983 ret_t
984 cherokee_connection_shutdown_wr (cherokee_connection_t *conn)
985 {
986         /* At this point, we don't want to follow the TLS protocol
987          * any longer.
988          */
989         conn->socket.is_tls = non_TLS;
990
991         /* Set the timeout for future linger read(s) leaving the
992          * non-blocking mode.
993          */
994         conn->timeout = CONN_THREAD(conn)->bogo_now + (MSECONDS_TO_LINGER / 1000) + 1;
995
996         /* Shut down the socket for write, which will send a FIN to
997          * the peer. If shutdown fails then the socket is unusable.
998          */
999         return cherokee_socket_shutdown (&conn->socket, SHUT_WR);
1000 }
1001
1002
1003 ret_t
1004 cherokee_connection_linger_read (cherokee_connection_t *conn)
1005 {
1006         ret_t              ret;
1007         size_t             cnt_read = 0;
1008         int                retries  = 2;
1009         cherokee_thread_t *thread   = CONN_THREAD(conn);
1010         cherokee_buffer_t *tmp1     = THREAD_TMP_BUF1(thread);
1011
1012         while (true) {
1013                 /* Read from the socket to nowhere
1014                  */
1015                 ret = cherokee_socket_read (&conn->socket, tmp1->buf, tmp1->size, &cnt_read);
1016                 switch (ret) {
1017                 case ret_eof:
1018                         TRACE(ENTRIES, "%s\n", "eof");
1019                         return ret;
1020                 case ret_error:
1021                         TRACE(ENTRIES, "%s\n", "error");
1022                         return ret;
1023                 case ret_eagain:
1024                         TRACE(ENTRIES, "read %u, eagain\n", cnt_read);
1025                         return ret;
1026                 case ret_ok:
1027                         TRACE(ENTRIES, "read %u, ok\n", cnt_read);
1028                         retries--;
1029                         if (cnt_read == tmp1->size && retries > 0)
1030                                 continue;
1031                         return ret;
1032                 default:
1033                         RET_UNKNOWN(ret);               
1034                         return ret_error;
1035                 }
1036                 /* NOTREACHED */
1037         }
1038 }
1039
1040
1041 ret_t
1042 cherokee_connection_step (cherokee_connection_t *conn)
1043 {
1044         ret_t ret;
1045         ret_t step_ret = ret_ok;
1046
1047         return_if_fail (conn->handler != NULL, ret_error);
1048
1049         /* Need to 'read' from handler ?
1050       &