1818#include "util_fcgi.h"
1919#include "util_script.h"
2020#include "ap_expr.h"
21+ #include "util_varbuf.h"
2122
2223module AP_MODULE_DECLARE_DATA proxy_fcgi_module ;
2324
@@ -593,6 +594,7 @@ static int handle_headers(request_rec *r, int *state,
593594 return 0 ;
594595}
595596
597+
596598static apr_status_t dispatch (proxy_conn_rec * conn , proxy_dir_conf * conf ,
597599 request_rec * r , apr_pool_t * setaside_pool ,
598600 apr_uint16_t request_id , const char * * err ,
@@ -614,6 +616,9 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
614616 char stack_iobuf [AP_IOBUFSIZE ];
615617 apr_size_t iobuf_size = AP_IOBUFSIZE ;
616618 char * iobuf = stack_iobuf ;
619+ /* Create our dynamic header buffer for large headers */
620+ ap_varbuf * header_vb = NULL ;
621+ ap_varbuf_make (& header_vb , r -> pool , 1024 );
617622
618623 * err = NULL ;
619624 if (conn -> worker -> s -> io_buffer_size_set ) {
@@ -823,61 +828,78 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
823828 APR_BRIGADE_INSERT_TAIL (ob , b );
824829
825830 if (! seen_end_of_headers ) {
826- int st = handle_headers (r , & header_state ,
827- iobuf , readbuflen );
828-
829- if (st == 1 ) {
830- int status ;
831+ /* Try our dynamic header buffer approach first */
832+ ap_varbuf_strncat (header_vb , iobuf , readbuflen );
833+ if (strstr (header_vb -> buf , "\r\n\r\n" ) != NULL ) {
834+ while (header_vb -> strlen > 0 &&
835+ isspace ((unsigned char )header_vb -> buf [0 ])) {
836+ memmove (header_vb -> buf , header_vb -> buf + 1 , header_vb -> strlen - 1 );
837+ header_vb -> strlen -- ;
838+ header_vb -> buf [header_vb -> strlen ] = '\0' ;
839+ }
831840 seen_end_of_headers = 1 ;
832-
833- status = ap_scan_script_header_err_brigade_ex (r , ob ,
834- NULL , APLOG_MODULE_INDEX );
835-
836- /* FCGI has its own body framing mechanism which we don't
837- * match against any provided Content-Length, so let the
838- * core determine C-L vs T-E based on what's actually sent.
839- */
840- if (!apr_table_get (r -> subprocess_env , AP_TRUST_CGILIKE_CL_ENVVAR ))
841- apr_table_unset (r -> headers_out , "Content-Length" );
842- apr_table_unset (r -> headers_out , "Transfer-Encoding" );
843-
844- /* suck in all the rest */
845- if (status != OK ) {
846- apr_bucket * tmp_b ;
847- apr_brigade_cleanup (ob );
848- tmp_b = apr_bucket_eos_create (c -> bucket_alloc );
849- APR_BRIGADE_INSERT_TAIL (ob , tmp_b );
850-
851- * has_responded = 1 ;
852- r -> status = status ;
853- rv = ap_pass_brigade (r -> output_filters , ob );
854- if (rv != APR_SUCCESS ) {
855- * err = "passing headers brigade to output filters" ;
856- break ;
841+ {
842+ int status_hdr ;
843+ apr_bucket_brigade * tmp_bb = apr_brigade_create (r -> pool , c -> bucket_alloc );
844+ apr_bucket * hdr_bucket = apr_bucket_heap_create (header_vb -> buf ,
845+ header_vb -> strlen , NULL , c -> bucket_alloc );
846+ APR_BRIGADE_INSERT_TAIL (tmp_bb , hdr_bucket );
847+ hdr_bucket = apr_bucket_eos_create (c -> bucket_alloc );
848+ APR_BRIGADE_INSERT_TAIL (tmp_bb , hdr_bucket );
849+ status_hdr = ap_scan_script_header_err_brigade_ex (r , tmp_bb ,
850+ NULL , APLOG_MODULE_INDEX );
851+ apr_brigade_cleanup (tmp_bb );
852+ if (status_hdr != OK ) {
853+ * has_responded = 1 ;
854+ return APR_EGENERAL ;
857855 }
858- else if (status == HTTP_NOT_MODIFIED
859- || status == HTTP_PRECONDITION_FAILED ) {
860- /* Special 'status' cases handled:
861- * 1) HTTP 304 response MUST NOT contain
862- * a message-body, ignore it.
863- * 2) HTTP 412 response.
864- * The break is not added since there might
865- * be more bytes to read from the FCGI
866- * connection. Even if the message-body is
867- * ignored (and the EOS bucket has already
868- * been sent) we want to avoid subsequent
869- * bogus reads. */
870- ignore_body = 1 ;
856+ }
857+ {
858+ char * hdr_end = strstr (header_vb -> buf , "\r\n\r\n" ) + 4 ;
859+ apr_size_t hdr_total = header_vb -> strlen ;
860+ apr_size_t remaining = hdr_total - (hdr_end - header_vb -> buf );
861+ if (remaining > 0 ) {
862+ apr_bucket * rem_bucket = apr_bucket_heap_create (hdr_end ,
863+ remaining , NULL , c -> bucket_alloc );
864+ APR_BRIGADE_INSERT_TAIL (ob , rem_bucket );
871865 }
872- else {
873- ap_log_rerror (APLOG_MARK , APLOG_ERR , 0 , r , APLOGNO (01070 )
866+ }
867+ }
868+ else {
869+ int st = handle_headers (r , & header_state ,
870+ iobuf , readbuflen );
871+ if (st == 1 ) {
872+ int status ;
873+ seen_end_of_headers = 1 ;
874+ status = ap_scan_script_header_err_brigade_ex (r , ob ,
875+ NULL , APLOG_MODULE_INDEX );
876+ if (!apr_table_get (r -> subprocess_env , AP_TRUST_CGILIKE_CL_ENVVAR ))
877+ apr_table_unset (r -> headers_out , "Content-Length" );
878+ apr_table_unset (r -> headers_out , "Transfer-Encoding" );
879+ if (status != OK ) {
880+ apr_bucket * tmp_b ;
881+ apr_brigade_cleanup (ob );
882+ tmp_b = apr_bucket_eos_create (c -> bucket_alloc );
883+ APR_BRIGADE_INSERT_TAIL (ob , tmp_b );
884+ * has_responded = 1 ;
885+ r -> status = status ;
886+ rv = ap_pass_brigade (r -> output_filters , ob );
887+ if (rv != APR_SUCCESS ) {
888+ * err = "passing headers brigade to output filters" ;
889+ break ;
890+ }
891+ else if (status == HTTP_NOT_MODIFIED
892+ || status == HTTP_PRECONDITION_FAILED ) {
893+ ignore_body = 1 ;
894+ }
895+ else {
896+ ap_log_rerror (APLOG_MARK , APLOG_ERR , 0 , r , APLOGNO (01070 )
874897 "Error parsing script headers" );
875- rv = APR_EINVAL ;
876- break ;
898+ rv = APR_EINVAL ;
899+ break ;
900+ }
877901 }
878- }
879-
880- if (ap_proxy_should_override (conf , r -> status ) && ap_is_initial_req (r )) {
902+ if (ap_proxy_should_override (conf , r -> status ) && ap_is_initial_req (r )) {
881903 /*
882904 * set script_error_status to discard
883905 * everything after the headers
@@ -912,6 +934,7 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf,
912934 * headers, so this part of the data will need
913935 * to persist. */
914936 apr_bucket_setaside (b , setaside_pool );
937+ }
915938 }
916939 } else {
917940 /* we've already passed along the headers, so now pass
0 commit comments