[mod-lisp-devel] Chunked encoding

Hugh Winkler hughw at hughw.net
Wed Dec 20 21:24:58 UTC 2006


Hi all,

I see this topic was raised  a couple of months ago :
http://common-lisp.net/pipermail/mod-lisp-devel/2006-October/thread.html#99.

I've made  changes to mod_lisp2.c to support chunked encoding. Sorry,
I only have a 2.0.55 to run against atm, so I have not backported to
1.3.

Notes:

Apache 2 has eliminated REQUEST_CHUNKED_DECHUNK, meaning there's no
way to receive chunked data — Apache will always dechunkify it.

I considered signaling the end of the stream by sending MSG_OOB. Well,
apr does not support that. So the only option left was to re-chunk the
data. I opted to re-chunk according to RFC 2616 so that on the Lisp
side we can use Dr. Weitz'  Chunga[1] to de-chunk.

The new behavior is compatible with existing code on the Lisp side
e.g. Kevin Rosenberg's modlisp. The mod_lisp2 code only chunks if the
Content-length header is omitted; formerly, Lisp side code could not
work properly if Content-length was omitted anyway.

There is one maybe extraneous change in this patch: I eliminated some
gcc compiler warnings issuing from local_lisp_cfg(). Here is my gcc
version string: (GCC) 4.1.2 20060928 (prerelease) (Ubuntu
4.1.1-13ubuntu5). This change is not essential but it's nice to build
with no warnings.

Thanks Mark for mod_lisp...  sorry I'm no help on the 1.3 backport.

Hugh

[1] http://weitz.de/chunga/


--- ../libapache2-mod-lisp2-1.3.1-orig/mod_lisp2.c	2006-12-20
13:23:46.000000000 -0600
+++ mod_lisp2.c	2006-12-20 14:01:47.000000000 -0600
@@ -58,6 +58,11 @@
 /*
   Change log:

+  If request contains chunked data, send chunks (length word plus data)
+  to backend lisp. Also eliminated a gcc warning.
+  -- Hugh Winkler
+     2006-12-05
+
   Fixed the APR 1.2.2 detection.
   -- sent by several people
      2006-1203
@@ -231,7 +236,7 @@
 static header_map_t map_header_to_lisp_header;
 static int write_client_data
   (request_rec * r, const char * data, unsigned int n_bytes);
-

+
 /* Configuration data */

 static lisp_cfg_t *
@@ -284,19 +289,19 @@
 static lisp_cfg_t *
 local_lisp_cfg (lisp_cfg_t *cfg)
 {
-  lisp_cfg_t *local_cfg = NULL;
-
-  apr_threadkey_private_get((void**)&local_cfg, cfg_key);
+  void *local_cfg = NULL;
+
+  apr_threadkey_private_get(&local_cfg, cfg_key);
   if (local_cfg == NULL)
     {
       local_cfg = copy_lisp_cfg (socket_pool, cfg);
-      apr_threadkey_private_set((void*)local_cfg, cfg_key);
+      apr_threadkey_private_set(local_cfg, cfg_key);
       return local_cfg;
     }

   check_cfg_for_reuse(local_cfg, cfg);

-  return local_cfg;
+  return (lisp_cfg_t*) local_cfg;
 }
 #else
 lisp_cfg_t *local_cfg;
@@ -433,6 +438,26 @@
 }

 static apr_status_t
+write_lisp_data_chunk (apr_socket_t * socket,
+                 const char * data, unsigned int n_bytes)
+{
+  char crlf[2] =  {0xd, 0xa};
+  char length[16];
+  snprintf(length, 16, "%x", n_bytes);
+
+  apr_status_t status = write_lisp_data (socket, length, strlen(length));
+  if ( status == APR_SUCCESS)
+    {
+      status = write_lisp_data (socket, crlf, 2);
+      if ( status == APR_SUCCESS && n_bytes)
+	status = write_lisp_data (socket, data, n_bytes);
+      if ( status == APR_SUCCESS)
+	status = write_lisp_data (socket, crlf, 2);
+    }
+  return status;
+}
+
+static apr_status_t
 write_lisp_line (apr_socket_t * socket, const char * data)
 {
   RELAY_ERROR (write_lisp_data (socket, data, (strlen (data))));
@@ -555,6 +580,7 @@
   int content_length = (-1);
   int keep_socket_p = 0;
   apr_socket_t * socket;
+  const char * request_content_length = 0;

   cfg = local_lisp_cfg(cfg);

@@ -600,6 +626,8 @@
       ((copy_headers ((r->headers_in), map_header_to_lisp_header, socket)),
               "writing to Lisp");

+  request_content_length = apr_table_get(r->headers_in, "Content-Length");
+
   /* Send the end-of-headers marker.  */
   ML_LOG_DEBUG (r, "write end-of-headers");
   CVT_ERROR ((write_lisp_line (socket, "end")), "writing to Lisp");
@@ -619,21 +647,31 @@
 	      close_lisp_socket (cfg);
 	      return (HTTP_INTERNAL_SERVER_ERROR);
 	    }
-	  if (n_read == 0)
-	    break;

+	  /* for chunked case, when nread == 0, we will write
+	   * a terminating 0.*/
+	
 	  {
-	    apr_status_t status = (write_lisp_data (socket, buffer, n_read));
+	    apr_status_t status = APR_SUCCESS;
+	
+	    /* if there's no Content-Type header, the data must be chunked */
+	    if (request_content_length == NULL)
+	      status = write_lisp_data_chunk (socket, buffer, n_read);
+	    else if (n_read != 0)
+	      status = write_lisp_data (socket, buffer, n_read);
+	
 	    if (APR_SUCCESS != status)
 	      {
-		while ((ap_get_client_block (r, buffer, (sizeof (buffer))))
-		       		       > 0)
+		while ((ap_get_client_block (r, buffer, sizeof(buffer)))
+		       > 0)
 		  ;
 		ML_LOG_ERROR (status, r, "writing to Lisp");
 		close_lisp_socket (cfg);
 		return (HTTP_INTERNAL_SERVER_ERROR);
 	      }
 	  }
+	  if( n_read == 0)
+	    break;
 	}
     }



More information about the mod-lisp-devel mailing list