View | Details | Raw Unified | Return to bug 35297
Collapse All | Expand All

(-)jk/native/common/jk_util.c (+2 lines)
Lines 1230-1235 Link Here
1230
    s->num_attributes = 0;
1230
    s->num_attributes = 0;
1231
    s->jvm_route = NULL;
1231
    s->jvm_route = NULL;
1232
    s->retries = JK_RETRIES;
1232
    s->retries = JK_RETRIES;
1233
    s->flush = NULL;
1234
    s->flush_packets = JK_FALSE;
1233
}
1235
}
1234
1236
1235
#ifdef _MT_CODE_PTHREAD
1237
#ifdef _MT_CODE_PTHREAD
(-)jk/native/iis/jk_isapi_plugin.c (-24 / +215 lines)
Lines 20-25 Link Here
20
 * Author:      Larry Isaacs <larryi@apache.org>                           *
20
 * Author:      Larry Isaacs <larryi@apache.org>                           *
21
 * Author:      Ignacio J. Ortega <nacho@apache.org>                       *
21
 * Author:      Ignacio J. Ortega <nacho@apache.org>                       *
22
 * Author:      Mladen Turk <mturk@apache.org>                             *
22
 * Author:      Mladen Turk <mturk@apache.org>                             *
23
 * Author:      Tim Whittington <tim.whittington@orionhealth.com           *
23
 * Version:     $Revision: 1.49 $                                          *
24
 * Version:     $Revision: 1.49 $                                          *
24
 ***************************************************************************/
25
 ***************************************************************************/
25
26
Lines 69-74 Link Here
69
#define URI_SELECT_UNPARSED_VERB    ("unparsed")
70
#define URI_SELECT_UNPARSED_VERB    ("unparsed")
70
#define URI_SELECT_ESCAPED_VERB     ("escaped")
71
#define URI_SELECT_ESCAPED_VERB     ("escaped")
71
72
73
#define ENABLE_CHUNKED_ENCODING_TAG ("enable_chunked_encoding")
74
75
/* Headers used in negotiating chunked encoding */
76
#define TRANSFER_ENCODING_HEADER_COMPLETE ("Transfer-Encoding: chunked")
77
#define TRANSFER_ENCODING_HEADER_NAME ("Transfer-Encoding")
78
#define CONTENT_LENGTH_HEADER_NAME ("Content-Length")
79
#define CONNECTION_HEADER_NAME ("Connection")
80
#define CONNECTION_CLOSE_VALUE ("Close")
81
72
#define BAD_REQUEST     -1
82
#define BAD_REQUEST     -1
73
#define BAD_PATH        -2
83
#define BAD_PATH        -2
74
#define MAX_SERVERNAME  128
84
#define MAX_SERVERNAME  128
Lines 115-120 Link Here
115
        (place) = def;                                      \
125
        (place) = def;                                      \
116
  } } while(0)
126
  } } while(0)
117
127
128
/* HTTP protocol CRLF */
129
static char CRLF[3] = { (char)13, (char)10, '\0' };
130
118
static char ini_file_name[MAX_PATH];
131
static char ini_file_name[MAX_PATH];
119
static int using_ini_file = JK_FALSE;
132
static int using_ini_file = JK_FALSE;
120
static int is_inited = JK_FALSE;
133
static int is_inited = JK_FALSE;
Lines 133-138 Link Here
133
static int log_level = JK_LOG_EMERG_LEVEL;
146
static int log_level = JK_LOG_EMERG_LEVEL;
134
static char worker_file[MAX_PATH * 2];
147
static char worker_file[MAX_PATH * 2];
135
static char worker_mount_file[MAX_PATH * 2] = {0};
148
static char worker_mount_file[MAX_PATH * 2] = {0};
149
/* Whether chunked encoding has been enabled in the settings */
150
static int chunked_encoding_enabled = JK_FALSE;
136
151
137
#define URI_SELECT_OPT_PARSED       0
152
#define URI_SELECT_OPT_PARSED       0
138
#define URI_SELECT_OPT_UNPARSED     1
153
#define URI_SELECT_OPT_UNPARSED     1
Lines 150-155 Link Here
150
    int request_started;
165
    int request_started;
151
    unsigned int bytes_read_so_far;
166
    unsigned int bytes_read_so_far;
152
    LPEXTENSION_CONTROL_BLOCK lpEcb;
167
    LPEXTENSION_CONTROL_BLOCK lpEcb;
168
    int chunk_content; /* Whether we're responding with Transfer-Encoding: chunked content */
