int readBufferOffset;
int readBufferSize;
int stream_length; // -1 when CL not present
- int contentLength;
- int totalRead;
+ long contentLength;
+ long totalRead;
internal long totalWritten;
bool nextReadCalled;
int pendingReads;
ReadAll ();
}
} catch {
- contentLength = Int32.MaxValue;
+ contentLength = Int64.MaxValue;
}
} else {
- contentLength = Int32.MaxValue;
+ contentLength = Int64.MaxValue;
}
// Negative numbers?
internal void ForceCompletion ()
{
if (!nextReadCalled) {
- if (contentLength == Int32.MaxValue)
+ if (contentLength == Int64.MaxValue)
contentLength = 0;
nextReadCalled = true;
cnc.NextRead ();
return;
}
- pending.WaitOne ();
+ if (!pending.WaitOne (ReadTimeout))
+ throw new WebException ("The operation has timed out.", WebExceptionStatus.Timeout);
lock (locker) {
if (totalRead >= contentLength)
return;
int diff = readBufferSize - readBufferOffset;
int new_size;
- if (contentLength == Int32.MaxValue) {
+ if (contentLength == Int64.MaxValue) {
MemoryStream ms = new MemoryStream ();
byte [] buffer = null;
if (readBuffer != null && diff > 0) {
new_size = (int) ms.Length;
contentLength = new_size;
} else {
- new_size = contentLength - totalRead;
+ new_size = (int) (contentLength - totalRead);
b = new byte [new_size];
if (readBuffer != null && diff > 0) {
if (diff > new_size)
if (cb != null)
cb = cb_wrapper;
- if (contentLength != Int32.MaxValue && contentLength - totalRead < size)
- size = contentLength - totalRead;
+ if (contentLength != Int64.MaxValue && contentLength - totalRead < size)
+ size = (int)(contentLength - totalRead);
if (!read_eof) {
result.InnerAsyncResult = cnc.BeginRead (request, buffer, offset, size, cb, result);
if (result.EndCalled)
return;
+ if (sendChunked) {
+ lock (locker) {
+ pendingWrites--;
+ if (pendingWrites <= 0)
+ pending.Set ();
+ }
+ }
+
result.EndCalled = true;
if (result.AsyncWriteAll) {
result.WaitUntilComplete ();
if (result.GotException)
throw result.Exception;
-
- if (sendChunked) {
- lock (locker) {
- pendingWrites--;
- if (pendingWrites == 0)
- pending.Set ();
- }
- }
}
public override void Write (byte [] buffer, int offset, int size)
{
}
- internal WebAsyncResult SetHeadersAsync (bool setInternalLength, AsyncCallback callback, object state)
+ internal void SetHeadersAsync (bool setInternalLength, SimpleAsyncCallback callback)
+ {
+ SimpleAsyncResult.Run (r => SetHeadersAsync (r, setInternalLength), callback);
+ }
+
+ bool SetHeadersAsync (SimpleAsyncResult result, bool setInternalLength)
{
if (headersSent)
- return null;
+ return false;
string method = request.Method;
bool no_writestream = (method == "GET" || method == "CONNECT" || method == "HEAD" ||
if (setInternalLength && !no_writestream && writeBuffer != null)
request.InternalContentLength = writeBuffer.Length;
- if (sendChunked || request.ContentLength > -1 || no_writestream || webdav) {
- headersSent = true;
- headers = request.GetRequestHeaders ();
+ bool has_content = !no_writestream && (writeBuffer == null || request.ContentLength > -1);
+ if (!(sendChunked || has_content || no_writestream || webdav))
+ return false;
- var result = new WebAsyncResult (callback, state);
- result.InnerAsyncResult = cnc.BeginWrite (request, headers, 0, headers.Length, new AsyncCallback (SetHeadersCB), result);
- if (result.InnerAsyncResult != null)
- return result;
- }
-
- return null;
- }
+ headersSent = true;
+ headers = request.GetRequestHeaders ();
- void SetHeadersCB (IAsyncResult r)
- {
- WebAsyncResult result = (WebAsyncResult) r.AsyncState;
- result.InnerAsyncResult = null;
- try {
- cnc.EndWrite (request, true, r);
- result.SetCompleted (false, 0);
- if (!initRead) {
- initRead = true;
- WebConnection.InitRead (cnc);
+ var innerResult = cnc.BeginWrite (request, headers, 0, headers.Length, r => {
+ try {
+ cnc.EndWrite (request, true, r);
+ if (!initRead) {
+ initRead = true;
+ WebConnection.InitRead (cnc);
+ }
+ var cl = request.ContentLength;
+ if (!sendChunked && cl == 0)
+ requestWritten = true;
+ result.SetCompleted (false);
+ } catch (WebException e) {
+ result.SetCompleted (false, e);
+ } catch (Exception e) {
+ result.SetCompleted (false, new WebException ("Error writing headers", e, WebExceptionStatus.SendFailure));
}
- long cl = request.ContentLength;
- if (!sendChunked && cl == 0)
- requestWritten = true;
- } catch (WebException e) {
- result.SetCompleted (false, e);
- } catch (Exception e) {
- result.SetCompleted (false, new WebException ("Error writing headers", e, WebExceptionStatus.SendFailure));
- }
- result.DoCallback ();
+ }, null);
+
+ return innerResult != null;
}
internal bool RequestWritten {
get { return requestWritten; }
}
- internal WebAsyncResult WriteRequestAsync (AsyncCallback callback, object state)
+ internal SimpleAsyncResult WriteRequestAsync (SimpleAsyncCallback callback)
+ {
+ var result = WriteRequestAsync (callback);
+ try {
+ if (!WriteRequestAsync (result))
+ result.SetCompleted (true);
+ } catch (Exception ex) {
+ result.SetCompleted (true, ex);
+ }
+ return result;
+ }
+
+ internal bool WriteRequestAsync (SimpleAsyncResult result)
{
if (requestWritten)
- return null;
+ return false;
requestWritten = true;
- if (sendChunked)
- return null;
-
- if (!allowBuffering || writeBuffer == null)
- return null;
+ if (sendChunked || !allowBuffering || writeBuffer == null)
+ return false;
// Keep the call for a potential side-effect of GetBuffer
- writeBuffer.GetBuffer ();
- int length = (int)writeBuffer.Length;
+ var bytes = writeBuffer.GetBuffer ();
+ var length = (int)writeBuffer.Length;
if (request.ContentLength != -1 && request.ContentLength < length) {
nextReadCalled = true;
cnc.Close (true);
WebExceptionStatus.ServerProtocolViolation, null);
}
- var result = new WebAsyncResult (callback, state);
- result.InnerAsyncResult = SetHeadersAsync (true, WriteRequestAsyncCB, result);
- if (result.InnerAsyncResult == null)
- WriteRequestAsyncCB (result);
- return result;
- }
-
- void WriteRequestAsyncCB (IAsyncResult ar)
- {
- var result = (WebAsyncResult)ar;
- var innerResult = (WebAsyncResult)result.InnerAsyncResult;
- result.InnerAsyncResult = null;
-
- if (innerResult != null && innerResult.GotException) {
- result.SetCompleted (false, innerResult.Exception);
- result.DoCallback ();
- return;
- }
-
- if (cnc.Data.StatusCode != 0 && cnc.Data.StatusCode != 100) {
- result.SetCompleted (false, 0);
- result.DoCallback ();
- return;
- }
-
- byte[] bytes = writeBuffer.GetBuffer ();
- int length = (int)writeBuffer.Length;
+ SetHeadersAsync (true, inner => {
+ if (inner.GotException) {
+ result.SetCompleted (inner.CompletedSynchronously, inner.Exception);
+ return;
+ }
- if (length > 0)
- result.InnerAsyncResult = cnc.BeginWrite (request, bytes, 0, length, WriteRequestAsyncCB2, result);
+ if (cnc.Data.StatusCode != 0 && cnc.Data.StatusCode != 100) {
+ result.SetCompleted (inner.CompletedSynchronously);
+ return;
+ }
- if (!initRead) {
- initRead = true;
- WebConnection.InitRead (cnc);
- }
+ if (!initRead) {
+ initRead = true;
+ WebConnection.InitRead (cnc);
+ }
- if (length == 0) {
- result.SetCompleted (false, 0);
- result.DoCallback ();
- complete_request_written = true;
- }
- }
+ if (length == 0) {
+ complete_request_written = true;
+ result.SetCompleted (inner.CompletedSynchronously);
+ return;
+ }
- void WriteRequestAsyncCB2 (IAsyncResult ar)
- {
- var result = (WebAsyncResult)ar.AsyncState;
- var innerResult = result.InnerAsyncResult;
- result.InnerAsyncResult = null;
+ cnc.BeginWrite (request, bytes, 0, length, r => {
+ try {
+ complete_request_written = cnc.EndWrite (request, false, r);
+ result.SetCompleted (false);
+ } catch (Exception exc) {
+ result.SetCompleted (false, exc);
+ }
+ }, null);
+ });
- try {
- complete_request_written = cnc.EndWrite (request, false, innerResult);
- result.SetCompleted (false, 0);
- } catch (Exception exc) {
- result.SetCompleted (false, exc);
- } finally {
- result.DoCallback ();
- }
+ return true;
}
internal void InternalClose ()
disposed = true;
}
+ internal bool GetResponseOnClose {
+ get; set;
+ }
+
public override void Close ()
{
+ if (GetResponseOnClose) {
+ if (disposed)
+ return;
+ disposed = true;
+ var response = (HttpWebResponse)request.GetResponse ();
+ response.ReadAll ();
+ response.Close ();
+ return;
+ }
+
if (sendChunked) {
if (disposed)
return;
disposed = true;
- pending.WaitOne ();
+ if (!pending.WaitOne (WriteTimeout)) {
+ throw new WebException ("The operation has timed out.", WebExceptionStatus.Timeout);
+ }
byte [] chunk = Encoding.ASCII.GetBytes ("0\r\n\r\n");
string err_msg = null;
cnc.Write (request, chunk, 0, chunk.Length, ref err_msg);