You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by rj...@apache.org on 2008/09/27 21:50:29 UTC

svn commit: r699727 - /tomcat/connectors/branches/other/jk_isapi_plugin_chunked/jk/native/iis/jk_isapi_plugin.c

Author: rjung
Date: Sat Sep 27 12:50:29 2008
New Revision: 699727

URL: http://svn.apache.org/viewvc?rev=699727&view=rev
Log:
Part 2 of chunked encoding: Further preparations
but do not actually chunk.

- Add enable_chunked_encoding config property
- Add done() method. Implementation needs to be
  checked, but at the moment it is not really used
  because we do not yet detect chunking.
- introduce new helper function isapi_write_client
  which is almost the same as the inner loop in the
  existing write(), but will be used multiple times
  once we really do chunking.

CAUTION: WriteClient in the new function sets
  dwSync=HSE_IO_SYNC. Before it was "0" in write().
  MSDN says, only SYNC and ASYNC are allowed and
  debug output shows, those values are 1 and 2.
  We use "0" in three other places we might want
  to switch to HSE_IO_SYNC?

Modified:
    tomcat/connectors/branches/other/jk_isapi_plugin_chunked/jk/native/iis/jk_isapi_plugin.c

Modified: tomcat/connectors/branches/other/jk_isapi_plugin_chunked/jk/native/iis/jk_isapi_plugin.c
URL: http://svn.apache.org/viewvc/tomcat/connectors/branches/other/jk_isapi_plugin_chunked/jk/native/iis/jk_isapi_plugin.c?rev=699727&r1=699726&r2=699727&view=diff
==============================================================================
--- tomcat/connectors/branches/other/jk_isapi_plugin_chunked/jk/native/iis/jk_isapi_plugin.c (original)
+++ tomcat/connectors/branches/other/jk_isapi_plugin_chunked/jk/native/iis/jk_isapi_plugin.c Sat Sep 27 12:50:29 2008
@@ -116,6 +116,7 @@
 #endif
 #define REJECT_UNSAFE_TAG           ("reject_unsafe")
 #define WATCHDOG_INTERVAL_TAG       ("watchdog_interval")
+#define ENABLE_CHUNKED_ENCODING_TAG ("enable_chunked_encoding")
 
 #define TRANSLATE_HEADER            ("Translate:")
 #define TRANSLATE_HEADER_NAME       ("Translate")
@@ -125,6 +126,10 @@
 #define CRLF                        ("\r\n")
 #define CRLF_LEN                    (2)
 
+/* Transfer-Encoding: chunked content trailer */
+#define CHUNKED_ENCODING_TRAILER     ("0\r\n\r\n")
+#define CHUNKED_ENCODING_TRAILER_LEN (5)
+
 #define BAD_REQUEST     -1
 #define BAD_PATH        -2
 #define MAX_SERVERNAME  128
@@ -216,6 +221,9 @@
 #ifndef AUTOMATIC_AUTH_NOTIFICATION
 static int  use_auth_notification_flags = 1;
 #endif
+/* Whether chunked encoding has been enabled in the settings */
+static int  chunked_encoding_enabled = JK_FALSE;
+
 static int  reject_unsafe = 0;
 static int  watchdog_interval = 0;
 static HANDLE watchdog_handle = NULL;
@@ -235,6 +243,7 @@
     jk_pool_t p;
 
     unsigned int bytes_read_so_far;
+    int chunk_content;          /* Whether we're responding with Transfer-Encoding: chunked content */
     LPEXTENSION_CONTROL_BLOCK lpEcb;
 };
 
@@ -265,6 +274,8 @@
 
 static int JK_METHOD write(jk_ws_service_t *s, const void *b, unsigned int l);
 
+static int JK_METHOD done(jk_ws_service_t *s);
+
 static int init_ws_service(isapi_private_data_t * private_data,
                            jk_ws_service_t *s, char **worker_name);
 
@@ -764,37 +775,136 @@
     return JK_FALSE;
 }
 
