2 // System.Net.WebConnection
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2003 Ximian, Inc (http://www.ximian.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System
.Collections
;
33 using System
.Net
.Sockets
;
34 using System
.Reflection
;
35 using System
.Security
.Cryptography
.X509Certificates
;
37 using System
.Threading
;
54 object socketLock
= new object ();
55 WebExceptionStatus status
;
56 WaitCallback initConn
;
59 static AsyncCallback readDoneDelegate
= new AsyncCallback (ReadDone
);
60 EventHandler abortHandler
;
61 AbortHelper abortHelper
;
63 internal WebConnectionData Data
;
65 ChunkStream chunkStream
;
70 HttpWebRequest priority_request
;
71 NetworkCredential ntlm_credentials
;
72 bool ntlm_authenticated
;
79 Exception connect_exception
;
80 static object classLock
= new object ();
81 static Type sslStream
;
82 static PropertyInfo piClient
;
83 static PropertyInfo piServer
;
84 static PropertyInfo piTrustFailure
;
86 public WebConnection (WebConnectionGroup
group, ServicePoint sPoint
)
89 buffer
= new byte [4096];
90 readState
= ReadState
.None
;
91 Data
= new WebConnectionData ();
92 initConn
= new WaitCallback (InitConnection
);
94 abortHelper
= new AbortHelper ();
95 abortHelper
.Connection
= this;
96 abortHandler
= new EventHandler (abortHelper
.Abort
);
100 public WebConnection Connection
;
102 public void Abort (object sender
, EventArgs args
)
104 WebConnection other
= ((HttpWebRequest
) sender
).WebConnection
;
107 other
.Abort (sender
, args
);
113 // The real condition is !(socket.Poll (0, SelectMode.SelectRead) || socket.Available != 0)
114 // but if there's data pending to read (!) we won't reuse the socket.
115 return (socket
.Poll (0, SelectMode
.SelectRead
) == false);
118 void Connect (HttpWebRequest request
)
121 if (socket
!= null && socket
.Connected
&& status
== WebExceptionStatus
.Success
) {
122 // Take the chunked stream to the expected state (State.None)
123 if (CanReuse () && CompleteChunkedRead ()) {
130 if (socket
!= null) {
136 IPHostEntry hostEntry
= sPoint
.HostEntry
;
138 if (hostEntry
== null) {
139 status
= sPoint
.UsesProxy
? WebExceptionStatus
.ProxyNameResolutionFailure
:
140 WebExceptionStatus
.NameResolutionFailure
;
144 WebConnectionData data
= Data
;
145 foreach (IPAddress address
in hostEntry
.AddressList
) {
146 socket
= new Socket (address
.AddressFamily
, SocketType
.Stream
, ProtocolType
.Tcp
);
147 IPEndPoint remote
= new IPEndPoint (address
, sPoint
.Address
.Port
);
149 socket
.SetSocketOption (SocketOptionLevel
.Tcp
, SocketOptionName
.NoDelay
, sPoint
.UseNagleAlgorithm
? 0 : 1);
152 socket
.NoDelay
= !sPoint
.UseNagleAlgorithm
;
153 if (!sPoint
.CallEndPointDelegate (socket
, remote
)) {
156 status
= WebExceptionStatus
.ConnectFailure
;
162 socket
.Connect (remote
);
163 status
= WebExceptionStatus
.Success
;
165 } catch (ThreadAbortException
) {
166 // program exiting...
172 } catch (ObjectDisposedException exc
) {
173 // socket closed from another thread
175 } catch (Exception exc
) {
180 if (!request
.Aborted
)
181 status
= WebExceptionStatus
.ConnectFailure
;
182 connect_exception
= exc
;
191 static void EnsureSSLStreamAvailable ()
194 if (sslStream
!= null)
197 #if MONOTOUCH && SECURITY_DEP
198 sslStream
= typeof (Mono
.Security
.Protocol
.Tls
.HttpsClientStream
);
200 // HttpsClientStream is an internal glue class in Mono.Security.dll
201 sslStream
= Type
.GetType ("Mono.Security.Protocol.Tls.HttpsClientStream, " +
202 Consts
.AssemblyMono_Security
, false);
204 if (sslStream
== null) {
205 string msg
= "Missing Mono.Security.dll assembly. " +
206 "Support for SSL/TLS is unavailable.";
208 throw new NotSupportedException (msg
);
211 piClient
= sslStream
.GetProperty ("SelectedClientCertificate");
212 piServer
= sslStream
.GetProperty ("ServerCertificate");
213 piTrustFailure
= sslStream
.GetProperty ("TrustFailure");
217 bool CreateTunnel (HttpWebRequest request
, Stream stream
, out byte [] buffer
)
219 StringBuilder sb
= new StringBuilder ();
220 sb
.Append ("CONNECT ");
221 sb
.Append (request
.Address
.Host
);
223 sb
.Append (request
.Address
.Port
);
224 sb
.Append (" HTTP/");
225 if (request
.ServicePoint
.ProtocolVersion
== HttpVersion
.Version11
)
230 sb
.Append ("\r\nHost: ");
231 sb
.Append (request
.Address
.Authority
);
232 string challenge
= Data
.Challenge
;
233 Data
.Challenge
= null;
234 bool have_auth
= (request
.Headers
["Proxy-Authorization"] != null);
236 sb
.Append ("\r\nProxy-Authorization: ");
237 sb
.Append (request
.Headers
["Proxy-Authorization"]);
238 } else if (challenge
!= null && Data
.StatusCode
== 407) {
240 ICredentials creds
= request
.Proxy
.Credentials
;
241 Authorization auth
= AuthenticationManager
.Authenticate (challenge
, request
, creds
);
243 sb
.Append ("\r\nProxy-Authorization: ");
244 sb
.Append (auth
.Message
);
247 sb
.Append ("\r\n\r\n");
250 byte [] connectBytes
= Encoding
.Default
.GetBytes (sb
.ToString ());
251 stream
.Write (connectBytes
, 0, connectBytes
.Length
);
254 WebHeaderCollection result
= ReadHeaders (request
, stream
, out buffer
, out status
);
255 if (!have_auth
&& result
!= null && status
== 407) { // Needs proxy auth
256 Data
.StatusCode
= status
;
257 Data
.Challenge
= result
["Proxy-Authenticate"];
259 } else if (status
!= 200) {
260 string msg
= String
.Format ("The remote server returned a {0} status code.", status
);
261 HandleError (WebExceptionStatus
.SecureChannelFailure
, null, msg
);
265 return (result
!= null);
268 WebHeaderCollection
ReadHeaders (HttpWebRequest request
, Stream stream
, out byte [] retBuffer
, out int status
)
273 byte [] buffer
= new byte [1024];
274 MemoryStream ms
= new MemoryStream ();
275 bool gotStatus
= false;
276 WebHeaderCollection headers
= null;
279 int n
= stream
.Read (buffer
, 0, 1024);
281 HandleError (WebExceptionStatus
.ServerProtocolViolation
, null, "ReadHeaders");
285 ms
.Write (buffer
, 0, n
);
288 headers
= new WebHeaderCollection ();
289 while (ReadLine (ms
.GetBuffer (), ref start
, (int) ms
.Length
, ref str
)) {
291 if (ms
.Length
- start
> 0) {
292 retBuffer
= new byte [ms
.Length
- start
];
293 Buffer
.BlockCopy (ms
.GetBuffer (), start
, retBuffer
, 0, retBuffer
.Length
);
303 int spaceidx
= str
.IndexOf (' ');
304 if (spaceidx
== -1) {
305 HandleError (WebExceptionStatus
.ServerProtocolViolation
, null, "ReadHeaders2");
309 status
= (int) UInt32
.Parse (str
.Substring (spaceidx
+ 1, 3));
315 bool CreateStream (HttpWebRequest request
)
318 NetworkStream serverStream
= new NetworkStream (socket
, false);
320 if (request
.Address
.Scheme
== Uri
.UriSchemeHttps
) {
322 EnsureSSLStreamAvailable ();
323 if (!reused
|| nstream
== null || nstream
.GetType () != sslStream
) {
324 byte [] buffer
= null;
325 if (sPoint
.UseConnect
) {
326 bool ok
= CreateTunnel (request
, serverStream
, out buffer
);
331 object[] args
= new object [4] { serverStream
,
332 request
.ClientCertificates
,
334 nstream
= (Stream
) Activator
.CreateInstance (sslStream
, args
);
335 certsAvailable
= false;
337 // we also need to set ServicePoint.Certificate
338 // and ServicePoint.ClientCertificate but this can
339 // only be done later (after handshake - which is
340 // done only after a read operation).
343 nstream
= serverStream
;
345 } catch (Exception
) {
346 if (!request
.Aborted
)
347 status
= WebExceptionStatus
.ConnectFailure
;
354 void HandleError (WebExceptionStatus st
, Exception e
, string where
)
358 if (st
== WebExceptionStatus
.RequestCanceled
)
359 Data
= new WebConnectionData ();
362 if (e
== null) { // At least we now where it comes from
365 throw new Exception ();
367 throw new Exception (new System
.Diagnostics
.StackTrace ().ToString ());
369 } catch (Exception e2
) {
374 HttpWebRequest req
= null;
375 if (Data
!= null && Data
.request
!= null)
380 req
.FinishedReading
= true;
381 req
.SetResponseError (st
, e
, where
);
385 static void ReadDone (IAsyncResult result
)
387 WebConnection cnc
= (WebConnection
) result
.AsyncState
;
388 WebConnectionData data
= cnc
.Data
;
389 Stream ns
= cnc
.nstream
;
397 nread
= ns
.EndRead (result
);
398 } catch (Exception e
) {
399 cnc
.HandleError (WebExceptionStatus
.ReceiveFailure
, e
, "ReadDone1");
404 cnc
.HandleError (WebExceptionStatus
.ReceiveFailure
, null, "ReadDone2");
409 cnc
.HandleError (WebExceptionStatus
.ServerProtocolViolation
, null, "ReadDone3");
414 nread
+= cnc
.position
;
415 if (cnc
.readState
== ReadState
.None
) {
416 Exception exc
= null;
418 pos
= cnc
.GetResponse (cnc
.buffer
, nread
);
419 } catch (Exception e
) {
424 cnc
.HandleError (WebExceptionStatus
.ServerProtocolViolation
, exc
, "ReadDone4");
429 if (cnc
.readState
!= ReadState
.Content
) {
431 int max
= (est
< cnc
.buffer
.Length
) ? cnc
.buffer
.Length
: est
;
432 byte [] newBuffer
= new byte [max
];
433 Buffer
.BlockCopy (cnc
.buffer
, 0, newBuffer
, 0, nread
);
434 cnc
.buffer
= newBuffer
;
435 cnc
.position
= nread
;
436 cnc
.readState
= ReadState
.None
;
443 WebConnectionStream stream
= new WebConnectionStream (cnc
);
445 string contentType
= data
.Headers
["Transfer-Encoding"];
446 cnc
.chunkedRead
= (contentType
!= null && contentType
.ToLower ().IndexOf ("chunked") != -1);
447 if (!cnc
.chunkedRead
) {
448 stream
.ReadBuffer
= cnc
.buffer
;
449 stream
.ReadBufferOffset
= pos
;
450 stream
.ReadBufferSize
= nread
;
451 stream
.CheckResponseInBuffer ();
452 } else if (cnc
.chunkStream
== null) {
454 cnc
.chunkStream
= new ChunkStream (cnc
.buffer
, pos
, nread
, data
.Headers
);
455 } catch (Exception e
) {
456 cnc
.HandleError (WebExceptionStatus
.ServerProtocolViolation
, e
, "ReadDone5");
460 cnc
.chunkStream
.ResetBuffer ();
462 cnc
.chunkStream
.Write (cnc
.buffer
, pos
, nread
);
463 } catch (Exception e
) {
464 cnc
.HandleError (WebExceptionStatus
.ServerProtocolViolation
, e
, "ReadDone6");
469 data
.stream
= stream
;
471 if (!ExpectContent (data
.StatusCode
) || data
.request
.Method
== "HEAD")
472 stream
.ForceCompletion ();
474 data
.request
.SetResponseData (data
);
477 static bool ExpectContent (int statusCode
)
479 return (statusCode
>= 200 && statusCode
!= 204 && statusCode
!= 304);
482 internal void GetCertificates ()
484 // here the SSL negotiation have been done
485 X509Certificate client
= (X509Certificate
) piClient
.GetValue (nstream
, null);
486 X509Certificate server
= (X509Certificate
) piServer
.GetValue (nstream
, null);
487 sPoint
.SetCertificates (client
, server
);
488 certsAvailable
= (server
!= null);
491 internal static void InitRead (object state
)
493 WebConnection cnc
= (WebConnection
) state
;
494 Stream ns
= cnc
.nstream
;
497 int size
= cnc
.buffer
.Length
- cnc
.position
;
498 ns
.BeginRead (cnc
.buffer
, cnc
.position
, size
, readDoneDelegate
, cnc
);
499 } catch (Exception e
) {
500 cnc
.HandleError (WebExceptionStatus
.ReceiveFailure
, e
, "InitRead");
504 int GetResponse (byte [] buffer
, int max
)
509 bool isContinue
= false;
510 bool emptyFirstLine
= false;
512 if (readState
== ReadState
.None
) {
513 lineok
= ReadLine (buffer
, ref pos
, max
, ref line
);
518 emptyFirstLine
= true;
521 emptyFirstLine
= false;
523 readState
= ReadState
.Status
;
525 string [] parts
= line
.Split (' ');
526 if (parts
.Length
< 2)
529 if (String
.Compare (parts
[0], "HTTP/1.1", true) == 0) {
530 Data
.Version
= HttpVersion
.Version11
;
531 sPoint
.SetVersion (HttpVersion
.Version11
);
533 Data
.Version
= HttpVersion
.Version10
;
534 sPoint
.SetVersion (HttpVersion
.Version10
);
537 Data
.StatusCode
= (int) UInt32
.Parse (parts
[1]);
538 if (parts
.Length
>= 3)
539 Data
.StatusDescription
= String
.Join (" ", parts
, 2, parts
.Length
- 2);
541 Data
.StatusDescription
= "";
547 emptyFirstLine
= false;
548 if (readState
== ReadState
.Status
) {
549 readState
= ReadState
.Headers
;
550 Data
.Headers
= new WebHeaderCollection ();
551 ArrayList headers
= new ArrayList ();
552 bool finished
= false;
554 if (ReadLine (buffer
, ref pos
, max
, ref line
) == false)
558 // Empty line: end of headers
563 if (line
.Length
> 0 && (line
[0] == ' ' || line
[0] == '\t')) {
564 int count
= headers
.Count
- 1;
568 string prev
= (string) headers
[count
] + line
;
569 headers
[count
] = prev
;
578 foreach (string s
in headers
)
579 Data
.Headers
.SetInternal (s
);
581 if (Data
.StatusCode
== (int) HttpStatusCode
.Continue
) {
582 sPoint
.SendContinue
= true;
586 if (Data
.request
.ExpectContinue
) {
587 Data
.request
.DoContinueDelegate (Data
.StatusCode
, Data
.Headers
);
588 // Prevent double calls when getting the
589 // headers in several packets.
590 Data
.request
.ExpectContinue
= false;
593 readState
= ReadState
.None
;
597 readState
= ReadState
.Content
;
601 } while (emptyFirstLine
|| isContinue
);
606 void InitConnection (object state
)
608 HttpWebRequest request
= (HttpWebRequest
) state
;
609 request
.WebConnection
= this;
614 keepAlive
= request
.KeepAlive
;
615 Data
= new WebConnectionData ();
616 Data
.request
= request
;
622 if (status
!= WebExceptionStatus
.Success
) {
623 if (!request
.Aborted
) {
624 request
.SetWriteStreamError (status
, connect_exception
);
630 if (!CreateStream (request
)) {
634 WebExceptionStatus st
= status
;
635 if (Data
.Challenge
!= null)
638 Exception cnc_exc
= connect_exception
;
639 connect_exception
= null;
640 request
.SetWriteStreamError (st
, cnc_exc
);
645 readState
= ReadState
.None
;
646 request
.SetWriteStream (new WebConnectionStream (this, request
));
649 internal EventHandler
SendRequest (HttpWebRequest request
)
657 status
= WebExceptionStatus
.Success
;
658 ThreadPool
.QueueUserWorkItem (initConn
, request
);
661 queue
.Enqueue (request
);
672 if (queue
.Count
> 0) {
673 SendRequest ((HttpWebRequest
) queue
.Dequeue ());
678 internal void NextRead ()
681 Data
.request
.FinishedReading
= true;
682 string header
= (sPoint
.UsesProxy
) ? "Proxy-Connection" : "Connection";
683 string cncHeader
= (Data
.Headers
!= null) ? Data
.Headers
[header
] : null;
684 bool keepAlive
= (Data
.Version
== HttpVersion
.Version11
&& this.keepAlive
);
685 if (cncHeader
!= null) {
686 cncHeader
= cncHeader
.ToLower ();
687 keepAlive
= (this.keepAlive
&& cncHeader
.IndexOf ("keep-alive") != -1);
690 if ((socket
!= null && !socket
.Connected
) ||
691 (!keepAlive
|| (cncHeader
!= null && cncHeader
.IndexOf ("close") != -1))) {
696 if (priority_request
!= null) {
697 SendRequest (priority_request
);
698 priority_request
= null;
705 static bool ReadLine (byte [] buffer
, ref int start
, int max
, ref string output
)
707 bool foundCR
= false;
708 StringBuilder text
= new StringBuilder ();
711 while (start
< max
) {
712 c
= (int) buffer
[start
++];
714 if (c
== '\n') { // newline
715 if ((text
.Length
> 0) && (text
[text
.Length
- 1] == '\r'))
720 } else if (foundCR
) {
729 text
.Append ((char) c
);
732 if (c
!= '\n' && c
!= '\r')
735 if (text
.Length
== 0) {
737 return (c
== '\n' || c
== '\r');
743 output
= text
.ToString ();
748 internal IAsyncResult
BeginRead (HttpWebRequest request
, byte [] buffer
, int offset
, int size
, AsyncCallback cb
, object state
)
751 if (Data
.request
!= request
)
752 throw new ObjectDisposedException (typeof (NetworkStream
).FullName
);
757 IAsyncResult result
= null;
758 if (!chunkedRead
|| chunkStream
.WantMore
) {
760 result
= nstream
.BeginRead (buffer
, offset
, size
, cb
, state
);
762 } catch (Exception
) {
763 HandleError (WebExceptionStatus
.ReceiveFailure
, null, "chunked BeginRead");
769 WebAsyncResult wr
= new WebAsyncResult (cb
, state
, buffer
, offset
, size
);
770 wr
.InnerAsyncResult
= result
;
771 if (result
== null) {
772 // Will be completed from the data in ChunkStream
773 wr
.SetCompleted (true, (Exception
) null);
782 internal int EndRead (HttpWebRequest request
, IAsyncResult result
)
785 if (Data
.request
!= request
)
786 throw new ObjectDisposedException (typeof (NetworkStream
).FullName
);
788 throw new ObjectDisposedException (typeof (NetworkStream
).FullName
);
792 WebAsyncResult wr
= null;
793 IAsyncResult nsAsync
= ((WebAsyncResult
) result
).InnerAsyncResult
;
794 if (chunkedRead
&& (nsAsync
is WebAsyncResult
)) {
795 wr
= (WebAsyncResult
) nsAsync
;
796 IAsyncResult inner
= wr
.InnerAsyncResult
;
797 if (inner
!= null && !(inner
is WebAsyncResult
))
798 nbytes
= nstream
.EndRead (inner
);
799 } else if (!(nsAsync
is WebAsyncResult
)) {
800 nbytes
= nstream
.EndRead (nsAsync
);
801 wr
= (WebAsyncResult
) result
;
805 bool done
= (nbytes
== 0);
807 chunkStream
.WriteAndReadBack (wr
.Buffer
, wr
.Offset
, wr
.Size
, ref nbytes
);
808 if (!done
&& nbytes
== 0 && chunkStream
.WantMore
)
809 nbytes
= EnsureRead (wr
.Buffer
, wr
.Offset
, wr
.Size
);
810 } catch (Exception e
) {
811 if (e
is WebException
)
814 throw new WebException ("Invalid chunked data.", e
,
815 WebExceptionStatus
.ServerProtocolViolation
, null);
818 if ((done
|| nbytes
== 0) && chunkStream
.ChunkLeft
!= 0) {
819 HandleError (WebExceptionStatus
.ReceiveFailure
, null, "chunked EndRead");
820 throw new WebException ("Read error", null, WebExceptionStatus
.ReceiveFailure
, null);
824 return (nbytes
!= 0) ? nbytes
: -1;
827 // To be called on chunkedRead when we can read no data from the ChunkStream yet
828 int EnsureRead (byte [] buffer
, int offset
, int size
)
830 byte [] morebytes
= null;
832 while (nbytes
== 0 && chunkStream
.WantMore
) {
833 int localsize
= chunkStream
.ChunkLeft
;
834 if (localsize
<= 0) // not read chunk size yet
836 else if (localsize
> 16384)
839 if (morebytes
== null || morebytes
.Length
< localsize
)
840 morebytes
= new byte [localsize
];
842 int nread
= nstream
.Read (morebytes
, 0, localsize
);
846 chunkStream
.Write (morebytes
, 0, nread
);
847 nbytes
+= chunkStream
.Read (buffer
, offset
+ nbytes
, size
- nbytes
);
853 bool CompleteChunkedRead()
855 if (!chunkedRead
|| chunkStream
== null)
858 while (chunkStream
.WantMore
) {
859 int nbytes
= nstream
.Read (buffer
, 0, buffer
.Length
);
861 return false; // Socket was disconnected
863 chunkStream
.Write (buffer
, 0, nbytes
);
869 internal IAsyncResult
BeginWrite (HttpWebRequest request
, byte [] buffer
, int offset
, int size
, AsyncCallback cb
, object state
)
872 if (Data
.request
!= request
)
873 throw new ObjectDisposedException (typeof (NetworkStream
).FullName
);
878 IAsyncResult result
= null;
880 result
= nstream
.BeginWrite (buffer
, offset
, size
, cb
, state
);
881 } catch (Exception
) {
882 status
= WebExceptionStatus
.SendFailure
;
889 internal void EndWrite2 (HttpWebRequest request
, IAsyncResult result
)
891 if (request
.FinishedReading
)
895 if (Data
.request
!= request
)
896 throw new ObjectDisposedException (typeof (NetworkStream
).FullName
);
898 throw new ObjectDisposedException (typeof (NetworkStream
).FullName
);
902 nstream
.EndWrite (result
);
903 } catch (Exception exc
) {
904 status
= WebExceptionStatus
.SendFailure
;
905 if (exc
.InnerException
!= null)
906 throw exc
.InnerException
;
911 internal bool EndWrite (HttpWebRequest request
, IAsyncResult result
)
913 if (request
.FinishedReading
)
917 if (Data
.request
!= request
)
918 throw new ObjectDisposedException (typeof (NetworkStream
).FullName
);
920 throw new ObjectDisposedException (typeof (NetworkStream
).FullName
);
924 nstream
.EndWrite (result
);
927 status
= WebExceptionStatus
.SendFailure
;
932 internal int Read (HttpWebRequest request
, byte [] buffer
, int offset
, int size
)
935 if (Data
.request
!= request
)
936 throw new ObjectDisposedException (typeof (NetworkStream
).FullName
);
945 result
= nstream
.Read (buffer
, offset
, size
);
946 done
= (result
== 0);
951 chunkStream
.WriteAndReadBack (buffer
, offset
, size
, ref result
);
952 if (!done
&& result
== 0 && chunkStream
.WantMore
)
953 result
= EnsureRead (buffer
, offset
, size
);
954 } catch (Exception e
) {
955 HandleError (WebExceptionStatus
.ReceiveFailure
, e
, "chunked Read1");
959 if ((done
|| result
== 0) && chunkStream
.WantMore
) {
960 HandleError (WebExceptionStatus
.ReceiveFailure
, null, "chunked Read2");
961 throw new WebException ("Read error", null, WebExceptionStatus
.ReceiveFailure
, null);
964 } catch (Exception e
) {
965 HandleError (WebExceptionStatus
.ReceiveFailure
, e
, "Read");
971 internal bool Write (HttpWebRequest request
, byte [] buffer
, int offset
, int size
, ref string err_msg
)
975 if (Data
.request
!= request
)
976 throw new ObjectDisposedException (typeof (NetworkStream
).FullName
);
982 nstream
.Write (buffer
, offset
, size
);
983 // here SSL handshake should have been done
984 if (ssl
&& !certsAvailable
)
986 } catch (Exception e
) {
988 WebExceptionStatus wes
= WebExceptionStatus
.SendFailure
;
989 string msg
= "Write: " + err_msg
;
990 if (e
is WebException
) {
991 HandleError (wes
, e
, msg
);
995 // if SSL is in use then check for TrustFailure
996 if (ssl
&& (bool) piTrustFailure
.GetValue (nstream
, null)) {
997 wes
= WebExceptionStatus
.TrustFailure
;
998 msg
= "Trust failure";
1001 HandleError (wes
, e
, msg
);
1007 internal void Close (bool sendNext
)
1010 if (nstream
!= null) {
1017 if (socket
!= null) {
1025 Data
= new WebConnectionData ();
1031 void Abort (object sender
, EventArgs args
)
1035 HttpWebRequest req
= (HttpWebRequest
) sender
;
1036 if (Data
.request
== req
) {
1037 if (!req
.FinishedReading
) {
1038 status
= WebExceptionStatus
.RequestCanceled
;
1040 if (queue
.Count
> 0) {
1041 Data
.request
= (HttpWebRequest
) queue
.Dequeue ();
1042 SendRequest (Data
.request
);
1048 req
.FinishedReading
= true;
1049 req
.SetResponseError (WebExceptionStatus
.RequestCanceled
, null, "User aborted");
1050 if (queue
.Count
> 0 && queue
.Peek () == sender
) {
1052 } else if (queue
.Count
> 0) {
1053 object [] old
= queue
.ToArray ();
1055 for (int i
= old
.Length
- 1; i
>= 0; i
--) {
1056 if (old
[i
] != sender
)
1057 queue
.Enqueue (old
[i
]);
1064 internal void ResetNtlm ()
1066 ntlm_authenticated
= false;
1067 ntlm_credentials
= null;
1068 unsafe_sharing
= false;
1071 internal bool Busy
{
1072 get { lock (this) return busy; }
1075 internal bool Connected
{
1078 return (socket
!= null && socket
.Connected
);
1083 // -Used for NTLM authentication
1084 internal HttpWebRequest PriorityRequest
{
1085 set { priority_request = value; }
1088 internal bool NtlmAuthenticated
{
1089 get { return ntlm_authenticated; }
1090 set { ntlm_authenticated = value; }
1093 internal NetworkCredential NtlmCredential
{
1094 get { return ntlm_credentials; }
1095 set { ntlm_credentials = value; }
1099 internal bool UnsafeAuthenticatedConnectionSharing
{
1100 get { return unsafe_sharing; }
1101 set { unsafe_sharing = value; }