php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #44393 [PATCH] Support for Keep-Alive connections under IIS using ISAPI sapi
Submitted: 2008-03-10 14:53 UTC Modified: 2021-02-11 17:40 UTC
Votes:4
Avg. Score:3.5 ± 0.9
Reproduced:2 of 2 (100.0%)
Same Version:2 (100.0%)
Same OS:1 (50.0%)
From: richard dot krehbiel at gmail dot com Assigned: cmb (profile)
Status: Closed Package: IIS related
PHP Version: 5.2.5 OS: Windows
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: richard dot krehbiel at gmail dot com
New email:
PHP Version: OS:

 

 [2008-03-10 14:53 UTC] richard dot krehbiel at gmail dot com
Description:
------------
The ISAPI module for PHP does not support "Keep-Alive" connections.

I have a modified sapi/isapi/php5isapi.c that adds "Transfer-Encoding: chunked" support, which allows keep-alive to work.  It works but needs polish*.  Interested?

*It needs to detect the presence of a "Content-Length" header and disable "chunked"; it needs buffering (every little 1-char echo becomes a chunk); I think it doesn't work with dynamic compression.

--- /mnt/rich3/c/php-5.2.5/sapi/isapi/php5isapi.c	2007-02-23 17:08:30.000000000 -0500
+++ /mnt/rich3/c/buildphp/php-5.2.5/sapi/isapi/php5isapi.c	2008-03-10 10:46:17.317923500 -0400
@@ -206,10 +206,25 @@
 {
 	DWORD num_bytes = str_length;
 	LPEXTENSION_CONTROL_BLOCK ecb;
+	// Chunked write...
+	char chunksize[16];
+	uint chunksizelen;
 	
 	ecb = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
-	if (ecb->WriteClient(ecb->ConnID, (char *) str, &num_bytes, HSE_IO_SYNC) == FALSE) {
-		php_handle_aborted_connection();
+
+	if(str_length > 0) {
+		uint two = 2;
+		_snprintf(chunksize, sizeof(chunksize), "%lX\r\n", str_length);
+		chunksizelen = strlen(chunksize);
+		if (ecb->WriteClient(ecb->ConnID, chunksize, &chunksizelen, HSE_IO_SYNC) == FALSE) {
+			php_handle_aborted_connection();
+		}
+		if (ecb->WriteClient(ecb->ConnID, (char *) str, &num_bytes, HSE_IO_SYNC) == FALSE) {
+			php_handle_aborted_connection();
+		}
+		if (ecb->WriteClient(ecb->ConnID, "\r\n", &two, HSE_IO_SYNC) == FALSE) {
+			php_handle_aborted_connection();
+		}
 	}
 	return num_bytes;
 }
@@ -256,16 +271,14 @@
 	zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) accumulate_header_length, (void *) &total_length TSRMLS_CC);
 
 	/* Generate headers */
-	combined_headers = (char *) emalloc(total_length+1);
+	combined_headers = (char *) emalloc(total_length+64);
 	combined_headers_ptr = combined_headers;
 	if (SG(sapi_headers).send_default_content_type) {
 		concat_header(&default_content_type, (void *) &combined_headers_ptr TSRMLS_CC);
 		sapi_free_header(&default_content_type); /* we no longer need it */
 	}
 	zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) concat_header, (void *) &combined_headers_ptr TSRMLS_CC);
-	*combined_headers_ptr++ = '\r';
-	*combined_headers_ptr++ = '\n';
-	*combined_headers_ptr = 0;
+	strcpy(combined_headers_ptr, "Transfer-Encoding: chunked\r\n\r\n");
 
 	switch (SG(sapi_headers).http_response_code) {
 		case 200:
@@ -300,7 +313,7 @@
 	header_info.cchStatus = strlen(header_info.pszStatus);
 	header_info.pszHeader = combined_headers;
 	header_info.cchHeader = total_length;
-	header_info.fKeepConn = FALSE;
+	header_info.fKeepConn = TRUE;
 	lpECB->dwHttpStatusCode = SG(sapi_headers).http_response_code;
 
 	lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL);
@@ -928,6 +941,15 @@
 		return HSE_STATUS_ERROR;
 	} zend_end_try();
 
+	// Finish a chunked transmission, send 0 length EOF chunk and trailing headers (none)
+
+	{
+		uint five = 5;
+		if (lpECB->WriteClient(lpECB->ConnID, "0\r\n\r\n", &five, HSE_IO_SYNC) == FALSE) {
+			php_handle_aborted_connection();
+		}
+	}
+
 	return HSE_STATUS_SUCCESS;
 }
 



Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2008-03-27 13:24 UTC] Richard dot Krehbiel at gmail dot com
I haven't been paying attention.  The patch is badly word-wrapped, and so doesn't apply.

Here's a link to an unformatted plain-text version:

http://home.comcast.net/~krehbiel3/php5isapi.c.patch
 [2008-03-27 13:54 UTC] jani@php.net
Note: I deleted your other comments since they only had that badly formatted patch, so please add some information what your patch exactly does.
 [2008-03-27 14:27 UTC] Richard dot Krehbiel at gmail dot com
To alleviate SSL session setup/takedown costs, the "Keep-Alive" allows a single socket connection to be used for multiple transactions.  However, for simplicity of implementation, the original php5isapi module did not allow keep-alive.

This patch allows Keep-Alive by implementing "Transfer-Encoding: chunked" (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.41).
 [2008-03-28 13:55 UTC] Richard dot Krehbiel at gmail dot com
If you fetched this patch before now, you may need to fetch it again, as it's revised.

I found that scripts would crash IIS6 (exception code 0xC0000005) when run in a virtual directory and zlib.output_compression was turned off.  This change "fixes" it, for reasons I don't understand, which bothers me.  And IIS5 was immune.  And a "debug" build didn't exhibit the problem.  Since it's so weird a "fix," I'll also mention that I built it with Visual Studio  .NET SP1.

(It is a real correction, though; if a WriteClient call were to fail, it might have called php_handle_aborted_connection more than once.)
 [2011-04-08 21:05 UTC] jani@php.net
-Package: Feature/Change Request +Package: IIS related
 [2021-02-11 17:40 UTC] cmb@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: cmb
 [2021-02-11 17:40 UTC] cmb@php.net
Thanks for the patch!  However, ISAPI has long been removed from
PHP, so this feature request is obsolete.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Sat Jun 14 22:01:34 2025 UTC