bool headersSent;
object locker = new object ();
bool initRead;
+ bool read_eof;
+ bool complete_request_written;
+ long max_buffer_size;
public WebConnectionStream (WebConnection cnc)
{
pending = new ManualResetEvent (true);
this.request = cnc.Data.request;
this.cnc = cnc;
+ string contentType = cnc.Data.Headers ["Transfer-Encoding"];
+ bool chunkedRead = (contentType != null && contentType.ToLower ().IndexOf ("chunked") != -1);
string clength = cnc.Data.Headers ["Content-Length"];
- if (clength != null && clength != "") {
+ if (!chunkedRead && clength != null && clength != "") {
+
try {
contentLength = Int32.Parse (clength);
} catch {
this.request = request;
allowBuffering = request.InternalAllowBuffering;
sendChunked = request.SendChunked;
- if (allowBuffering)
+ if (allowBuffering) {
writeBuffer = new MemoryStream ();
+ max_buffer_size = request.ContentLength;
+ } else {
+ max_buffer_size = -1;
+ }
if (sendChunked)
pending = new ManualResetEvent (true);
}
+ internal bool CompleteRequestWritten {
+ get { return complete_request_written; }
+ }
+
internal bool SendChunked {
set { sendChunked = value; }
}
internal void ReadAll ()
{
- if (!isRead || totalRead >= contentLength || nextReadCalled) {
- if (!nextReadCalled) {
+ if (!isRead || read_eof || totalRead >= contentLength || nextReadCalled) {
+ if (isRead && !nextReadCalled) {
nextReadCalled = true;
cnc.NextRead ();
}
AsyncCallback cb = new AsyncCallback (ReadCallbackWrapper);
WebAsyncResult res = (WebAsyncResult) BeginRead (buffer, offset, size, cb, null);
if (!res.IsCompleted && !res.WaitUntilComplete (request.ReadWriteTimeout, false)) {
+ nextReadCalled = true;
cnc.Close (true);
throw new IOException ("Read timed out.");
}
if (contentLength != Int32.MaxValue && contentLength - totalRead < size)
size = contentLength - totalRead;
- result.InnerAsyncResult = cnc.BeginRead (buffer, offset, size, cb, result);
+ if (!read_eof) {
+ result.InnerAsyncResult = cnc.BeginRead (buffer, offset, size, cb, result);
+ } else {
+ result.SetCompleted (true, result.NBytes);
+ result.DoCallback ();
+ }
return result;
}
result.EndCalled = true;
if (!result.IsCompleted) {
- int nbytes = cnc.EndRead (result);
- bool finished = (nbytes == -1);
- if (finished && result.NBytes > 0)
+ int nbytes = -1;
+ try {
+ nbytes = cnc.EndRead (result);
+ } catch (Exception exc) {
+ lock (locker) {
+ pendingReads--;
+ if (pendingReads == 0)
+ pending.Set ();
+ }
+
+ nextReadCalled = true;
+ cnc.Close (true);
+ result.SetCompleted (false, exc);
+ throw;
+ }
+
+ if (nbytes < 0) {
nbytes = 0;
+ read_eof = true;
+ }
totalRead += nbytes;
result.SetCompleted (false, nbytes + result.NBytes);
result.DoCallback ();
- if (finished || nbytes == 0)
+ if (nbytes == 0)
contentLength = totalRead;
}
WebAsyncResult result = new WebAsyncResult (cb, state);
if (allowBuffering) {
+ if (max_buffer_size >= 0) {
+ long avail = max_buffer_size - writeBuffer.Length;
+ if (size > avail) {
+ if (requestWritten)
+ throw new ProtocolViolationException (
+ "The number of bytes to be written is greater than " +
+ "the specified ContentLength.");
+ }
+ }
writeBuffer.Write (buffer, offset, size);
if (!sendChunked) {
result.SetCompleted (true, 0);
AsyncCallback cb = new AsyncCallback (WriteCallbackWrapper);
WebAsyncResult res = (WebAsyncResult) BeginWrite (buffer, offset, size, cb, null);
if (!res.IsCompleted && !res.WaitUntilComplete (request.ReadWriteTimeout, false)) {
+ nextReadCalled = true;
cnc.Close (true);
throw new IOException ("Write timed out.");
}
if (cnc.Data.StatusCode != 0 && cnc.Data.StatusCode != 100)
return;
- cnc.Write (bytes, 0, length);
+ IAsyncResult result = null;
+ if (length > 0)
+ result = cnc.BeginWrite (bytes, 0, length, null, null);
+
+ if (!initRead) {
+ initRead = true;
+ WebConnection.InitRead (cnc);
+ }
+
+ if (length > 0)
+ complete_request_written = cnc.EndWrite (result);
+ else
+ complete_request_written = true;
}
internal void InternalClose ()
{
disposed = true;
}
-
+
+ internal void ForceCloseConnection ()
+ {
+ if (!disposed) {
+ disposed = true;
+ cnc.Close (true);
+ }
+ }
+
public override void Close ()
{
if (sendChunked) {
if (!nextReadCalled) {
CheckComplete ();
// If we have not read all the contents
- if (!nextReadCalled)
+ if (!nextReadCalled) {
+ nextReadCalled = true;
cnc.Close (true);
+ }
}
return;
} else if (!allowBuffering) {
+ complete_request_written = true;
if (!initRead) {
initRead = true;
WebConnection.InitRead (cnc);
if (disposed)
return;
- disposed = true;
-
long length = request.ContentLength;
if (length != -1 && length > writeBuffer.Length)
throw new IOException ("Cannot close the stream until all bytes are written");
WriteRequest ();
- if (!initRead) {
- initRead = true;
- WebConnection.InitRead (cnc);
- }
+ disposed = true;
}
public override long Seek (long a, SeekOrigin b)