2 // System.Net.HttpWebRequest
5 // Lawrence Pit (loz@cable.a2000.nl)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (c) 2002 Lawrence Pit
9 // (c) 2003 Ximian, Inc. (http://www.ximian.com)
10 // (c) 2004 Novell, Inc. (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System
.Collections
;
36 using System
.Configuration
;
38 using System
.Net
.Sockets
;
39 using System
.Runtime
.Remoting
.Messaging
;
40 using System
.Runtime
.Serialization
;
41 using System
.Security
.Cryptography
.X509Certificates
;
43 using System
.Threading
;
48 public class HttpWebRequest
: WebRequest
, ISerializable
53 bool allowAutoRedirect
= true;
54 bool allowBuffering
= true;
55 X509CertificateCollection certificates
;
56 string connectionGroup
;
57 long contentLength
= -1;
58 HttpContinueDelegate continueDelegate
;
59 CookieContainer cookieContainer
;
60 ICredentials credentials
;
64 WebHeaderCollection webHeaders
= new WebHeaderCollection (true);
65 bool keepAlive
= true;
66 int maxAutoRedirect
= 50;
67 string mediaType
= String
.Empty
;
68 string method
= "GET";
69 string initialMethod
= "GET";
70 bool pipelined
= true;
73 Version version
= HttpVersion
.Version11
;
74 Version actualVersion
;
77 ServicePoint servicePoint
;
80 WebConnectionStream writeStream
;
81 HttpWebResponse webResponse
;
82 WebAsyncResult asyncWrite
;
83 WebAsyncResult asyncRead
;
84 EventHandler abortHandler
;
86 bool gotRequestStream
;
93 int maxResponseHeadersLength
;
94 static int defaultMaxResponseHeadersLength
;
98 static HttpWebRequest ()
100 NetConfig config
= ConfigurationSettings
.GetConfig ("system.net/settings") as NetConfig
;
101 defaultMaxResponseHeadersLength
= 64 * 1024;
102 if (config
!= null) {
103 int x
= config
.MaxResponseHeadersLength
;
107 defaultMaxResponseHeadersLength
= x
;
112 internal HttpWebRequest (Uri uri
)
114 this.requestUri
= uri
;
115 this.actualUri
= uri
;
116 this.proxy
= GlobalProxySelection
.Select
;
119 protected HttpWebRequest (SerializationInfo serializationInfo
, StreamingContext streamingContext
)
121 SerializationInfo info
= serializationInfo
;
123 requestUri
= (Uri
) info
.GetValue ("requestUri", typeof (Uri
));
124 actualUri
= (Uri
) info
.GetValue ("actualUri", typeof (Uri
));
125 allowAutoRedirect
= info
.GetBoolean ("allowAutoRedirect");
126 allowBuffering
= info
.GetBoolean ("allowBuffering");
127 certificates
= (X509CertificateCollection
) info
.GetValue ("certificates", typeof (X509CertificateCollection
));
128 connectionGroup
= info
.GetString ("connectionGroup");
129 contentLength
= info
.GetInt64 ("contentLength");
130 webHeaders
= (WebHeaderCollection
) info
.GetValue ("webHeaders", typeof (WebHeaderCollection
));
131 keepAlive
= info
.GetBoolean ("keepAlive");
132 maxAutoRedirect
= info
.GetInt32 ("maxAutoRedirect");
133 mediaType
= info
.GetString ("mediaType");
134 method
= info
.GetString ("method");
135 initialMethod
= info
.GetString ("initialMethod");
136 pipelined
= info
.GetBoolean ("pipelined");
137 version
= (Version
) info
.GetValue ("version", typeof (Version
));
138 proxy
= (IWebProxy
) info
.GetValue ("proxy", typeof (IWebProxy
));
139 sendChunked
= info
.GetBoolean ("sendChunked");
140 timeout
= info
.GetInt32 ("timeout");
141 redirects
= info
.GetInt32 ("redirects");
146 public string Accept
{
147 get { return webHeaders ["Accept"]; }
149 CheckRequestStarted ();
150 webHeaders
.RemoveAndAdd ("Accept", value);
155 get { return actualUri; }
158 public bool AllowAutoRedirect
{
159 get { return allowAutoRedirect; }
160 set { this.allowAutoRedirect = value; }
163 public bool AllowWriteStreamBuffering
{
164 get { return allowBuffering; }
165 set { allowBuffering = value; }
168 internal bool InternalAllowBuffering
{
170 return (allowBuffering
&& (method
== "PUT" || method
== "POST"));
174 public X509CertificateCollection ClientCertificates
{
176 if (certificates
== null)
177 certificates
= new X509CertificateCollection ();
183 public string Connection
{
184 get { return webHeaders ["Connection"]; }
186 CheckRequestStarted ();
189 val
= val
.Trim ().ToLower ();
191 if (val
== null || val
.Length
== 0) {
192 webHeaders
.RemoveInternal ("Connection");
196 if (val
== "keep-alive" || val
== "close")
197 throw new ArgumentException ("Keep-Alive and Close may not be set with this property");
199 if (keepAlive
&& val
.IndexOf ("keep-alive") == -1)
200 value = value + ", Keep-Alive";
202 webHeaders
.RemoveAndAdd ("Connection", value);
206 public override string ConnectionGroupName
{
207 get { return connectionGroup; }
208 set { connectionGroup = value; }
211 public override long ContentLength
{
212 get { return contentLength; }
214 CheckRequestStarted ();
216 throw new ArgumentOutOfRangeException ("value", "Content-Length must be >= 0");
218 contentLength
= value;
222 internal long InternalContentLength
{
223 set { contentLength = value; }
226 public override string ContentType
{
227 get { return webHeaders ["Content-Type"]; }
229 if (value == null || value.Trim().Length
== 0) {
230 webHeaders
.RemoveInternal ("Content-Type");
233 webHeaders
.RemoveAndAdd ("Content-Type", value);
237 public HttpContinueDelegate ContinueDelegate
{
238 get { return continueDelegate; }
239 set { continueDelegate = value; }
242 public CookieContainer CookieContainer
{
243 get { return cookieContainer; }
244 set { cookieContainer = value; }
247 public override ICredentials Credentials
{
248 get { return credentials; }
249 set { credentials = value; }
252 public string Expect
{
253 get { return webHeaders ["Expect"]; }
255 CheckRequestStarted ();
258 val
= val
.Trim ().ToLower ();
260 if (val
== null || val
.Length
== 0) {
261 webHeaders
.RemoveInternal ("Expect");
265 if (val
== "100-continue")
266 throw new ArgumentException ("100-Continue cannot be set with this property.",
268 webHeaders
.RemoveAndAdd ("Expect", value);
272 public bool HaveResponse
{
273 get { return haveResponse; }
276 public override WebHeaderCollection Headers
{
277 get { return webHeaders; }
279 CheckRequestStarted ();
280 WebHeaderCollection newHeaders
= new WebHeaderCollection (true);
281 int count
= value.Count
;
282 for (int i
= 0; i
< count
; i
++)
283 newHeaders
.Add (value.GetKey (i
), value.Get (i
));
285 webHeaders
= newHeaders
;
289 public DateTime IfModifiedSince
{
291 string str
= webHeaders
["If-Modified-Since"];
295 return MonoHttpDate
.Parse (str
);
296 } catch (Exception
) {
301 CheckRequestStarted ();
303 webHeaders
.SetInternal ("If-Modified-Since",
304 value.ToUniversalTime ().ToString ("r", null));
305 // TODO: check last param when using different locale
309 public bool KeepAlive
{
318 public int MaximumAutomaticRedirections
{
319 get { return maxAutoRedirect; }
322 throw new ArgumentException ("Must be > 0", "value");
324 maxAutoRedirect
= value;
329 [MonoTODO ("Use this")]
330 public int MaximumResponseHeadersLength
{
331 get { return maxResponseHeadersLength; }
332 set { maxResponseHeadersLength = value; }
335 [MonoTODO ("Use this")]
336 public static int DefaultMaximumResponseHeadersLength
{
337 get { return defaultMaxResponseHeadersLength; }
338 set { defaultMaxResponseHeadersLength = value; }
341 [MonoTODO ("Use this")]
342 public int ReadWriteTimeout
{
343 get { return readWriteTimeout; }
344 set { readWriteTimeout = value; }
348 public string MediaType
{
349 get { return mediaType; }
355 public override string Method
{
356 get { return this.method; }
358 if (value == null || value.Trim () == "")
359 throw new ArgumentException ("not a valid method");
365 public bool Pipelined
{
366 get { return pipelined; }
367 set { pipelined = value; }
370 public override bool PreAuthenticate
{
371 get { return preAuthenticate; }
372 set { preAuthenticate = value; }
375 public Version ProtocolVersion
{
376 get { return version; }
378 if (value != HttpVersion
.Version10
&& value != HttpVersion
.Version11
)
379 throw new ArgumentException ("value");
385 public override IWebProxy Proxy
{
386 get { return proxy; }
388 CheckRequestStarted ();
390 throw new ArgumentNullException ("value");
393 servicePoint
= null; // we may need a new one
397 public string Referer
{
398 get { return webHeaders ["Referer"]; }
400 CheckRequestStarted ();
401 if (value == null || value.Trim().Length
== 0) {
402 webHeaders
.RemoveInternal ("Referer");
405 webHeaders
.SetInternal ("Referer", value);
409 public override Uri RequestUri
{
410 get { return requestUri; }
413 public bool SendChunked
{
414 get { return sendChunked; }
416 CheckRequestStarted ();
421 public ServicePoint ServicePoint
{
422 get { return GetServicePoint (); }
425 public override int Timeout
{
426 get { return timeout; }
429 throw new ArgumentOutOfRangeException ("value");
435 public string TransferEncoding
{
436 get { return webHeaders ["Transfer-Encoding"]; }
438 CheckRequestStarted ();
441 val
= val
.Trim ().ToLower ();
443 if (val
== null || val
.Length
== 0) {
444 webHeaders
.RemoveInternal ("Transfer-Encoding");
448 if (val
== "chunked")
449 throw new ArgumentException ("Chunked encoding must be set with the SendChunked property");
452 throw new ArgumentException ("SendChunked must be True", "value");
454 webHeaders
.RemoveAndAdd ("Transfer-Encoding", value);
458 public string UserAgent
{
459 get { return webHeaders ["User-Agent"]; }
460 set { webHeaders.SetInternal ("User-Agent", value); }
465 public bool UnsafeAuthenticatedConnectionSharing
467 get { throw new NotImplementedException (); }
468 set { throw new NotImplementedException (); }
472 internal bool GotRequestStream
{
473 get { return gotRequestStream; }
476 internal bool ExpectContinue
{
477 get { return expectContinue; }
478 set { expectContinue = value; }
481 internal Uri AuthUri
{
482 get { return actualUri; }
485 internal bool ProxyQuery
{
486 get { return servicePoint.UsesProxy && !servicePoint.UseConnect; }
491 internal ServicePoint
GetServicePoint ()
493 if (!hostChanged
&& servicePoint
!= null)
497 if (hostChanged
|| servicePoint
== null) {
498 servicePoint
= ServicePointManager
.FindServicePoint (actualUri
, proxy
);
506 public void AddRange (int range
)
508 AddRange ("bytes", range
);
511 public void AddRange (int from, int to
)
513 AddRange ("bytes", from, to
);
516 public void AddRange (string rangeSpecifier
, int range
)
518 if (rangeSpecifier
== null)
519 throw new ArgumentNullException ("rangeSpecifier");
520 string value = webHeaders
["Range"];
521 if (value == null || value.Length
== 0)
522 value = rangeSpecifier
+ "=";
523 else if (value.ToLower ().StartsWith (rangeSpecifier
.ToLower () + "="))
526 throw new InvalidOperationException ("rangeSpecifier");
527 webHeaders
.RemoveAndAdd ("Range", value + range
+ "-");
530 public void AddRange (string rangeSpecifier
, int from, int to
)
532 if (rangeSpecifier
== null)
533 throw new ArgumentNullException ("rangeSpecifier");
534 if (from < 0 || to
< 0 || from > to
)
535 throw new ArgumentOutOfRangeException ();
536 string value = webHeaders
["Range"];
537 if (value == null || value.Length
== 0)
538 value = rangeSpecifier
+ "=";
539 else if (value.ToLower ().StartsWith (rangeSpecifier
.ToLower () + "="))
542 throw new InvalidOperationException ("rangeSpecifier");
543 webHeaders
.RemoveAndAdd ("Range", value + from + "-" + to
);
546 public override int GetHashCode ()
548 return base.GetHashCode ();
551 void CommonChecks (bool putpost
)
554 throw new ProtocolViolationException ("Method is null.");
556 if (putpost
&& ((!keepAlive
|| (contentLength
== -1 && !sendChunked
)) && !allowBuffering
))
557 throw new ProtocolViolationException ("Content-Length not set");
559 string transferEncoding
= TransferEncoding
;
560 if (!sendChunked
&& transferEncoding
!= null && transferEncoding
.Trim () != "")
561 throw new ProtocolViolationException ("SendChunked should be true.");
564 public override IAsyncResult
BeginGetRequestStream (AsyncCallback callback
, object state
)
567 throw new WebException ("The request was previosly aborted.");
569 bool send
= !(method
== "GET" || method
== "CONNECT" || method
== "HEAD");
570 if (method
== null || !send
)
571 throw new ProtocolViolationException ("Cannot send data when method is: " + method
);
577 if (asyncWrite
!= null) {
578 throw new InvalidOperationException ("Cannot re-call start of asynchronous " +
579 "method while a previous call is still in progress.");
582 asyncWrite
= new WebAsyncResult (this, callback
, state
);
583 initialMethod
= method
;
585 if (writeStream
!= null) {
586 asyncWrite
.SetCompleted (true, writeStream
);
587 asyncWrite
.DoCallback ();
592 gotRequestStream
= true;
593 WebAsyncResult result
= asyncWrite
;
596 servicePoint
= GetServicePoint ();
597 abortHandler
= servicePoint
.SendRequest (this, connectionGroup
);
603 public override Stream
EndGetRequestStream (IAsyncResult asyncResult
)
605 if (asyncResult
== null)
606 throw new ArgumentNullException ("asyncResult");
608 WebAsyncResult result
= asyncResult
as WebAsyncResult
;
610 throw new ArgumentException ("Invalid IAsyncResult");
613 result
.WaitUntilComplete ();
615 Exception e
= result
.Exception
;
619 return result
.WriteStream
;
622 public override Stream
GetRequestStream()
624 IAsyncResult asyncResult
= BeginGetRequestStream (null, null);
625 asyncWrite
= (WebAsyncResult
) asyncResult
;
626 if (!asyncResult
.AsyncWaitHandle
.WaitOne (timeout
, false)) {
628 throw new WebException ("The request timed out", WebExceptionStatus
.Timeout
);
631 return EndGetRequestStream (asyncResult
);
634 public override IAsyncResult
BeginGetResponse (AsyncCallback callback
, object state
)
636 bool send
= (method
== "PUT" || method
== "POST");
638 if ((!KeepAlive
|| (ContentLength
== -1 && !SendChunked
)) && !AllowWriteStreamBuffering
)
639 throw new ProtocolViolationException ("Content-Length not set");
643 Monitor
.Enter (this);
644 if (asyncRead
!= null && !haveResponse
) {
646 throw new InvalidOperationException ("Cannot re-call start of asynchronous " +
647 "method while a previous call is still in progress.");
650 asyncRead
= new WebAsyncResult (this, callback
, state
);
651 initialMethod
= method
;
653 if (webResponse
!= null) {
655 asyncRead
.SetCompleted (true, webResponse
);
656 asyncRead
.DoCallback ();
663 servicePoint
= GetServicePoint ();
664 abortHandler
= servicePoint
.SendRequest (this, connectionGroup
);
671 public override WebResponse
EndGetResponse (IAsyncResult asyncResult
)
673 if (asyncResult
== null)
674 throw new ArgumentNullException ("asyncResult");
676 WebAsyncResult result
= asyncResult
as WebAsyncResult
;
678 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
681 bool redirected
= false;
685 haveResponse
= false;
687 servicePoint
= GetServicePoint ();
688 abortHandler
= servicePoint
.SendRequest (this, connectionGroup
);
691 if (!result
.WaitUntilComplete (timeout
, false)) {
693 throw new WebException("The request timed out", WebExceptionStatus
.Timeout
);
696 redirected
= CheckFinalStatus (result
);
697 } while (redirected
);
699 return result
.Response
;
702 public override WebResponse
GetResponse()
704 if (haveResponse
&& webResponse
!= null)
707 WebAsyncResult result
= (WebAsyncResult
) BeginGetResponse (null, null);
708 return EndGetResponse (result
);
711 public override void Abort ()
715 if (asyncWrite
!= null) {
716 WebAsyncResult r
= asyncWrite
;
717 WebException wexc
= new WebException ("Aborted.", WebExceptionStatus
.RequestCanceled
);
718 r
.SetCompleted (false, wexc
);
723 if (asyncRead
!= null) {
724 WebAsyncResult r
= asyncRead
;
725 WebException wexc
= new WebException ("Aborted.", WebExceptionStatus
.RequestCanceled
);
726 r
.SetCompleted (false, wexc
);
731 if (abortHandler
!= null) {
733 abortHandler (this, EventArgs
.Empty
);
738 if (writeStream
!= null) {
740 writeStream
.Close ();
745 if (webResponse
!= null) {
747 webResponse
.Close ();
753 void ISerializable
.GetObjectData (SerializationInfo serializationInfo
,
754 StreamingContext streamingContext
)
756 SerializationInfo info
= serializationInfo
;
758 info
.AddValue ("requestUri", requestUri
, typeof (Uri
));
759 info
.AddValue ("actualUri", actualUri
, typeof (Uri
));
760 info
.AddValue ("allowAutoRedirect", allowAutoRedirect
);
761 info
.AddValue ("allowBuffering", allowBuffering
);
762 info
.AddValue ("certificates", certificates
, typeof (X509CertificateCollection
));
763 info
.AddValue ("connectionGroup", connectionGroup
);
764 info
.AddValue ("contentLength", contentLength
);
765 info
.AddValue ("webHeaders", webHeaders
, typeof (WebHeaderCollection
));
766 info
.AddValue ("keepAlive", keepAlive
);
767 info
.AddValue ("maxAutoRedirect", maxAutoRedirect
);
768 info
.AddValue ("mediaType", mediaType
);
769 info
.AddValue ("method", method
);
770 info
.AddValue ("initialMethod", initialMethod
);
771 info
.AddValue ("pipelined", pipelined
);
772 info
.AddValue ("version", version
, typeof (Version
));
773 info
.AddValue ("proxy", proxy
, typeof (IWebProxy
));
774 info
.AddValue ("sendChunked", sendChunked
);
775 info
.AddValue ("timeout", timeout
);
776 info
.AddValue ("redirects", redirects
);
779 void CheckRequestStarted ()
782 throw new InvalidOperationException ("request started");
785 internal void DoContinueDelegate (int statusCode
, WebHeaderCollection headers
)
787 if (continueDelegate
!= null)
788 continueDelegate (statusCode
, headers
);
791 bool Redirect (WebAsyncResult result
, HttpStatusCode code
)
795 string uriString
= null;
798 case HttpStatusCode
.Ambiguous
: // 300
799 e
= new WebException ("Ambiguous redirect.");
801 case HttpStatusCode
.MovedPermanently
: // 301
802 case HttpStatusCode
.Redirect
: // 302
803 case HttpStatusCode
.TemporaryRedirect
: // 307
804 if (method
!= "GET" && method
!= "HEAD") // 10.3
807 uriString
= webResponse
.Headers
["Location"];
809 case HttpStatusCode
.SeeOther
: //303
811 uriString
= webResponse
.Headers
["Location"];
813 case HttpStatusCode
.NotModified
: // 304
815 case HttpStatusCode
.UseProxy
: // 305
816 e
= new NotImplementedException ("Proxy support not available.");
818 case HttpStatusCode
.Unused
: // 306
820 e
= new ProtocolViolationException ("Invalid status code: " + (int) code
);
827 if (uriString
== null)
828 throw new WebException ("No Location header found for " + (int) code
,
829 WebExceptionStatus
.ProtocolError
);
831 Uri prev
= actualUri
;
833 actualUri
= new Uri (actualUri
, uriString
);
834 } catch (Exception
) {
835 throw new WebException (String
.Format ("Invalid URL ({0}) for {1}",
836 uriString
, (int) code
),
837 WebExceptionStatus
.ProtocolError
);
840 hostChanged
= (actualUri
.Scheme
!= prev
.Scheme
|| actualUri
.Host
!= prev
.Host
||
841 actualUri
.Port
!= prev
.Port
);
847 bool continue100
= false;
848 if (gotRequestStream
&& contentLength
!= -1) {
850 webHeaders
.SetInternal ("Content-Length", contentLength
.ToString ());
851 webHeaders
.RemoveInternal ("Transfer-Encoding");
852 } else if (sendChunked
) {
854 webHeaders
.RemoveAndAdd ("Transfer-Encoding", "chunked");
855 webHeaders
.RemoveInternal ("Content-Length");
858 if (actualVersion
== HttpVersion
.Version11
&& continue100
&&
859 servicePoint
.SendContinue
) { // RFC2616 8.2.3
860 webHeaders
.RemoveAndAdd ("Expect" , "100-continue");
861 expectContinue
= true;
863 webHeaders
.RemoveInternal ("Expect");
864 expectContinue
= false;
867 string connectionHeader
= (ProxyQuery
) ? "Proxy-Connection" : "Connection";
868 webHeaders
.RemoveInternal ((!ProxyQuery
) ? "Proxy-Connection" : "Connection");
869 bool spoint10
= (servicePoint
.ProtocolVersion
== null ||
870 servicePoint
.ProtocolVersion
== HttpVersion
.Version10
);
872 if (keepAlive
&& (version
== HttpVersion
.Version10
|| spoint10
)) {
873 webHeaders
.RemoveAndAdd (connectionHeader
, "keep-alive");
874 } else if (!keepAlive
&& version
== HttpVersion
.Version11
) {
875 webHeaders
.RemoveAndAdd (connectionHeader
, "close");
878 webHeaders
.SetInternal ("Host", actualUri
.Authority
);
879 if (cookieContainer
!= null) {
880 string cookieHeader
= cookieContainer
.GetCookieHeader (requestUri
);
881 if (cookieHeader
!= "")
882 webHeaders
.SetInternal ("Cookie", cookieHeader
);
885 if (!usedPreAuth
&& preAuthenticate
)
886 DoPreAuthenticate ();
888 return webHeaders
.ToString ();
891 void DoPreAuthenticate ()
893 webHeaders
.RemoveInternal ("Proxy-Authorization");
894 webHeaders
.RemoveInternal ("Authorization");
895 bool isProxy
= (proxy
!= null && !proxy
.IsBypassed (actualUri
));
896 ICredentials creds
= (!isProxy
) ? credentials
: proxy
.Credentials
;
897 Authorization auth
= AuthenticationManager
.PreAuthenticate (this, creds
);
901 string authHeader
= (isProxy
) ? "Proxy-Authorization" : "Authorization";
902 webHeaders
[authHeader
] = auth
.Message
;
906 internal void SetWriteStreamError (WebExceptionStatus status
)
911 WebAsyncResult r
= asyncWrite
;
916 r
.SetCompleted (false, new WebException ("Error: " + status
, status
));
921 internal void SendRequestHeaders ()
923 StringBuilder req
= new StringBuilder ();
926 query
= actualUri
.PathAndQuery
;
927 } else if (actualUri
.IsDefaultPort
) {
928 query
= String
.Format ("{0}://{1}{2}", actualUri
.Scheme
,
930 actualUri
.PathAndQuery
);
932 query
= String
.Format ("{0}://{1}:{2}{3}", actualUri
.Scheme
,
935 actualUri
.PathAndQuery
);
938 if (servicePoint
.ProtocolVersion
!= null && servicePoint
.ProtocolVersion
< version
) {
939 actualVersion
= servicePoint
.ProtocolVersion
;
941 actualVersion
= version
;
944 req
.AppendFormat ("{0} {1} HTTP/{2}.{3}\r\n", method
, query
,
945 actualVersion
.Major
, actualVersion
.Minor
);
946 req
.Append (GetHeaders ());
947 string reqstr
= req
.ToString ();
948 byte [] bytes
= Encoding
.UTF8
.GetBytes (reqstr
);
949 writeStream
.SetHeaders (bytes
, 0, bytes
.Length
);
952 internal void SetWriteStream (WebConnectionStream stream
)
957 writeStream
= stream
;
958 if (bodyBuffer
!= null) {
959 webHeaders
.RemoveInternal ("Transfer-Encoding");
960 contentLength
= bodyBufferLength
;
961 writeStream
.SendChunked
= false;
964 SendRequestHeaders ();
968 if (bodyBuffer
!= null) {
969 // The body has been written and buffered. The request "user"
970 // won't write it again, so we must do it.
971 writeStream
.Write (bodyBuffer
, 0, bodyBufferLength
);
973 writeStream
.Close ();
976 if (asyncWrite
!= null) {
977 asyncWrite
.SetCompleted (false, stream
);
978 asyncWrite
.DoCallback ();
983 internal void SetResponseError (WebExceptionStatus status
, Exception e
, string where
)
985 WebAsyncResult r
= asyncRead
;
990 string msg
= String
.Format ("Error getting response stream ({0}): {1}", where
, status
);
991 WebException wexc
= new WebException (msg
, e
, status
, null);
992 r
.SetCompleted (false, wexc
);
999 internal void SetResponseData (WebConnectionData data
)
1002 if (data
.stream
!= null)
1003 data
.stream
.Close ();
1007 webResponse
= new HttpWebResponse (actualUri
, method
, data
, (cookieContainer
!= null));
1008 haveResponse
= true;
1010 WebAsyncResult r
= asyncRead
;
1012 r
.SetCompleted (false, webResponse
);
1017 bool CheckAuthorization (WebResponse response
, HttpStatusCode code
)
1019 authCompleted
= false;
1020 if (code
== HttpStatusCode
.Unauthorized
&& credentials
== null)
1023 bool isProxy
= (code
== HttpStatusCode
.ProxyAuthenticationRequired
);
1024 if (isProxy
&& (proxy
== null || proxy
.Credentials
== null))
1027 string authHeader
= response
.Headers
[(isProxy
) ? "Proxy-Authenticate" : "WWW-Authenticate"];
1028 if (authHeader
== null)
1031 ICredentials creds
= (!isProxy
) ? credentials
: proxy
.Credentials
;
1032 Authorization auth
= AuthenticationManager
.Authenticate (authHeader
, this, creds
);
1036 webHeaders
[(isProxy
) ? "Proxy-Authorization" : "Authorization"] = auth
.Message
;
1037 authCompleted
= auth
.Complete
;
1041 // Returns true if redirected
1042 bool CheckFinalStatus (WebAsyncResult result
)
1044 if (result
.GotException
)
1045 throw result
.Exception
;
1047 Exception throwMe
= result
.Exception
;
1050 HttpWebResponse resp
= result
.Response
;
1051 WebExceptionStatus protoError
= WebExceptionStatus
.ProtocolError
;
1052 HttpStatusCode code
= 0;
1053 if (throwMe
== null && webResponse
!= null) {
1054 code
= webResponse
.StatusCode
;
1055 if (!authCompleted
&& ((code
== HttpStatusCode
.Unauthorized
&& credentials
!= null) ||
1056 code
== HttpStatusCode
.ProxyAuthenticationRequired
)) {
1057 if (!usedPreAuth
&& CheckAuthorization (webResponse
, code
)) {
1058 // Keep the written body, so it can be rewritten in the retry
1059 if (InternalAllowBuffering
) {
1060 bodyBuffer
= writeStream
.WriteBuffer
;
1061 bodyBufferLength
= writeStream
.WriteBufferLength
;
1063 } else if (method
!= "PUT" && method
!= "POST") {
1067 writeStream
.InternalClose ();
1070 throw new WebException ("This request requires buffering " +
1071 "of data for authentication or " +
1072 "redirection to be sucessful.");
1076 if ((int) code
>= 400) {
1077 string err
= String
.Format ("The remote server returned an error: ({0}) {1}.",
1078 (int) code
, webResponse
.StatusDescription
);
1079 throwMe
= new WebException (err
, null, protoError
, webResponse
);
1080 } else if ((int) code
== 304 && allowAutoRedirect
) {
1081 string err
= String
.Format ("The remote server returned an error: ({0}) {1}.",
1082 (int) code
, webResponse
.StatusDescription
);
1083 throwMe
= new WebException (err
, null, protoError
, webResponse
);
1084 } else if ((int) code
>= 300 && allowAutoRedirect
&& redirects
> maxAutoRedirect
) {
1085 throwMe
= new WebException ("Max. redirections exceeded.", null,
1086 protoError
, webResponse
);
1090 if (throwMe
== null) {
1092 if (allowAutoRedirect
&& (int) code
>= 300)
1093 b
= Redirect (result
, code
);
1098 if (writeStream
!= null) {
1099 writeStream
.InternalClose ();
1103 if (webResponse
!= null)