+/*
+ * Writes a buffer to the ISAPI response.
+ */
+static int isapi_write_client(isapi_private_data_t *p, const char *buf, unsigned int write_length)
+{
+    unsigned int written = 0;
+    DWORD try_to_write = 0;
+
+    JK_TRACE_ENTER(logger);
+
+    if (JK_IS_DEBUG_LEVEL(logger))
+        jk_log(logger, JK_LOG_DEBUG, "Writing %d bytes of data to client", write_length);
+
+    while (written < write_length) {
+        try_to_write = write_length - written;
+        if (!p->lpEcb->WriteClient(p->lpEcb->ConnID,
+                                   (LPVOID)(buf + written), &try_to_write, HSE_IO_SYNC)) {
+            jk_log(logger, JK_LOG_ERROR,
+                   "WriteClient failed with %d (0x%08x)", GetLastError(), GetLastError());
+            JK_TRACE_EXIT(logger);
+            return JK_FALSE;
+        }
+        written += try_to_write;
+        if (JK_IS_DEBUG_LEVEL(logger))
+            jk_log(logger, JK_LOG_DEBUG, "Wrote %d bytes of data successfully", try_to_write);
+    }
+    JK_TRACE_EXIT(logger);
+    return JK_TRUE;
+}
+
 static int JK_METHOD write(jk_ws_service_t *s, const void *b, unsigned int l)
 {
     JK_TRACE_ENTER(logger);
 
+    if (!l) {
+        JK_TRACE_EXIT(logger);
+        return JK_TRUE;
+    }
+
     if (s && s->ws_private && b) {
         isapi_private_data_t *p = s->ws_private;
+        const char *buf = (const char *)b;
 
-        if (l) {
-            unsigned int written = 0;
-            char *buf = (char *)b;
+        if (!p) {
+            JK_TRACE_EXIT(logger);
+            return JK_FALSE;
+        }
 
-            if (!s->response_started) {
-                start_response(s, 200, NULL, NULL, NULL, 0);
-            }
+        if (!s->response_started) {
+            start_response(s, 200, NULL, NULL, NULL, 0);
+        }
+
+        if (isapi_write_client(p, buf, l) == JK_FALSE) {
+            JK_TRACE_EXIT(logger);
+            return JK_FALSE;
+        }
+
+        JK_TRACE_EXIT(logger);
+        return JK_TRUE;
+
+    }
+
+    JK_LOG_NULL_PARAMS(logger);
+    JK_TRACE_EXIT(logger);
+    return JK_FALSE;
+}
 
-            while (written < l) {
-                DWORD try_to_write = l - written;
-                if (!p->lpEcb->WriteClient(p->lpEcb->ConnID,
-                                           buf + written, &try_to_write, 0)) {
+/**
+ * In the case of a Transfer-Encoding: chunked response, this will write the terminator chunk.
+ */
+static int JK_METHOD done(jk_ws_service_t *s)
+{
+    JK_TRACE_ENTER(logger);
+
+    if (s && s->ws_private) {
+        isapi_private_data_t *p = s->ws_private;
+
+        if (p->chunk_content == JK_FALSE) {
+            JK_TRACE_EXIT(logger);
+            return JK_TRUE;
+        }
+
+        /* Write last chunk + terminator */
+        if (iis_info.major >= 6) {
+            HSE_RESPONSE_VECTOR response_vector;
+            HSE_VECTOR_ELEMENT response_elements[1];
+
+            response_elements[0].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
+            response_elements[0].pvContext = CHUNKED_ENCODING_TRAILER;
+            response_elements[0].cbOffset = 0;
+            response_elements[0].cbSize = CHUNKED_ENCODING_TRAILER_LEN;
+
+            /* HSE_IO_FINAL_SEND lets IIS process the response to the client before we return */
+            response_vector.dwFlags = HSE_IO_SYNC | HSE_IO_FINAL_SEND;
+            response_vector.pszStatus = NULL;
+            response_vector.pszHeaders = NULL;
+            response_vector.nElementCount = 1;
+            response_vector.lpElementArray = response_elements;
+
+            if (JK_IS_DEBUG_LEVEL(logger))
+                jk_log(logger, JK_LOG_DEBUG,
+                       "Using vector write to terminate chunk encoded response.");
+
+            if (!p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID,
+                                                 HSE_REQ_VECTOR_SEND,
+                                                 &response_vector,
+                                                 (LPDWORD)NULL,
+                                                 (LPDWORD)NULL)) {
                     jk_log(logger, JK_LOG_ERROR,
-                           "WriteClient failed with %d (0x%08x)", GetLastError(), GetLastError());
+                           "Vector termination of chunk encoded response failed with %d (0x%08x)",
+                           GetLastError(), GetLastError());
                     JK_TRACE_EXIT(logger);
                     return JK_FALSE;
-                }
-                written += try_to_write;
+            }
+        }
+        else {
+            if (JK_IS_DEBUG_LEVEL(logger))
+                jk_log(logger, JK_LOG_DEBUG, "Terminating chunk encoded response");
+
+            if (!isapi_write_client(p, CHUNKED_ENCODING_TRAILER, CHUNKED_ENCODING_TRAILER_LEN)) {
+                jk_log(logger, JK_LOG_ERROR,
+                       "WriteClient for chunked response terminator failed with %d (0x%08x)",
+                       GetLastError(), GetLastError());
+                JK_TRACE_EXIT(logger);
+                return JK_FALSE;
             }
         }
 
         JK_TRACE_EXIT(logger);
         return JK_TRUE;
-
     }
 
     JK_LOG_NULL_PARAMS(logger);
@@ -1535,6 +1645,7 @@
 
         private_data.bytes_read_so_far = 0;
         private_data.lpEcb = lpEcb;
+        private_data.chunk_content = JK_FALSE;
 
         s.ws_private = &private_data;
         s.pool = &private_data.p;
@@ -1772,6 +1883,7 @@
         jk_log(logger, JK_LOG_DEBUG, "Using rewrite rule file %s.",
                rewrite_rule_file);
         jk_log(logger, JK_LOG_DEBUG, "Using uri select %d.", uri_select_option);
+        jk_log(logger, JK_LOG_DEBUG, "Using%s chunked encoding.", (chunked_encoding_enabled ? "" : " no"));
 
         jk_log(logger, JK_LOG_DEBUG, "Using notification event %s (0x%08x)",
                (iis_info.filter_notify_event == SF_NOTIFY_AUTH_COMPLETE) ?
@@ -1984,6 +2096,8 @@
 #endif
     reject_unsafe = get_config_bool(src, REJECT_UNSAFE_TAG, JK_FALSE);
     watchdog_interval = get_config_int(src, WATCHDOG_INTERVAL_TAG, 0);
+    chunked_encoding_enabled = get_config_bool(src, ENABLE_CHUNKED_ENCODING_TAG, JK_FALSE);
+
     if (using_ini_file) {
         jk_map_free(&map);
     }
@@ -2089,6 +2203,7 @@
     s->start_response = start_response;
     s->read = read;
     s->write = write;
+    s->done = done;
 
     if (!(huge_buf = jk_pool_alloc(&private_data->p, MAX_PACKET_SIZE))) {
         JK_TRACE_EXIT(logger);



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org