php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #50078 [PATCH] file upload fails with thttpd
Submitted: 2009-11-04 15:27 UTC Modified: 2018-07-14 13:05 UTC
Votes:2
Avg. Score:4.5 ± 0.5
Reproduced:2 of 2 (100.0%)
Same Version:2 (100.0%)
Same OS:2 (100.0%)
From: nishantkumar05 at gmail dot com Assigned: cmb (profile)
Status: Closed Package: Other web server
PHP Version: 5.3.0 OS: ubuntu 8.10
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: nishantkumar05 at gmail dot com
New email:
PHP Version: OS:

 

 [2009-11-04 15:27 UTC] 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.


Patches

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-11-04 15:36 UTC] nishantkumar05 at gmail dot com
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
 [2009-11-20 10:22 UTC] asure007 at hotmail dot com
I've grabbed that patch and edited it back into something i could use, but it won't work for me. Can you upload it somewhere to wget ?

The error i get:
patch: **** malformed patch at line 100:  static char *sapi_thttpd_read_cookies(TSRMLS_D)
 [2018-07-14 13:05 UTC] cmb@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: cmb
 [2018-07-14 13:05 UTC] cmb@php.net
The thttp SAPI is no longer available as of PHP 7.0.0, so this
ticket is obsolete.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Sep 08 01:01:28 2024 UTC