153
};
169
};
154
170
155
typedef struct isapi_log_data_t isapi_log_data_t;
171
typedef struct isapi_log_data_t isapi_log_data_t;
Lines 170-175 Link Here
170
186
171
static int JK_METHOD write(jk_ws_service_t *s, const void *b, unsigned int l);
187
static int JK_METHOD write(jk_ws_service_t *s, const void *b, unsigned int l);
172
188
189
static int JK_METHOD flush_response(jk_ws_service_t *s);
190
173
static int init_ws_service(isapi_private_data_t * private_data,
191
static int init_ws_service(isapi_private_data_t * private_data,
174
                           jk_ws_service_t *s, char **worker_name);
192
                           jk_ws_service_t *s, char **worker_name);
175
193
Lines 469-476 Link Here
469
                                    const char *const *header_values,
487
                                    const char *const *header_values,
470
                                    unsigned int num_of_headers)
488
                                    unsigned int num_of_headers)
471
{
489
{
472
    static char crlf[3] = { (char)13, (char)10, '\0' };
473
474
    JK_TRACE_ENTER(logger);
490
    JK_TRACE_ENTER(logger);
475
    if (status < 100 || status > 1000) {
491
    if (status < 100 || status > 1000) {
476
        jk_log(logger, JK_LOG_ERROR,
492
        jk_log(logger, JK_LOG_ERROR,
Lines 482-491 Link Here
482
498
483
    if (s && s->ws_private) {
499
    if (s && s->ws_private) {
484
        isapi_private_data_t *p = s->ws_private;
500
        isapi_private_data_t *p = s->ws_private;
501
        int keep_alive = JK_FALSE;	    /* Whether the downstream or us can supply content length */
502
        
485
        if (!p->request_started) {
503
        if (!p->request_started) {
486
            size_t len_of_status;
504
            HSE_SEND_HEADER_EX_INFO send_header_ex_info;
487
            char *status_str;
505
            char *status_str;
488
            char *headers_str;
506
            char *headers_str;
507
            int keep_alive = JK_FALSE;	    /* Whether the downstream or us can supply content length */
489
508
490
            p->request_started = JK_TRUE;
509
            p->request_started = JK_TRUE;
491
510
Lines 497-542 Link Here
497
            }
516
            }
498
            status_str = (char *)_alloca((6 + strlen(reason)) * sizeof(char));
517
            status_str = (char *)_alloca((6 + strlen(reason)) * sizeof(char));
499
            sprintf(status_str, "%d %s", status, reason);
518
            sprintf(status_str, "%d %s", status, reason);
500
            len_of_status = strlen(status_str);
501
519
502
            /*
520
            /*
503
             * Create response headers string
521
             * Create response headers string
504
             */
522
             */
505
            if (num_of_headers) {
523
            if (num_of_headers) {
524
                int chunked_ok = JK_FALSE;	    /* Whether the downstream response allows chunking */
525
                int http11_request = JK_FALSE;	/* Whether the client is HTTP/1.1 */
526
506
                size_t i, len_of_headers;
527
                size_t i, len_of_headers;
528
529
                /* Check if we've got an HTTP/1.1 response */
530
                jk_log(logger, JK_LOG_DEBUG, 
531
                    "jk_ws_service_t::start_response, Request uses protocol %s\n", s->protocol);
532
533
                if (strcasecmp(s->protocol, "HTTP/1.1")==0) {
534
                    http11_request = JK_TRUE;
535
                    chunked_ok = JK_TRUE;	/* Chunking only on HTTP/1.1 */
536
                }
537
507
                for (i = 0, len_of_headers = 0; i < num_of_headers; i++) {
538
                for (i = 0, len_of_headers = 0; i < num_of_headers; i++) {
508
                    len_of_headers += strlen(header_names[i]);
539
                    len_of_headers += strlen(header_names[i]);
509
                    len_of_headers += strlen(header_values[i]);
540
                    len_of_headers += strlen(header_values[i]);
510
                    len_of_headers += 4;        /* extra for colon, space and crlf */
541
                    len_of_headers += 4;        /* extra for colon, space and crlf */
511
                }
542
                }
512
543
544
                /* Provide room in the buffer for the Transfer-Encoding header if we use it. */
545
                len_of_headers += strlen(TRANSFER_ENCODING_HEADER_COMPLETE) + 2;
546
513
                len_of_headers += 3;    /* crlf and terminating null char */
547
                len_of_headers += 3;    /* crlf and terminating null char */
514
                headers_str = (char *)_alloca(len_of_headers * sizeof(char));
548
                headers_str = (char *)_alloca(len_of_headers * sizeof(char));
515
                headers_str[0] = '\0';
549
                headers_str[0] = '\0';
516
550
517
                for (i = 0; i < num_of_headers; i++) {
551
                for (i = 0; i < num_of_headers; i++) {
552
                    /* Check the downstream response to see whether 
553
                    it's appropriate the chunk the response content
554
                    and whether it supports keeping the connection open */
555
                    if(strcasecmp(TRANSFER_ENCODING_HEADER_NAME, header_names[i])==0) {
556
                        keep_alive = http11_request;
557
                        chunked_ok = JK_FALSE;
558
                    }
559
                    else if(strcasecmp(CONTENT_LENGTH_HEADER_NAME, header_names[i])==0) {
560
                        keep_alive = http11_request;
561
                        chunked_ok = JK_FALSE;
562
                    } 
563
                    else if((strcasecmp(CONNECTION_HEADER_NAME, header_names[i])==0)
564
                            && (strcasecmp(CONNECTION_CLOSE_VALUE, header_values[i])==0)) {
565
                        keep_alive = JK_FALSE;
566
                        chunked_ok = JK_FALSE;
567
                    }
568
518
                    strcat(headers_str, header_names[i]);
569
                    strcat(headers_str, header_names[i]);
519
                    strcat(headers_str, ": ");
570
                    strcat(headers_str, ": ");
520
                    strcat(headers_str, header_values[i]);
571
                    strcat(headers_str, header_values[i]);
521
                    strcat(headers_str, crlf);
572
                    strcat(headers_str, CRLF);
522
                }
573
                }
523
                strcat(headers_str, crlf);
574
575
                /* Check if we can send chunked content */
576
                if (chunked_encoding_enabled && chunked_ok) {
577
                    jk_log(logger, JK_LOG_DEBUG, 
578
                        "jk_ws_service_t::start_response, using Transfer-Encoding: chunked\n");
579
580
                    /** We will supply the transfer-encoding to allow IIS to keep the connection open */
581
                    keep_alive = JK_TRUE;
582
583
                    p->chunk_content = JK_TRUE;
584
                    /* Indicate to the client that the content will be chunked
585
                    - We've already reserved space for this */
586
                    strcat(headers_str, TRANSFER_ENCODING_HEADER_COMPLETE);
587
                    strcat(headers_str, CRLF);
588
                } 
589
                else {
590
                    p->chunk_content = JK_FALSE;
591
                }
592
593
                strcat(headers_str, CRLF);
524
            }
594
            }
525
            else {
595
            else {
526
                headers_str = crlf;
596
                headers_str = CRLF;
527
            }
597
            }
528
598
529
            if (!p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID,
599
            /** Fill in the response */
530
                                                 HSE_REQ_SEND_RESPONSE_HEADER,
600
            send_header_ex_info.pszStatus = status_str;
531
                                                 status_str,
601
            send_header_ex_info.pszHeader = headers_str;
532
                                                 (LPDWORD) &len_of_status,
602
            send_header_ex_info.cchStatus = strlen(status_str);
533
                                                 (LPDWORD) headers_str)) {
603
            send_header_ex_info.cchHeader = strlen(headers_str);
534
                jk_log(logger, JK_LOG_ERROR,
604
535
                       "HSE_REQ_SEND_RESPONSE_HEADER failed");
605
            /* 
606
             * Using the extended form of the API means we have to get this right,
607
             * i.e. IIS won't keep connections open if there's a Content-Length and close them if there isn't.
608
             */
609
            jk_log(logger, JK_LOG_DEBUG, 
610
                "jk_ws_service_t::start_response, keep_alive = %d\n", keep_alive);
611
612
            send_header_ex_info.fKeepConn = keep_alive;
613
614
            if (!p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID, 
615
                                                 HSE_REQ_SEND_RESPONSE_HEADER_EX,
616
                                                 &send_header_ex_info,
617
                                                 NULL,
618
                                                 NULL)) {
619
                jk_log(logger, JK_LOG_ERROR, 
620
                    "HSE_REQ_SEND_RESPONSE_HEADER failed");
536
                JK_TRACE_EXIT(logger);
621
                JK_TRACE_EXIT(logger);
537
                return JK_FALSE;
622
                return JK_FALSE;
538
            }
623
            }       
539
        }
624
        }
625
540
        JK_TRACE_EXIT(logger);
626
        JK_TRACE_EXIT(logger);
541
        return JK_TRUE;
627
        return JK_TRUE;
542
628
Lines 602-607 Link Here
602
    return JK_FALSE;
688
    return JK_FALSE;
603
}
689
}
604
690
691
/*
692
 * Writes a buffer to the ISAPI response.
693
 */
694
static int isapi_write_client(isapi_private_data_t *p, const char *buf, unsigned write_length)
695
{
696
    unsigned written = 0;           
697
    DWORD try_to_write = 0;
698
699
    JK_TRACE_ENTER(logger);
700
701
    while (written < write_length) {
702
        try_to_write = (write_length - written);
703
        if (!p->lpEcb->WriteClient(p->lpEcb->ConnID, 
704
                                   buf + written, &try_to_write, 0)) {
705
            jk_log(logger, JK_LOG_ERROR,
706
                    "WriteClient failed with %08x", GetLastError());
707
            JK_TRACE_EXIT(logger);
708
            return JK_FALSE;
709
        }
710
        written += try_to_write;
711
    }
712
    JK_TRACE_EXIT(logger);
713
    return JK_TRUE;
714
}
715
716
/* 
717
 * Write content to the response.
718
 * If chunked encoding has been enabled and the client supports it 
719
 *(and it's appropriate for the response), then this will write a
720
 * single "Transfer-Encoding: chunked" chunk
721
 * 
722
 */
605
static int JK_METHOD write(jk_ws_service_t *s, const void *b, unsigned int l)
723
static int JK_METHOD write(jk_ws_service_t *s, const void *b, unsigned int l)
606
{
724
{
607
    JK_TRACE_ENTER(logger);
725
    JK_TRACE_ENTER(logger);
Lines 610-638 Link Here
610
        isapi_private_data_t *p = s->ws_private;
728
        isapi_private_data_t *p = s->ws_private;
611
729
612
        if (l) {
730
        if (l) {
613
            unsigned int written = 0;
614
            char *buf = (char *)b;
731
            char *buf = (char *)b;
615
732
616
            if (!p->request_started) {
733
            if (!p->request_started) {
617
                start_response(s, 200, NULL, NULL, NULL, 0);
734
                start_response(s, 200, NULL, NULL, NULL, 0);
618
            }
735
            }
619
736
620
            while (written < l) {
737
            /* Chunk header */
621
                DWORD try_to_write = l - written;
738
            if (p->chunk_content) {
622
                if (!p->lpEcb->WriteClient(p->lpEcb->ConnID,
739
                char chunk_header[sizeof(unsigned)*2+3]; /* Hex of chunk length + CRLF + term. */
623
                                           buf + written, &try_to_write, 0)) {
740
                jk_log(logger, JK_LOG_DEBUG, 
624
                    jk_log(logger, JK_LOG_ERROR,
741
                    "Using chunked encoding - writing chunk header\n");
625
                           "WriteClient failed with %08x", GetLastError());
742
743
                /* Construct chunk header : HEX CRLF*/
744
                sprintf(chunk_header, "%X%s", l, CRLF);
745
746
                if (!isapi_write_client(p, chunk_header, strlen(chunk_header))) {
747
                    jk_log(logger, JK_LOG_ERROR, 
748
                        "WriteClient for chunk header failed\n");
749
                    JK_TRACE_EXIT(logger);
750
                    return JK_FALSE;
751
                }
752
            }
753
754
            /* Write chunk body */
755
            if (!isapi_write_client(p, buf, l)) {
756
                jk_log(logger, JK_LOG_ERROR, 
757
                    "WriteClient for body chunk failed\n");
758
                JK_TRACE_EXIT(logger);
759
                return JK_FALSE;
760
            }
761
762
            /* Write chunk trailer */
763
            if (p->chunk_content) {
764
                jk_log(logger, JK_LOG_DEBUG, 
765
                    "Using chunked encoding - writing chunk trailer\n");
766
767
                if (!isapi_write_client(p, CRLF, strlen(CRLF))) {
768
                    jk_log(logger, JK_LOG_ERROR, 
769
                        "WriteClient for chunk trailer failed\n");
626
                    JK_TRACE_EXIT(logger);
770
                    JK_TRACE_EXIT(logger);
627
                    return JK_FALSE;
771
                    return JK_FALSE;
628
                }
772
                }
629
                written += try_to_write;
630
            }
773
            }
631
        }
774
        }
632
775
633
        JK_TRACE_EXIT(logger);
776
        JK_TRACE_EXIT(logger);
634
        return JK_TRUE;
777
        return JK_TRUE;
778
    }
779
    
780
    JK_LOG_NULL_PARAMS(logger);
781
    JK_TRACE_EXIT(logger);
782
    return JK_FALSE;
783
}
784
785
/**
786
 * In the case of a Transfer-Encoding: chunked response, this will write the terminator chunk.
787
 */
788
static int JK_METHOD flush_response(jk_ws_service_t *s)
789
{
790
    JK_TRACE_ENTER(logger);
635
791
792
    if (s && s->ws_private) {
793
        isapi_private_data_t *p = s->ws_private;
794
795
        /* Write last chunk + terminator */
796
        if (p->chunk_content) {
797
            static char CHUNKED_ENCODING_TRAILER[6] = { '0', (char)13, (char)10, (char)13, (char)10, '\0' };
798
799
            jk_log(logger, JK_LOG_DEBUG, 
800
                "Terminating chunk encoded response.\n");
801
802
            if (!isapi_write_client(p, CHUNKED_ENCODING_TRAILER, strlen(CHUNKED_ENCODING_TRAILER))) {
803
                jk_log(logger, JK_LOG_ERROR, 
804
                    "WriteClient for chunk response terminator failed\n");
805
                JK_TRACE_EXIT(logger);
806
                return JK_FALSE;
807
            }
808
        }
809
        
810
        JK_TRACE_EXIT(logger);
811
        return JK_TRUE;
636
    }
812
    }
637
813
638
    JK_LOG_NULL_PARAMS(logger);
814
    JK_LOG_NULL_PARAMS(logger);
Lines 992-997 Link Here
992
        private_data.request_started = JK_FALSE;
1168
        private_data.request_started = JK_FALSE;
993
        private_data.bytes_read_so_far = 0;
1169
        private_data.bytes_read_so_far = 0;
994
        private_data.lpEcb = lpEcb;
1170
        private_data.lpEcb = lpEcb;
1171
        private_data.chunk_content = JK_FALSE;
995
1172
996
        s.ws_private = &private_data;
1173
        s.ws_private = &private_data;
997
        s.pool = &private_data.p;
1174
        s.pool = &private_data.p;
Lines 1139-1144 Link Here
1139
        jk_log(logger, JK_LOG_DEBUG, "Using worker mount file %s.",
1316
        jk_log(logger, JK_LOG_DEBUG, "Using worker mount file %s.",
1140
               worker_mount_file);
1317
               worker_mount_file);
1141
        jk_log(logger, JK_LOG_DEBUG, "Using uri select %d.", uri_select_option);
1318
        jk_log(logger, JK_LOG_DEBUG, "Using uri select %d.", uri_select_option);
1319
        jk_log(logger, JK_LOG_DEBUG, "Using chunked encoding? %d.\n", chunked_encoding_enabled);
1142
    }
1320
    }
