Changeset 1947

Show
Ignore:
Timestamp:
09/05/08 12:57:58 (4 months ago)
Author:
alo
Message:

--

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • cherokee/trunk/ChangeLog

    r1946 r1947  
     12008-09-05  Alvaro Lopez Ortega  <alvaro@alobbs.com> 
     2 
     3        * cherokee/connection-protected.h, cherokee/handler_cgi_base.c, 
     4        cherokee/handler_cgi_base.h, cherokee/handler.h, cherokee/util.h, 
     5        cherokee/util.c, cherokee/connection.c: Reimplements the Chunked 
     6        encoding support.  Now it is system-wide and does less memory 
     7        moves/allocations. 
     8 
    192008-09-04  Alvaro Lopez Ortega  <alvaro@alobbs.com> 
    210 
  • cherokee/trunk/cherokee/connection-protected.h

    r1944 r1947  
    198198        cherokee_boolean_t            chunked_encoding; 
    199199        cherokee_buffer_t             chunked_len; 
     200        size_t                        chunked_sent; 
     201        struct iovec                  chunks[3]; 
     202        uint16_t                      chunksn; 
    200203}; 
    201204 
  • cherokee/trunk/cherokee/connection.c

    r1945 r1947  
    149149 
    150150        n->chunked_encoding = false; 
     151        n->chunked_sent     = 0; 
    151152        cherokee_buffer_init (&n->chunked_len); 
    152153 
     
    257258        conn->expiration_time      = 0; 
    258259        conn->chunked_encoding     = false; 
     260        conn->chunked_sent         = 0; 
    259261 
    260262        memset (conn->regex_ovector, OVECTOR_LEN * sizeof(int), 0); 
     
    626628        } 
    627629 
    628         /* It might need to deactive Keep-Alive after checking the 
    629          * handler headers.. 
     630        /* If the connection is using Kee-Alive, it must either know 
     631         * the length or use chunked encoding. Otherwise, Keep-Alive 
     632         * has to be turned off. 
    630633         */ 
    631634        if ((conn->keepalive != 0) && 
    632             (conn->chunked_encoding == false) && 
    633635            (http_method_with_body (conn->error_code)))  
    634636        { 
    635                 if (HANDLER_SUPPORTS (conn->handler, hsupport_maybe_length)) { 
    636                         if (strcasestr (conn->header_buffer.buf, "Content-Length: ") == NULL) 
     637                if ((! HANDLER_SUPPORTS (conn->handler, hsupport_length)) || 
     638                    ((HANDLER_SUPPORTS (conn->handler, hsupport_maybe_length)) && 
     639                     (! strcasestr (conn->header_buffer.buf, "Content-Length: ")))) 
     640                { 
     641                        conn->chunked_encoding = ( 
     642                                // srv->allow_chunked 
     643                                (conn->header.version == http_version_11)); 
     644 
     645                        if (! conn->chunked_encoding) 
    637646                                conn->keepalive = 0; 
    638                          
    639                 } else if (! HANDLER_SUPPORTS (conn->handler, hsupport_length)) { 
    640                         conn->keepalive = 0; 
    641647                } 
    642648        } 
     
    866872        /* Use writev to send the chunk-begin mark 
    867873         */ 
    868         if ((conn->chunked_encoding) && 
    869             (! cherokee_buffer_is_empty (&conn->chunked_len))) 
     874        if (conn->chunked_encoding)  
    870875        { 
    871                 struct iovec bufs[2]; 
    872  
    873                 bufs[0].iov_base = conn->chunked_len.buf; 
    874                 bufs[0].iov_len  = conn->chunked_len.len; 
    875                 bufs[1].iov_base = conn->buffer.buf; 
    876                 bufs[1].iov_len  = conn->buffer.len; 
    877  
    878                 ret = cherokee_socket_writev (&conn->socket, bufs, 2, &sent); 
     876                struct iovec tmp[3]; 
     877 
     878                tmp[0].iov_base = conn->chunked_len.buf; 
     879                tmp[0].iov_len  = conn->chunked_len.len; 
     880                tmp[1].iov_base = conn->buffer.buf; 
     881                tmp[1].iov_len  = conn->buffer.len; 
     882                tmp[2].iov_base = CRLF; 
     883                tmp[2].iov_len  = 2; 
     884 
     885                cherokee_iovec_skip_sent (tmp, 3,  
     886                                          conn->chunks, &conn->chunksn, 
     887                                          conn->chunked_sent); 
     888 
     889                ret = cherokee_socket_writev (&conn->socket, conn->chunks, conn->chunksn, &sent); 
    879890                if (unlikely (ret != ret_ok)) { 
    880891                        switch (ret) { 
     
    893904                } 
    894905 
    895                 if (unlikely (sent <= conn->chunked_len.len)) { 
    896                         cherokee_buffer_move_to_begin (&conn->chunked_len, sent); 
    897  
     906                conn->chunked_sent += sent; 
     907 
     908                /* Clean the information buffer only when everything 
     909                 * has been sent. 
     910                 */ 
     911                if (cherokee_iovec_was_sent (tmp, 3, conn->chunked_sent)) { 
     912                        cherokee_buffer_clean (&conn->chunked_len); 
     913                        cherokee_buffer_clean (&conn->buffer); 
     914                        ret = ret_ok; 
    898915                } else { 
    899                         cherokee_buffer_move_to_begin (&conn->buffer, (sent - conn->chunked_len.len)); 
    900                         cherokee_buffer_clean (&conn->chunked_len); 
    901                 } 
    902  
    903                 return (conn->buffer.len > 0) ? ret_eagain : ret_ok; 
     916                        ret = ret_eagain; 
     917                } 
     918 
     919                goto out; 
    904920        } 
    905921 
     
    908924        ret = cherokee_socket_bufwrite (&conn->socket, &conn->buffer, &sent); 
    909925        if (unlikely(ret != ret_ok)) return ret; 
    910  
    911         /* Add to the connection traffic counter 
    912          */ 
    913         cherokee_connection_tx_add (conn, sent); 
    914926 
    915927        /* Drop out the sent info 
     
    922934                ret = ret_eagain; 
    923935        } 
     936 
     937out: 
     938        /* Add to the connection traffic counter 
     939         */ 
     940        cherokee_connection_tx_add (conn, sent); 
    924941 
    925942        /* If this connection has a handler without Content-Length support 
     
    10261043        /* Return now if no encoding is needed. 
    10271044         */ 
    1028         if (conn->encoder == NULL) 
    1029                 return step_ret; 
    1030  
    1031         /* Encode handler output. 
    1032          */ 
    1033         switch (step_ret) { 
    1034         case ret_eof: 
    1035         case ret_eof_have_data: 
    1036                 ret = cherokee_encoder_flush (conn->encoder, &conn->buffer, &conn->encoder_buffer);                      
    1037                 step_ret = (conn->encoder_buffer.len == 0) ? ret_eof : ret_eof_have_data; 
    1038                 break; 
    1039         default: 
    1040                 ret = cherokee_encoder_encode (conn->encoder, &conn->buffer, &conn->encoder_buffer); 
    1041                 break; 
    1042         } 
    1043         if (ret < ret_ok) return ret; 
    1044          
    1045         /* Swap buffers  
    1046          */ 
    1047         cherokee_buffer_swap_buffers (&conn->buffer, &conn->encoder_buffer);             
    1048         cherokee_buffer_clean (&conn->encoder_buffer); 
     1045        if (conn->encoder != NULL) { 
     1046                /* Encode handler output. 
     1047                 */ 
     1048                switch (step_ret) { 
     1049                case ret_eof: 
     1050                case ret_eof_have_data: 
     1051                        ret = cherokee_encoder_flush (conn->encoder, &conn->buffer, &conn->encoder_buffer);                      
     1052                        step_ret = (conn->encoder_buffer.len == 0) ? ret_eof : ret_eof_have_data; 
     1053                        break; 
     1054                default: 
     1055                        ret = cherokee_encoder_encode (conn->encoder, &conn->buffer, &conn->encoder_buffer); 
     1056                        break; 
     1057                } 
     1058                if (ret < ret_ok)  
     1059                        return ret; 
     1060                 
     1061                /* Swap buffers  
     1062                 */ 
     1063                cherokee_buffer_swap_buffers (&conn->buffer, &conn->encoder_buffer);             
     1064                cherokee_buffer_clean (&conn->encoder_buffer); 
     1065        } 
     1066 
     1067        /* Chunked encoding header 
     1068         */ 
     1069        if (conn->chunked_encoding) { 
     1070                /* In case it is the last package, turn the chunked 
     1071                 * encoding off and send the final mark. 
     1072                 */ 
     1073                if ((step_ret == ret_eof) || 
     1074                    (step_ret == ret_eof_have_data)) 
     1075                { 
     1076                        cherokee_buffer_add_str (&conn->buffer, "0" CRLF CRLF); 
     1077                        conn->chunked_encoding = false; 
     1078 
     1079                        step_ret = ret_eof_have_data; 
     1080 
     1081                } else { 
     1082                        /* Build the Chunked package header:  
     1083                         * len(str(hex(4294967295))+"\r\n\0") = 13 
     1084                         */ 
     1085                        cherokee_buffer_clean       (&conn->chunked_len); 
     1086                        cherokee_buffer_ensure_size (&conn->chunked_len, 13); 
     1087                        cherokee_buffer_add_ulong16 (&conn->chunked_len, conn->buffer.len); 
     1088                        cherokee_buffer_add_str     (&conn->chunked_len, CRLF); 
     1089 
     1090                        conn->chunked_sent = 0; 
     1091                } 
     1092        } 
    10491093         
    10501094        return step_ret; 
     
    20362080 
    20372081        cherokee_buffer_clean (&conn->web_directory); 
     2082        conn->chunked_encoding = false; 
    20382083 
    20392084        TRACE_CONN(conn); 
  • cherokee/trunk/cherokee/handler.h

    r1853 r1947  
    4949        hsupport_length        = 1,         /* Knows the length. Eg: for keep-alive    */ 
    5050        hsupport_maybe_length  = 1 << 1,    /* It might include content-length         */ 
    51         hsupport_chunked       = 1 << 2,    /* Support Chunked transfer encoding       */ 
    52         hsupport_range         = 1 << 3,    /* Can handle "Range: bytes=" requests     */ 
    53         hsupport_error         = 1 << 4,    /* It is an error handler                  */ 
    54         hsupport_full_headers  = 1 << 5,    /* Handler adds the full header stack      */ 
    55         hsupport_skip_headers  = 1 << 6     /* The server shouldn't add any headers    */ 
     51        hsupport_range         = 1 << 2,    /* Can handle "Range: bytes=" requests     */ 
     52        hsupport_error         = 1 << 3,    /* It is an error handler                  */ 
     53        hsupport_full_headers  = 1 << 4,    /* Handler adds the full header stack      */ 
     54        hsupport_skip_headers  = 1 << 5     /* The server shouldn't add any headers    */ 
    5655} cherokee_handler_support_t; 
    5756 
  • cherokee/trunk/cherokee/handler_cgi_base.c

    r1944 r1947  
    3535 
    3636#define ENTRIES "cgibase" 
    37 #define LAST_CHUNK "0" CRLF CRLF 
    3837 
    3938#define set_env(cgi,key,val,len) \ 
     
    178177        props->change_user      = false; 
    179178        props->check_file       = true; 
    180         props->allow_chunked    = true; 
    181179        props->allow_xsendfile  = false; 
    182180        props->pass_req_headers = false; 
     
    211209                } else if (equal_buf_str (&subconf->key, "check_file")) { 
    212210                        props->check_file = !! atoi(subconf->val.buf); 
    213  
    214                 } else if (equal_buf_str (&subconf->key, "allow_chunked")) { 
    215                         props->allow_chunked = !! atoi(subconf->val.buf); 
    216211 
    217212                } else if (equal_buf_str (&subconf->key, "xsendfile")) { 
     
    965960        } 
    966961 
    967         /* Chunked encoding 
    968          */ 
    969         conn->chunked_encoding = ( 
    970                 (conn->keepalive > 0) && 
    971                 (cgi->content_length_set == false) && 
    972                 (conn->header.version == http_version_11) && 
    973                 (HANDLER_CGI_BASE_PROPS(cgi)->allow_chunked)); 
    974          
    975         TRACE (ENTRIES, "Chunked: Keepalive: %d, len not set=%d, version ok=%d, allowed=%d => %d\n", 
    976                (conn->keepalive > 0), 
    977                (cgi->content_length_set == false), 
    978                (conn->header.version == http_version_11), 
    979                (HANDLER_CGI_BASE_PROPS(cgi)->allow_chunked), 
    980                conn->chunked_encoding); 
    981  
    982962        return ret_ok; 
    983963} 
     
    988968                                cherokee_buffer_t           *outbuf) 
    989969{ 
    990         ret_t                  ret; 
    991         cherokee_buffer_t     *inbuf = &cgi->data;  
    992         cherokee_connection_t *conn  = HANDLER_CONN(cgi); 
     970        ret_t              ret; 
     971        cherokee_buffer_t *inbuf = &cgi->data;  
    993972 
    994973        /* Is it replying a "X-Sendfile" request? 
     
    1004983                TRACE (ENTRIES, "sending stored data: %d bytes\n", cgi->data.len); 
    1005984 
    1006                 if (conn->chunked_encoding) { 
    1007                         /* Build the chunk-hader: 
    1008                          * len(str(hex(4294967295))+"\r\n\0") = 13 
    1009                          */ 
    1010                         cherokee_buffer_ensure_size (&conn->chunked_len, 13); 
    1011                         cherokee_buffer_add_ulong16 (&conn->chunked_len, cgi->data.len); 
    1012                         cherokee_buffer_add_str (&conn->chunked_len, CRLF); 
    1013                 } 
    1014  
    1015985                cherokee_buffer_add_buffer (outbuf, &cgi->data); 
    1016986                cherokee_buffer_clean (&cgi->data); 
    1017987 
    1018988                if (cgi->got_eof) { 
    1019                         if (conn->chunked_encoding) { 
    1020                                 cherokee_buffer_add_str (outbuf, LAST_CHUNK); 
    1021                         } 
    1022989                        return ret_eof_have_data; 
    1023990                } 
     
    1031998 
    1032999        if (inbuf->len > 0) { 
    1033                 cherokee_buffer_add_buffer (outbuf, inbuf);                     
     1000                cherokee_buffer_add_buffer (outbuf, inbuf);      
    10341001                cherokee_buffer_clean (inbuf); 
    1035  
    1036                 if (conn->chunked_encoding) { 
    1037                         cherokee_buffer_ensure_size (&conn->chunked_len, 13); 
    1038                         cherokee_buffer_add_ulong16 (&conn->chunked_len, outbuf->len); 
    1039                         cherokee_buffer_add_str (&conn->chunked_len, CRLF); 
    1040                 } 
    1041         } 
    1042  
    1043         if ((conn->chunked_encoding) && 
    1044             ((ret == ret_eof) || (ret == ret_eof_have_data))) 
    1045         { 
    1046                 cherokee_buffer_add_str (outbuf, LAST_CHUNK); 
    1047                 return ret_eof_have_data; 
    10481002        } 
    10491003 
  • cherokee/trunk/cherokee/handler_cgi_base.h

    r1944 r1947  
    106106        cherokee_buffer_t                  script_alias; 
    107107        cherokee_boolean_t                 check_file;   
    108         cherokee_boolean_t                 allow_chunked; 
    109108        cherokee_boolean_t                 allow_xsendfile; 
    110109        cherokee_boolean_t                 is_error_handler; 
  • cherokee/trunk/cherokee/util.c

    r1885 r1947  
    14251425        return ret_ok; 
    14261426} 
     1427 
     1428 
     1429ret_t 
     1430cherokee_iovec_skip_sent (struct iovec *orig, uint16_t  orig_len, 
     1431                          struct iovec *dest, uint16_t *dest_len, 
     1432                          size_t sent) 
     1433{ 
     1434        int    i; 
     1435        int    j      = 0; 
     1436        size_t total  = 0; 
     1437        int    add    = 0; 
     1438 
     1439        for (i=0; i<orig_len; i++) { 
     1440                if (sent >= total + orig[i].iov_len) { 
     1441                        /* Already sent */ 
     1442                        total += orig[i].iov_len; 
     1443 
     1444                } else if (add) { 
     1445                        /* Add the whole thing */ 
     1446                        dest[j].iov_len  = orig[i].iov_len; 
     1447                        dest[j].iov_base = orig[i].iov_base; 
     1448                        j++; 
     1449 
     1450                } else { 
     1451                        /* Add only a piece */ 
     1452                        dest[j].iov_len  = orig[i].iov_len  - (sent - total); 
     1453                        dest[j].iov_base = orig[i].iov_base + (sent - total); 
     1454                        j++; 
     1455                        add = 1; 
     1456                } 
     1457        } 
     1458 
     1459        *dest_len = j; 
     1460        return ret_ok; 
     1461} 
     1462 
     1463 
     1464int 
     1465cherokee_iovec_was_sent (struct iovec *orig, uint16_t orig_len, size_t sent) 
     1466{ 
     1467        int    i; 
     1468        size_t total =0; 
     1469 
     1470        for (i=0; i<orig_len; i++) { 
     1471                total += orig[i].iov_len; 
     1472                if (total > sent) { 
     1473                        return 0; 
     1474                } 
     1475        } 
     1476         
     1477        return 1; 
     1478} 
  • cherokee/trunk/cherokee/util.h

    r1885 r1947  
    122122void  cherokee_print_wrapped   (cherokee_buffer_t *buffer); 
    123123 
     124ret_t cherokee_iovec_skip_sent (struct iovec orig[], uint16_t  orig_len, 
     125                                struct iovec dest[], uint16_t *dest_len, 
     126                                size_t sent); 
     127 
     128int   cherokee_iovec_was_sent  (struct iovec orig[], uint16_t orig_len, size_t sent); 
     129 
    124130/* Debug 
    125131 */