using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace System.Net {
- class RequestStream : NetworkStream
+ class RequestStream : Stream
{
byte [] buffer;
int offset;
int length;
+ long remaining_body;
bool disposed;
+ Stream stream;
- internal RequestStream (Socket sock, byte [] buffer, int offset, int length) :
- base (sock, false)
+ internal RequestStream (Stream stream, byte [] buffer, int offset, int length)
+ : this (stream, buffer, offset, length, -1)
{
+ }
+
+ internal RequestStream (Stream stream, byte [] buffer, int offset, int length, long contentlength)
+ {
+ this.stream = stream;
this.buffer = buffer;
this.offset = offset;
this.length = length;
+ this.remaining_body = contentlength;
}
public override bool CanRead {
{
}
- // true if the we have >= count bytes in this.buffer
+
+ // Returns 0 if we can keep reading from the base stream,
+ // > 0 if we read something from the buffer.
+ // -1 if we had a content length set and we finished reading that many bytes.
int FillFromBuffer (byte [] buffer, int off, int count)
{
- int size = this.length - this.offset;
- if (size <= 0)
- return 0;
-
if (buffer == null)
throw new ArgumentNullException ("buffer");
if (off < 0)
if (off > len - count)
throw new ArgumentException ("Reading would overrun buffer");
- size = Math.Min (size, count);
+ if (this.remaining_body == 0)
+ return -1;
+
+ if (this.length == 0)
+ return 0;
+
+ int size = Math.Min (this.length, count);
+ if (this.remaining_body > 0)
+ size = (int) Math.Min (size, this.remaining_body);
+
+ if (this.offset > this.buffer.Length - size) {
+ size = Math.Min (size, this.buffer.Length - this.offset);
+ }
+ if (size == 0)
+ return 0;
+
Buffer.BlockCopy (this.buffer, this.offset, buffer, off, size);
this.offset += size;
+ this.length -= size;
+ if (this.remaining_body > 0)
+ remaining_body -= size;
return size;
}
if (disposed)
throw new ObjectDisposedException (typeof (RequestStream).ToString ());
+ // Call FillFromBuffer to check for buffer boundaries even when remaining_body is 0
int nread = FillFromBuffer (buffer, offset, count);
- if (nread > 0)
+ if (nread == -1) { // No more bytes available (Content-Length)
+ return 0;
+ } else if (nread > 0) {
return nread;
+ }
- return base.Read (buffer, offset, count);
+ nread = stream.Read (buffer, offset, count);
+ if (nread > 0 && remaining_body > 0)
+ remaining_body -= nread;
+ return nread;
}
public override IAsyncResult BeginRead (byte [] buffer, int offset, int count,
throw new ObjectDisposedException (typeof (RequestStream).ToString ());
int nread = FillFromBuffer (buffer, offset, count);
- if (nread > 0) {
+ if (nread > 0 || nread == -1) {
HttpStreamAsyncResult ares = new HttpStreamAsyncResult ();
ares.Buffer = buffer;
ares.Offset = offset;
return ares;
}
- return base.BeginRead (buffer, offset, count, cback, state);
+ // Avoid reading past the end of the request to allow
+ // for HTTP pipelining
+ if (remaining_body >= 0 && count > remaining_body)
+ count = (int) Math.Min (Int32.MaxValue, remaining_body);
+ return stream.BeginRead (buffer, offset, count, cback, state);
}
public override int EndRead (IAsyncResult ares)
}
// Close on exception?
- return base.EndRead (ares);
+ int nread = stream.EndRead (ares);
+ if (remaining_body > 0 && nread > 0)
+ remaining_body -= nread;
+ return nread;
}
public override long Seek (long offset, SeekOrigin origin)