1143
    if (uri_worker_map_alloc(&uw_map, NULL, logger)) {
1321
    if (uri_worker_map_alloc(&uw_map, NULL, logger)) {
1144
        rc = JK_FALSE;
1322
        rc = JK_FALSE;
Lines 1256-1261 Link Here
1256
                ok = JK_FALSE;
1434
                ok = JK_FALSE;
1257
            }
1435
            }
1258
        }
1436
        }
1437
        chunked_encoding_enabled = jk_map_get_bool(map, ENABLE_CHUNKED_ENCODING_TAG, JK_FALSE);
1259
1438
1260
    }
1439
    }
1261
    else {
1440
    else {
Lines 1323-1328 Link Here
1323
            }
1502
            }
1324
        }
1503
        }
1325
1504
1505
        if (get_registry_config_parameter(hkey,
1506
                                          ENABLE_CHUNKED_ENCODING_TAG, 
1507
                                          tmpbuf, sizeof(tmpbuf))) {
1508
            if (strcasecmp(tmpbuf, "true") == 0 ||
1509
                *tmpbuf == 'Y' || *tmpbuf == 'y' || *tmpbuf == '1') {
1510
                    chunked_encoding_enabled = JK_TRUE;
1511
            }
1512
        }
1513
1326
        RegCloseKey(hkey);
1514
        RegCloseKey(hkey);
1327
    }
1515
    }
1328
    return ok;
1516
    return ok;
Lines 1356-1362 Link Here
1356
    s->start_response = start_response;
1544
    s->start_response = start_response;
1357
    s->read = read;
1545
    s->read = read;
1358
    s->write = write;
1546
    s->write = write;
1359
    s->flush = NULL;
1547
1548
    /* We want to flush at end of content to terminate chunked encoding */
1549
    s->flush = flush_response;
1550
    s->flush_packets = JK_FALSE;    
1360
1551
1361
    /* Clear RECO status */
1552
    /* Clear RECO status */
1362
    s->reco_status = RECO_NONE;
1553
    s->reco_status = RECO_NONE;

Return to bug 35297