2 // System.Net.WebConnectionStream
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2003 Ximian, Inc (http://www.ximian.com)
11 using System.Threading;
15 class WebConnectionStream : Stream
19 HttpWebRequest request;
27 ManualResetEvent pending;
30 MemoryStream writeBuffer;
34 public WebConnectionStream (WebConnection cnc)
37 pending = new ManualResetEvent (true);
40 contentLength = Int32.Parse (cnc.Data.Headers ["Content-Length"]);
42 contentLength = Int32.MaxValue;
46 public WebConnectionStream (WebConnection cnc, HttpWebRequest request)
50 this.request = request;
51 allowBuffering = request.InternalAllowBuffering;
52 sendChunked = request.SendChunked;
54 writeBuffer = new MemoryStream ();
57 internal byte [] ReadBuffer {
58 set { readBuffer = value; }
61 internal int ReadBufferOffset {
62 set { readBufferOffset = value;}
65 internal int ReadBufferSize {
66 set { readBufferSize = value; }
69 internal void CheckComplete ()
71 if (readBufferSize - readBufferOffset == contentLength) {
72 nextReadCalled = true;
77 internal void ReadAll ()
79 if (!isRead || totalRead >= contentLength || nextReadCalled)
84 if (totalRead >= contentLength)
88 int diff = readBufferSize - readBufferOffset;
91 if (contentLength == Int32.MaxValue) {
92 MemoryStream ms = new MemoryStream ();
93 if (readBuffer != null && diff > 0)
94 ms.Write (readBuffer, readBufferOffset, diff);
96 byte [] buffer = new byte [2048];
98 while ((read = cnc.Read (buffer, 0, 2048)) != 0)
99 ms.Write (buffer, 0, read);
102 new_size = (int) ms.Length;
104 new_size = contentLength - totalRead;
105 b = new byte [new_size];
106 if (readBuffer != null && diff > 0)
107 Buffer.BlockCopy (readBuffer, readBufferOffset, b, 0, diff);
109 int remaining = new_size - diff;
111 while (remaining > 0 && r != 0) {
112 r = cnc.Read (b, diff, remaining);
119 readBufferOffset = 0;
120 readBufferSize = new_size;
121 contentLength = new_size;
123 nextReadCalled = true;
129 public override int Read (byte [] buffer, int offset, int size)
132 throw new NotSupportedException ("this stream does not allow reading");
134 if (totalRead >= contentLength)
137 IAsyncResult res = BeginRead (buffer, offset, size, null, null);
138 return EndRead (res);
141 public override IAsyncResult BeginRead (byte [] buffer, int offset, int size,
142 AsyncCallback cb, object state)
145 throw new NotSupportedException ("this stream does not allow reading");
148 throw new ArgumentNullException ("buffer");
150 int length = buffer.Length;
151 if (size < 0 || offset < 0 || length < offset || length - offset < size)
152 throw new ArgumentOutOfRangeException ();
159 WebAsyncResult result = new WebAsyncResult (cb, state, buffer, offset, size);
160 if (totalRead >= contentLength) {
161 result.SetCompleted (true, 0);
162 result.DoCallback ();
166 int remaining = readBufferSize - readBufferOffset;
168 int copy = (remaining > size) ? size : remaining;
169 Buffer.BlockCopy (readBuffer, readBufferOffset, buffer, offset, copy);
171 readBufferOffset += copy;
174 if (size == 0 || totalRead >= contentLength) {
175 result.SetCompleted (true, copy);
176 result.DoCallback ();
181 result.InnerAsyncResult = cnc.BeginRead (buffer, offset, size, null, null);
185 public override int EndRead (IAsyncResult r)
187 WebAsyncResult result = (WebAsyncResult) r;
190 if (result.IsCompleted) {
191 nbytes = result.NBytes;
193 nbytes = cnc.EndRead (result.InnerAsyncResult);
196 if (pendingReads == 0)
199 result.SetCompleted (false, nbytes);
203 if (totalRead >= contentLength && !nextReadCalled) {
204 nextReadCalled = true;
211 public override IAsyncResult BeginWrite (byte [] buffer, int offset, int size,
212 AsyncCallback cb, object state)
215 throw new NotSupportedException ("this stream does not allow writing");
218 throw new ArgumentNullException ("buffer");
220 int length = buffer.Length;
221 if (size < 0 || offset < 0 || length < offset || length - offset < size)
222 throw new ArgumentOutOfRangeException ();
224 WebAsyncResult result = new WebAsyncResult (cb, state);
225 if (allowBuffering) {
226 writeBuffer.Write (buffer, offset, size);
227 result.SetCompleted (true, 0);
228 result.DoCallback ();
230 result.InnerAsyncResult = cnc.BeginWrite (buffer, offset, size, cb, state);
231 if (result.InnerAsyncResult == null)
232 throw new WebException ("Aborted");
238 public override void EndWrite (IAsyncResult r)
241 throw new ArgumentNullException ("r");
246 WebAsyncResult result = r as WebAsyncResult;
248 throw new ArgumentException ("Invalid IAsyncResult");
250 cnc.EndWrite (result.InnerAsyncResult);
254 public override void Write (byte [] buffer, int offset, int size)
257 throw new NotSupportedException ("this stream does not allow writing");
259 IAsyncResult res = BeginWrite (buffer, offset, size, null, null);
263 public override void Flush ()
267 internal void SetHeaders (byte [] buffer, int offset, int size)
269 if (!allowBuffering) {
270 Write (buffer, offset, size);
272 headers = new byte [size];
273 Buffer.BlockCopy (buffer, offset, headers, 0, size);
277 internal void WriteRequest ()
279 if (!allowBuffering || writeBuffer == null || requestWritten)
282 byte [] bytes = writeBuffer.GetBuffer ();
283 int length = (int) writeBuffer.Length;
284 if (request.ContentLength != -1 && request.ContentLength < length) {
285 throw new ProtocolViolationException ("Specified Content-Length is less than the " +
286 "number of bytes to write");
289 request.InternalContentLength = length;
290 request.SendRequestHeaders ();
291 cnc.WaitForContinue (headers, 0, headers.Length);
292 if (cnc.Data.StatusCode != 0 && cnc.Data.StatusCode != 100)
295 cnc.Write (bytes, 0, length);
296 requestWritten = true;
297 cnc.dataAvailable.Set ();
300 public override void Close ()
305 // may be ReadAll is isRead?
306 long length = request.ContentLength;
307 if (length != -1 && length > writeBuffer.Length)
308 throw new IOException ("Cannot close the stream until all bytes are written");
313 internal void ResetWriteBuffer ()
318 writeBuffer = new MemoryStream ();
319 requestWritten = false;
322 public override long Seek (long a, SeekOrigin b)
324 throw new NotSupportedException ();
327 public override void SetLength (long a)
329 throw new NotSupportedException ();
332 public override bool CanSeek {
333 get { return false; }
336 public override bool CanRead {
337 get { return isRead && (contentLength == Int32.MaxValue || totalRead < contentLength); }
340 public override bool CanWrite {
341 get { return !isRead; }
344 public override long Length {
345 get { throw new NotSupportedException (); }
348 public override long Position {
349 get { throw new NotSupportedException (); }
350 set { throw new NotSupportedException (); }