#50078 [Com]: file upload to the thttpd (with php patch) fails

From: Date: Wed, 04 Nov 2009 15:36:11 +0000
Subject: #50078 [Com]: file upload to the thttpd (with php patch) fails
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-144257@lists.php.net to get a copy of this message
 ID:               50078
 Comment by:       nishantkumar05 at gmail dot com
 Reported By:      nishantkumar05 at gmail dot com
 Status:           Open
 Bug Type:         Other web server
 Operating System: ubuntu 8.10
 PHP Version:      5.3.0
 New Comment:

This is the patch available.
=============================================================
diff -Nur php-5.3.0/sapi/thttpd/thttpd.c php-
5.3.0_mod/sapi/thttpd/thttpd.c
--- php-5.3.0/sapi/thttpd/thttpd.c	2008-12-31 03:15:49.000000000 
-0800
+++ php-5.3.0_mod/sapi/thttpd/thttpd.c	2009-11-02 19:02:28.000000000 
-0800
@@ -64,6 +64,9 @@
 #define TG(v) (thttpd_globals.v)
 #endif
 
+
+int read_pending_content( void ); 
+
 static int sapi_thttpd_ub_write(const char *str, uint str_length 
TSRMLS_DC)
 {
 	int n;
@@ -247,16 +250,77 @@
 
 static int sapi_thttpd_read_post(char *buffer, uint count_bytes 
TSRMLS_DC)
 {
-	size_t read_bytes = 0;
+	size_t read_bytes = 0, send2php_bytes = 0 ;
+	size_t buff_bytes = TG(hc)->read_idx - TG(hc)->checked_idx ;
 
-	if (TG(unconsumed_length) > 0) {
-		read_bytes = MIN(TG(unconsumed_length), count_bytes);
-		memcpy(buffer, TG(hc)->read_buf + TG(hc)->checked_idx, 
read_bytes);
-		TG(unconsumed_length) -= read_bytes;
-		CONSUME_BYTES(read_bytes);
+
+	if ( buff_bytes > 0 ) {
+		/*we might already have some bytes in read_buf to be 
sent to php module*/
+		read_bytes = buff_bytes;
+	}else if ( TG(hc)->contentlength > 0 ){
+		read_bytes=read_pending_content();	
+	}
+
+	if ( read_bytes ) {
+			send2php_bytes = MIN ( read_bytes, 
count_bytes);
+			memcpy(buffer, TG(hc)->read_buf + TG(hc)-
>checked_idx, send2php_bytes);
+			TG(hc)->contentlength -= send2php_bytes;
+			/*bringing the read_idx back to checked_idx, 
so we have more room to read
+			  the pending bytes from connection*/
+			if ( send2php_bytes == read_bytes ) {
+				TG(hc)->read_idx = TG(hc)->checked_idx 
;
+			} else {
+				/*memmove is costly: but for small 
devices we cant increase the buffer
+  				  size substantially. presuming that 
memmove doesnt use extra buffer
+				  internally*/
+				memmove(TG(hc)->read_buf + TG(hc)-
>checked_idx, 
+							TG(hc)-
>read_buf + TG(hc)->checked_idx + send2php_bytes ,
+							read_bytes-
count_bytes);
+				TG(hc)->read_idx = TG(hc)->checked_idx 
+ ( read_bytes - count_bytes )  ;
+			}
+
+			TG(unconsumed_length) -= send2php_bytes;
 	}
-	
-	return read_bytes;
+
+	return send2php_bytes;
+}
+
+
+/*
+ * Read the max possible (limited by the available buffer ) pending 
data
+ * from the network. hc->contenlength has been used to tell about the

+ * pending data to be read from the network, hence onus is on the 
caller
+ * to modify it accordingly.
+ * It starts reading from checked_idx and updates the read_idx after 
reading.
+ * -nishant
+ * */
+int read_pending_content( void ) 
+{
+	int avail_buf= TG(hc)->read_size - TG(hc)->read_idx; 
+	int act_to_read=0,total_read=0,ctr=0;
+
+
+	if ( TG(hc)->contentlength < avail_buf ){
+		act_to_read = TG(hc)->contentlength;
+	} else {
+		act_to_read = avail_buf - 2;
+	}
+
+	while(total_read != act_to_read)
+	{
+		ctr = read(TG(hc)->conn_fd, &(TG(hc)->read_buf[TG(hc)-
>checked_idx]), act_to_read );
+		if(ctr < 0){
+			if( ( errno == EINTR ) || ( errno == EAGAIN ) 
){
+				continue;
+			}else{
+				break;
+			}
+		}
+		total_read += ctr;
+	}
+
+	TG(hc)->read_idx += total_read;
+	return total_read;
 }
 
 static char *sapi_thttpd_read_cookies(TSRMLS_D)
@@ -663,12 +727,14 @@
 		hc->do_keep_alive = 0;
 	}
 	
+#if 0
+	/*Its ok to have unconsumed bytes. We will consum in read_post 
function*/
 	if (hc->contentlength != -1
 			&& SIZEOF_UNCONSUMED_BYTES() < hc-
>contentlength) {
 		hc->read_body_into_mem = 1;
 		return 0;
 	}
-	
+#endif
 	thttpd_request_ctor(TSRMLS_C);
 
 	thttpd_module_main(show_source TSRMLS_CC);
=============================================================

thanks
Nishant


Previous Comments:
------------------------------------------------------------------------

[2009-11-04 15:27:21] nishantkumar05 at gmail dot com

Description:
------------
I have thttpd 2.1b patched with php-5.3.0. Try to upload file using
POST 
request to this web server. Small files ( max of 600 bytes or so ) can

be transferred, but big files, for which POST request will span
multiple 
packets fails.

Reproduce code:
---------------
.php web page that reproduces this bug is: (upload.php) 
<form enctype="multipart/form-data" action="uploader.php"
method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="2000000" />
Choose a file to upload: <input name="uploadedfile" type="file" /><br
/>
<input type="submit" value="Upload File" />
</form>

Expected result:
----------------
It should be able to upload file of any size successfully.



------------------------------------------------------------------------


-- 
Edit this bug report at http://bugs.php.net/?id=50078&edit=1



Thread (4 messages)

« previous php.bugs (#144257) next »