Selaa lähdekoodia

System.Web: Fixed bugs in HttpRequest.GetBufferlessInputStream()

Alexander Köplinger 13 vuotta sitten
vanhempi
sitoutus
ebbe9b571d

+ 57 - 63
mcs/class/System.Web/System.Web/HttpRequest.cs

@@ -113,6 +113,7 @@ namespace System.Web
 		bool lazyQueryStringValidation;
 		bool inputValidationEnabled;
 		RequestContext requestContext;
+		BufferlessInputStream bufferlessInputStream;
 		
 		static bool validateRequestNewMode;
 		internal static bool ValidateRequestNewMode {
@@ -989,50 +990,17 @@ namespace System.Web
 			}
 		}
 
-		//
-		// TODO:
-		//   * I no longer remember what worker_request = null meant.
-		//   * Hook up the Filter?
-		// 
-		Stream MakeBufferlessInputStream ()
+		public Stream GetBufferlessInputStream ()
 		{
-			int content_length = ContentLength;
-			int content_length_kb = content_length / 1024;
-			HttpRuntimeSection config = HttpRuntime.Section;
-			if (content_length_kb > config.MaxRequestLength)
-				throw HttpException.NewWithCode (400, "Upload size exceeds httpRuntime limit.", WebEventCodes.RuntimeErrorPostTooLarge);
+			if (bufferlessInputStream == null) {
+				if (input_stream != null)
+					throw new HttpException ("Input stream has already been created");
 
-			int total = 0;
-			byte [] buffer;
-			buffer = worker_request.GetPreloadedEntityBody ();
-			// we check the instance field 'content_length' here, not the local var.
-			if (this.content_length <= 0 || worker_request.IsEntireEntityBodyIsPreloaded ()) {
-				if (buffer == null || content_length == 0) {
-					input_stream = new MemoryStream (new byte [0], 0, 0, false, true);
-				} else {
-					input_stream = new MemoryStream (buffer, 0, buffer.Length, false, true);
-				}
-				DoFilter (new byte [1024]);
-				return input_stream;
+				// we don't need to hook up the filter here, because the raw stream should be returned
+				bufferlessInputStream = new BufferlessInputStream (this);
 			}
 
-			if (buffer != null)
-				total = buffer.Length;
-
-			return new BufferlessInputStream (this, buffer);
-		}
-
-
-		public Stream GetBufferlessInputStream ()
-		{
-			if (input_stream != null)
-				throw new HttpException ("Input stream has already been created");
-			input_stream = MakeBufferlessInputStream ();
-			if (input_filter != null){
-				input_filter.BaseStream = input_stream;
-				return input_filter;
-			}
-			return input_stream;
+			return bufferlessInputStream;
 		}
 
 		//
@@ -1040,33 +1008,27 @@ namespace System.Web
 		//
 		class BufferlessInputStream : Stream {
 			HttpRequest request;
-			
 
 			// cached, the request content-length
 			int content_length;
 
-			// the buffer that we read from
+			// buffer that holds preloaded data
 			byte [] preloadedBuffer;
 
-			// number of valid bytes in buffer.
-			int bytes_in_buffer;
+			// indicates if we already served the whole preloaded buffer
+			bool preloaded_served;
 
-			// how many bytes we have returned so far
-			int total;
+			// indicates if we already checked the request content-length against httpRuntime limit
+			bool checked_maxRequestLength;
 
 			// our stream position
 			long position;
-			int buffer_start;
 
 			//
 			// @request: the containing request that created us, used to find out content length
-			// @buffer: the byte buffer that we start serving (may be null).
-			// @total: number of valid bytes in buffer.
-			public BufferlessInputStream (HttpRequest request, byte [] preloadedBuffer)
+			public BufferlessInputStream (HttpRequest request)
 			{
 				this.request = request;
-				this.preloadedBuffer = preloadedBuffer;
-				bytes_in_buffer = preloadedBuffer == null ? 0 : preloadedBuffer.Length;
 				content_length = request.ContentLength;
 			}
 
@@ -1105,28 +1067,60 @@ namespace System.Web
 			{
 				if (buffer == null)
 					throw new ArgumentNullException ("buffer");
-				
+
 				if (offset < 0 || count < 0)
 					throw new ArgumentOutOfRangeException ("offset or count less than zero.");
-				
+
 				if (buffer.Length - offset < count )
 					throw new ArgumentException ("offset+count",
 								     "The size of the buffer is less than offset + count.");
 
+				if (count == 0 || request.worker_request == null)
+					return 0;
+
+				if (!checked_maxRequestLength) {
+					int content_length_kb = content_length / 1024;
+					HttpRuntimeSection config = HttpRuntime.Section;
+					if (content_length_kb > config.MaxRequestLength)
+						throw HttpException.NewWithCode (400, "Upload size exceeds httpRuntime limit.", WebEventCodes.RuntimeErrorPostTooLarge);
+					else
+						checked_maxRequestLength = true;
+				}
+
 				// Serve the bytes we might have preloaded already.
-				if (preloadedBuffer != null){
-					int bytes_left = bytes_in_buffer-buffer_start;
-					if (bytes_left != 0){
-						int n = Math.Min (count, bytes_left);
-						Array.Copy (preloadedBuffer, buffer_start, buffer, offset, n);
-						buffer_start += n;
-						if (buffer_start == bytes_in_buffer)
-							preloadedBuffer = null;
+				if (!preloaded_served) {
+					if (preloadedBuffer == null)
+						preloadedBuffer = request.worker_request.GetPreloadedEntityBody ();
+
+					if (preloadedBuffer != null) {
+						long bytes_left = preloadedBuffer.Length-position;
+						int n = (int) Math.Min (count, bytes_left);
+						Array.Copy (preloadedBuffer, position, buffer, offset, n);
+						position += n;
+
+						if (n == bytes_left)
+							preloaded_served = true;
+
 						return n;
 					}
+					else
+						preloaded_served = true;
+				}
+
+				// serve bytes from worker request if available
+				if (position < content_length) {
+					long bytes_left = content_length-position;
+					int n = count;
+
+					if (bytes_left < count)
+						n = (int) bytes_left;
+
+					int bytes_read = request.worker_request.ReadEntityBody (buffer, offset, n);
+					position += bytes_read;
+					return bytes_read;
 				}
 
-				return request.worker_request.ReadEntityBody (buffer, offset, count);
+				return 0;
 			}
 
 			public override long Seek (long offset, SeekOrigin origin)

+ 7 - 1
mcs/class/System.Web/System.Web/HttpWorkerRequest.cs

@@ -298,7 +298,13 @@ namespace System.Web
 
 		public virtual int ReadEntityBody (byte [] buffer, int offset, int size)
 		{
-			return 0;
+			byte[] temp = new byte [size];
+			int n = ReadEntityBody (temp, size);
+
+			if(n > 0)
+				Array.Copy (temp, 0, buffer, offset, n);
+
+			return n;
 		}
 
 		public virtual void SendCalculatedContentLength (long contentLength)