}
- internal IAsyncResult BeginRead (byte [] buffer, int offset, int size, AsyncCallback cb, object state)
+ internal IAsyncResult BeginRead (HttpWebRequest request, byte [] buffer, int offset, int size, AsyncCallback cb, object state)
{
- if (nstream == null)
- return null;
+ lock (this) {
+ if (Data.request != request)
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+ if (nstream == null)
+ return null;
+ }
IAsyncResult result = null;
if (!chunkedRead || chunkStream.WantMore) {
return result;
}
- internal int EndRead (IAsyncResult result)
+ internal int EndRead (HttpWebRequest request, IAsyncResult result)
{
- if (nstream == null)
- return 0;
+ lock (this) {
+ if (Data.request != request)
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+ if (nstream == null)
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+ }
int nbytes = 0;
WebAsyncResult wr = null;
return true;
}
- internal IAsyncResult BeginWrite (byte [] buffer, int offset, int size, AsyncCallback cb, object state)
+
+ internal IAsyncResult BeginWrite (HttpWebRequest request, byte [] buffer, int offset, int size, AsyncCallback cb, object state)
{
- IAsyncResult result = null;
- if (nstream == null)
- return null;
+ lock (this) {
+ if (Data.request != request)
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+ if (nstream == null)
+ return null;
+ }
+ IAsyncResult result = null;
try {
result = nstream.BeginWrite (buffer, offset, size, cb, state);
} catch (Exception) {
return result;
}
- internal bool EndWrite (IAsyncResult result)
+ internal void EndWrite2 (HttpWebRequest request, IAsyncResult result)
{
- if (nstream == null)
- return false;
+ lock (this) {
+ if (Data.request != request)
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+ if (nstream == null)
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+ }
+
+ try {
+ nstream.EndWrite (result);
+ } catch (Exception exc) {
+ status = WebExceptionStatus.SendFailure;
+ if (exc.InnerException != null)
+ throw exc.InnerException;
+ throw;
+ }
+ }
+
+ internal bool EndWrite (HttpWebRequest request, IAsyncResult result)
+ {
+ lock (this) {
+ if (Data.request != request)
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+ if (nstream == null)
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+ }
try {
nstream.EndWrite (result);
}
}
- internal int Read (byte [] buffer, int offset, int size)
+ internal int Read (HttpWebRequest request, byte [] buffer, int offset, int size)
{
- if (nstream == null)
- return 0;
+ lock (this) {
+ if (Data.request != request)
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+ if (nstream == null)
+ return 0;
+ }
int result = 0;
try {
return result;
}
- internal bool Write (byte [] buffer, int offset, int size)
+ internal bool Write (HttpWebRequest request, byte [] buffer, int offset, int size)
{
- if (nstream == null)
- return false;
+ lock (this) {
+ if (Data.request != request)
+ throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+ if (nstream == null)
+ return false;
+ }
try {
nstream.Write (buffer, offset, size);
}
busy = false;
+ Data = new WebConnectionData ();
if (sendNext)
SendNext ();
}
if (!req.FinishedReading) {
status = WebExceptionStatus.RequestCanceled;
Close (false);
- Data = new WebConnectionData ();
if (queue.Count > 0) {
Data.request = (HttpWebRequest) queue.Dequeue ();
SendRequest (Data.request);
}
}
+ internal HttpWebRequest Request {
+ get { return request; }
+ }
+
internal WebConnection Connection {
get { return cnc; }
}
buffer = new byte [8192];
int read;
- while ((read = cnc.Read (buffer, 0, buffer.Length)) != 0)
+ while ((read = cnc.Read (request, buffer, 0, buffer.Length)) != 0)
ms.Write (buffer, 0, read);
b = ms.GetBuffer ();
int remaining = new_size - diff;
int r = -1;
while (remaining > 0 && r != 0) {
- r = cnc.Read (b, diff, remaining);
+ r = cnc.Read (request, b, diff, remaining);
remaining -= r;
diff += r;
}
size = contentLength - totalRead;
if (!read_eof) {
- result.InnerAsyncResult = cnc.BeginRead (buffer, offset, size, cb, result);
+ result.InnerAsyncResult = cnc.BeginRead (request, buffer, offset, size, cb, result);
} else {
result.SetCompleted (true, result.NBytes);
result.DoCallback ();
if (!result.IsCompleted) {
int nbytes = -1;
try {
- nbytes = cnc.EndRead (result);
+ nbytes = cnc.EndRead (request, result);
} catch (Exception exc) {
lock (locker) {
pendingReads--;
int nb = result.NBytes;
return (nb >= 0) ? nb : 0;
}
-
+
+ void WriteRequestAsyncCB (IAsyncResult r)
+ {
+ WebAsyncResult result = (WebAsyncResult) r.AsyncState;
+ try {
+ cnc.EndWrite2 (request, r);
+ result.SetCompleted (false, 0);
+ if (!initRead) {
+ initRead = true;
+ WebConnection.InitRead (cnc);
+ }
+ } catch (Exception e) {
+ result.SetCompleted (false, e);
+ }
+ headersSent = true;
+ complete_request_written = true;
+ result.DoCallback ();
+ }
+
public override IAsyncResult BeginWrite (byte [] buffer, int offset, int size,
AsyncCallback cb, object state)
{
WebAsyncResult result = new WebAsyncResult (cb, state);
if (!sendChunked)
CheckWriteOverflow (request.ContentLength, totalWritten, size);
- if (allowBuffering) {
+ if (allowBuffering && !sendChunked) {
writeBuffer.Write (buffer, offset, size);
totalWritten += size;
- if (!sendChunked) {
+ if (request.ContentLength > 0 && totalWritten == request.ContentLength) {
+ try {
+ result.AsyncWriteAll = true;
+ result.InnerAsyncResult = WriteRequestAsync (new AsyncCallback (WriteRequestAsyncCB), result);
+ if (result.InnerAsyncResult == null) {
+ result.SetCompleted (true, 0);
+ result.DoCallback ();
+ }
+ } catch (Exception exc) {
+ result.SetCompleted (true, exc);
+ result.DoCallback ();
+ }
+ } else {
result.SetCompleted (true, 0);
result.DoCallback ();
- return result;
}
+ return result;
}
AsyncCallback callback = null;
size = chunkSize;
}
- result.InnerAsyncResult = cnc.BeginWrite (buffer, offset, size, callback, result);
+ result.InnerAsyncResult = cnc.BeginWrite (request, buffer, offset, size, callback, result);
totalWritten += size;
return result;
}
- static void CheckWriteOverflow (long contentLength, long totalWritten, long size)
+ void CheckWriteOverflow (long contentLength, long totalWritten, long size)
{
if (contentLength == -1)
return;
long avail = contentLength - totalWritten;
- if (size > avail)
+ if (size > avail) {
+ KillBuffer ();
+ nextReadCalled = true;
+ cnc.Close (true);
throw new ProtocolViolationException (
"The number of bytes to be written is greater than " +
"the specified ContentLength.");
+ }
}
public override void EndWrite (IAsyncResult r)
return;
result.EndCalled = true;
+ if (result.AsyncWriteAll) {
+ result.WaitUntilComplete ();
+ if (result.GotException)
+ throw result.Exception;
+ return;
+ }
if (allowBuffering && !sendChunked)
return;
if (result.GotException)
throw result.Exception;
- try {
- cnc.EndWrite (result.InnerAsyncResult);
+ try {
+ cnc.EndWrite (request, result.InnerAsyncResult);
result.SetCompleted (false, 0);
} catch (Exception e) {
result.SetCompleted (false, e);
- }
-
- if (sendChunked) {
- lock (locker) {
- pendingWrites--;
- if (pendingWrites == 0)
- pending.Set ();
+ throw;
+ } finally {
+ if (sendChunked) {
+ lock (locker) {
+ pendingWrites--;
+ if (pendingWrites == 0)
+ pending.Set ();
+ }
}
}
}
AsyncCallback cb = new AsyncCallback (WriteCallbackWrapper);
WebAsyncResult res = (WebAsyncResult) BeginWrite (buffer, offset, size, cb, null);
if (!res.IsCompleted && !res.WaitUntilComplete (WriteTimeout, false)) {
+ KillBuffer ();
nextReadCalled = true;
cnc.Close (true);
throw new IOException ("Write timed out.");
if (!allowBuffering || sendChunked) {
headersSent = true;
- if (!cnc.Connected)
+ if (!cnc.Connected) {
+ KillBuffer ();
throw new WebException ("Not connected", null, WebExceptionStatus.SendFailure, null);
+ }
- if (!cnc.Write (buffer, offset, size))
+ if (!cnc.Write (request, buffer, offset, size)) {
+ KillBuffer ();
throw new WebException ("Error writing request.", null, WebExceptionStatus.SendFailure, null);
+ }
if (!initRead) {
initRead = true;
get { return requestWritten; }
}
+ IAsyncResult WriteRequestAsync (AsyncCallback cb, object state)
+ {
+ requestWritten = true;
+ byte [] bytes = writeBuffer.GetBuffer ();
+ int length = (int) writeBuffer.Length;
+ writeBuffer = null;
+ request.InternalContentLength = length;
+ request.SendRequestHeaders ();
+
+ //
+ // For small requests, make a copy, it will reduce the traffic, for large
+ // requests, the NoDelay bit on the socket should take effect (set in WebConnection).
+ //
+ if (headers.Length + length < 8192){
+ byte[] b = new byte [headers.Length + length];
+
+ Buffer.BlockCopy (headers, 0, b, 0, headers.Length);
+ Buffer.BlockCopy (bytes, 0, b, headers.Length, length);
+
+ return cnc.BeginWrite (request, b, 0, b.Length, cb, state);
+ } else {
+ if (!cnc.Write (request, headers, 0, headers.Length))
+ throw new WebException ("Error writing request.", null, WebExceptionStatus.SendFailure, null);
+
+ headersSent = true;
+ if (cnc.Data.StatusCode != 0 && cnc.Data.StatusCode != 100)
+ return null;
+
+ return (length > 0) ? cnc.BeginWrite (request, bytes, 0, length, cb, state) : null;
+ }
+ }
+
internal void WriteRequest ()
{
if (requestWritten)
byte [] bytes = writeBuffer.GetBuffer ();
int length = (int) writeBuffer.Length;
+ writeBuffer = null;
if (request.ContentLength != -1 && request.ContentLength < length) {
+ nextReadCalled = true;
+ cnc.Close (true);
throw new WebException ("Specified Content-Length is less than the number of bytes to write", null,
WebExceptionStatus.ServerProtocolViolation, null);
}
Buffer.BlockCopy (headers, 0, b, 0, headers.Length);
Buffer.BlockCopy (bytes, 0, b, headers.Length, length);
- if (!cnc.Write (b, 0, b.Length))
+ if (!cnc.Write (request, b, 0, b.Length))
throw new WebException ("Error writing request.", null, WebExceptionStatus.SendFailure, null);
headersSent = true;
WebConnection.InitRead (cnc);
}
} else {
- if (!cnc.Write (headers, 0, headers.Length))
+ if (!cnc.Write (request, headers, 0, headers.Length))
throw new WebException ("Error writing request.", null, WebExceptionStatus.SendFailure, null);
headersSent = true;
IAsyncResult result = null;
if (length > 0)
- result = cnc.BeginWrite (bytes, 0, length, null, null);
+ result = cnc.BeginWrite (request, bytes, 0, length, null, null);
if (!initRead) {
initRead = true;
WebConnection.InitRead (cnc);
}
-
+
if (length > 0)
- complete_request_written = cnc.EndWrite (result);
+ complete_request_written = cnc.EndWrite (request, result);
else
complete_request_written = true;
}
disposed = true;
}
- internal void ForceCloseConnection ()
- {
- if (!disposed) {
- disposed = true;
- cnc.Close (true);
- }
- }
-
public override void Close ()
{
if (sendChunked) {
pending.WaitOne ();
byte [] chunk = Encoding.ASCII.GetBytes ("0\r\n\r\n");
- cnc.Write (chunk, 0, chunk.Length);
+ cnc.Write (request, chunk, 0, chunk.Length);
return;
}
return;
}
- if (disposed)
+ if (disposed || requestWritten)
return;
long length = request.ContentLength;