X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem%2FSystem.Net%2FHttpWebRequest.cs;h=a151f6bb870e2ed992fa5b5639864d82835979ec;hb=a2147aa78a8ec78353b88e52a73c6551051ce5e3;hp=04baad213dd3ed3f3df9b70d5008dcd06095c6fc;hpb=136f17a02462595d189fecebf458bf74c372458d;p=mono.git diff --git a/mcs/class/System/System.Net/HttpWebRequest.cs b/mcs/class/System/System.Net/HttpWebRequest.cs index 04baad213dd..a151f6bb870 100644 --- a/mcs/class/System/System.Net/HttpWebRequest.cs +++ b/mcs/class/System/System.Net/HttpWebRequest.cs @@ -31,6 +31,15 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +#if SECURITY_DEP +#if MONO_SECURITY_ALIAS +extern alias MonoSecurity; +using MonoSecurity::Mono.Security.Interface; +#else +using Mono.Security.Interface; +#endif +#endif + using System; using System.Collections; using System.Configuration; @@ -39,11 +48,13 @@ using System.IO; using System.Net; using System.Net.Cache; using System.Net.Sockets; +using System.Net.Security; using System.Runtime.Remoting.Messaging; using System.Runtime.Serialization; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; +using Mono.Net.Security; namespace System.Net { @@ -101,6 +112,11 @@ namespace System.Net int maxResponseHeadersLength; static int defaultMaxResponseHeadersLength; int readWriteTimeout = 300000; // ms + IMonoTlsProvider tlsProvider; +#if SECURITY_DEP + MonoTlsSettings tlsSettings; +#endif + ServerCertValidationCallback certValidationCallback; enum NtlmAuthState { None, @@ -110,6 +126,9 @@ namespace System.Net AuthorizationState auth_state, proxy_auth_state; string host; + [NonSerialized] + internal Action ResendContentFactory; + // Constructors static HttpWebRequest () { @@ -135,11 +154,20 @@ namespace System.Net { this.requestUri = uri; this.actualUri = uri; - this.proxy = GlobalProxySelection.Select; - this.webHeaders = new WebHeaderCollection (WebHeaderCollection.HeaderInfo.Request); + this.proxy = InternalDefaultWebProxy; + this.webHeaders = new WebHeaderCollection (WebHeaderCollectionType.HttpWebRequest); ThrowOnError = true; ResetAuthorization (); } + +#if SECURITY_DEP + internal HttpWebRequest (Uri uri, IMonoTlsProvider tlsProvider, MonoTlsSettings settings = null) + : this (uri) + { + this.tlsProvider = tlsProvider; + this.tlsSettings = settings; + } +#endif [Obsolete ("Serialization is obsoleted for this type", false)] protected HttpWebRequest (SerializationInfo serializationInfo, StreamingContext streamingContext) @@ -177,11 +205,19 @@ namespace System.Net // Properties + void SetSpecialHeaders(string HeaderName, string value) { + value = WebHeaderCollection.CheckBadChars(value, true); + webHeaders.RemoveInternal(HeaderName); + if (value.Length != 0) { + webHeaders.AddInternal(HeaderName, value); + } + } + public string Accept { get { return webHeaders ["Accept"]; } set { CheckRequestStarted (); - webHeaders.RemoveAndAdd ("Accept", value); + SetSpecialHeaders ("Accept", value); } } @@ -226,25 +262,41 @@ namespace System.Net internal bool InternalAllowBuffering { get { - return (allowBuffering && (method != "HEAD" && method != "GET" && - method != "MKCOL" && method != "CONNECT" && - method != "TRACE")); + return allowBuffering && MethodWithBuffer; } } + + bool MethodWithBuffer { + get { + return method != "HEAD" && method != "GET" && + method != "MKCOL" && method != "CONNECT" && + method != "TRACE"; + } + } + + internal IMonoTlsProvider TlsProvider { + get { return tlsProvider; } + } + +#if SECURITY_DEP + internal MonoTlsSettings TlsSettings { + get { return tlsSettings; } + } +#endif public X509CertificateCollection ClientCertificates { get { if (certificates == null) certificates = new X509CertificateCollection (); - return certificates; } - [MonoTODO] set { - throw GetMustImplement (); + if (value == null) + throw new ArgumentNullException ("value"); + certificates = value; } } - + public string Connection { get { return webHeaders ["Connection"]; } set { @@ -262,7 +314,7 @@ namespace System.Net if (keepAlive) value = value + ", Keep-Alive"; - webHeaders.RemoveAndAdd ("Connection", value); + webHeaders.CheckUpdate ("Connection", value); } } @@ -292,11 +344,7 @@ namespace System.Net public override string ContentType { get { return webHeaders ["Content-Type"]; } set { - if (value == null || value.Trim().Length == 0) { - webHeaders.RemoveInternal ("Content-Type"); - return; - } - webHeaders.RemoveAndAdd ("Content-Type", value); + SetSpecialHeaders ("Content-Type", value); } } @@ -323,13 +371,17 @@ namespace System.Net return DateTime.ParseExact (date, "r", CultureInfo.InvariantCulture).ToLocalTime (); } set { - if (value.Equals (DateTime.MinValue)) - webHeaders.RemoveInternal ("Date"); - else - webHeaders.RemoveAndAdd ("Date", value.ToUniversalTime ().ToString ("r", CultureInfo.InvariantCulture)); + SetDateHeaderHelper ("Date", value); } } + void SetDateHeaderHelper(string headerName, DateTime dateTime) { + if (dateTime == DateTime.MinValue) + SetSpecialHeaders(headerName, null); // remove header + else + SetSpecialHeaders(headerName, HttpProtocolUtils.date2string(dateTime)); + } + #if !NET_2_1 [MonoTODO] public static new RequestCachePolicy DefaultCachePolicy @@ -370,7 +422,8 @@ namespace System.Net if (val == "100-continue") throw new ArgumentException ("100-Continue cannot be set with this property.", "value"); - webHeaders.RemoveAndAdd ("Expect", value); + + webHeaders.CheckUpdate ("Expect", value); } } @@ -383,12 +436,21 @@ namespace System.Net get { return webHeaders; } set { CheckRequestStarted (); - WebHeaderCollection newHeaders = new WebHeaderCollection (WebHeaderCollection.HeaderInfo.Request); - int count = value.Count; - for (int i = 0; i < count; i++) - newHeaders.Add (value.GetKey (i), value.Get (i)); - webHeaders = newHeaders; + WebHeaderCollection webHeaders = value; + WebHeaderCollection newWebHeaders = new WebHeaderCollection(WebHeaderCollectionType.HttpWebRequest); + + // Copy And Validate - + // Handle the case where their object tries to change + // name, value pairs after they call set, so therefore, + // we need to clone their headers. + // + + foreach (String headerName in webHeaders.AllKeys ) { + newWebHeaders.Add(headerName,webHeaders[headerName]); + } + + webHeaders = newWebHeaders; } } @@ -549,6 +611,7 @@ namespace System.Net CheckRequestStarted (); proxy = value; servicePoint = null; // we may need a new one + GetServicePoint (); } } @@ -619,7 +682,7 @@ namespace System.Net if (!sendChunked) throw new ArgumentException ("SendChunked must be True", "value"); - webHeaders.RemoveAndAdd ("Transfer-Encoding", value); + webHeaders.CheckUpdate ("Transfer-Encoding", value); } } @@ -657,7 +720,26 @@ namespace System.Net internal bool ProxyQuery { get { return servicePoint.UsesProxy && !servicePoint.UseConnect; } } - + + internal ServerCertValidationCallback ServerCertValidationCallback { + get { return certValidationCallback; } + } + + public RemoteCertificateValidationCallback ServerCertificateValidationCallback { + get { + if (certValidationCallback == null) + return null; + return certValidationCallback.ValidationCallback; + } + set + { + if (value == null) + certValidationCallback = null; + else + certValidationCallback = new ServerCertValidationCallback (value); + } + } + // Methods internal ServicePoint GetServicePoint () @@ -708,7 +790,7 @@ namespace System.Net { if (rangeSpecifier == null) throw new ArgumentNullException ("rangeSpecifier"); - if (!WebHeaderCollection.IsHeaderValue (rangeSpecifier)) + if (!WebHeaderCollection.IsValidToken (rangeSpecifier)) throw new ArgumentException ("Invalid range specifier", "rangeSpecifier"); string r = webHeaders ["Range"]; @@ -726,7 +808,7 @@ namespace System.Net r = r + "0" + n; else r = r + n + "-"; - webHeaders.RemoveAndAdd ("Range", r); + webHeaders.ChangeInternal ("Range", r); } public @@ -734,7 +816,7 @@ namespace System.Net { if (rangeSpecifier == null) throw new ArgumentNullException ("rangeSpecifier"); - if (!WebHeaderCollection.IsHeaderValue (rangeSpecifier)) + if (!WebHeaderCollection.IsValidToken (rangeSpecifier)) throw new ArgumentException ("Invalid range specifier", "rangeSpecifier"); if (from > to || from < 0) throw new ArgumentOutOfRangeException ("from"); @@ -748,7 +830,7 @@ namespace System.Net r += ","; r = String.Format ("{0}{1}-{2}", r, from, to); - webHeaders.RemoveAndAdd ("Range", r); + webHeaders.ChangeInternal ("Range", r); } @@ -906,11 +988,17 @@ namespace System.Net } } - if (!requestSent) { + if (requestSent) + return; + + try { requestSent = true; redirects = 0; servicePoint = GetServicePoint (); abortHandler = servicePoint.SendRequest (this, connectionGroup); + } catch (Exception ex) { + aread.SetCompleted (synch, ex); + aread.DoCallback (); } }); @@ -1095,13 +1183,13 @@ namespace System.Net break; } - if (method != "GET" && !InternalAllowBuffering && writeStream.WriteBufferLength > 0) + if (method != "GET" && !InternalAllowBuffering && (writeStream.WriteBufferLength > 0 || contentLength > 0)) e = new WebException ("The request requires buffering data to succeed.", null, WebExceptionStatus.ProtocolError, webResponse); if (e != null) throw e; - if (AllowWriteStreamBuffering) + if (AllowWriteStreamBuffering || method == "GET") contentLength = -1; uriString = webResponse.Headers ["Location"]; @@ -1128,7 +1216,7 @@ namespace System.Net bool continue100 = false; if (sendChunked) { continue100 = true; - webHeaders.RemoveAndAdd ("Transfer-Encoding", "chunked"); + webHeaders.ChangeInternal ("Transfer-Encoding", "chunked"); webHeaders.RemoveInternal ("Content-Length"); } else if (contentLength != -1) { if (auth_state.NtlmAuthState == NtlmAuthState.Challenge || proxy_auth_state.NtlmAuthState == NtlmAuthState.Challenge) { @@ -1151,7 +1239,7 @@ namespace System.Net if (actualVersion == HttpVersion.Version11 && continue100 && servicePoint.SendContinue) { // RFC2616 8.2.3 - webHeaders.RemoveAndAdd ("Expect" , "100-continue"); + webHeaders.ChangeInternal ("Expect" , "100-continue"); expectContinue = true; } else { webHeaders.RemoveInternal ("Expect"); @@ -1167,16 +1255,16 @@ namespace System.Net if (keepAlive && (version == HttpVersion.Version10 || spoint10)) { if (webHeaders[connectionHeader] == null || webHeaders[connectionHeader].IndexOf ("keep-alive", StringComparison.OrdinalIgnoreCase) == -1) - webHeaders.RemoveAndAdd (connectionHeader, "keep-alive"); + webHeaders.ChangeInternal (connectionHeader, "keep-alive"); } else if (!keepAlive && version == HttpVersion.Version11) { - webHeaders.RemoveAndAdd (connectionHeader, "close"); + webHeaders.ChangeInternal (connectionHeader, "close"); } webHeaders.SetInternal ("Host", Host); if (cookieContainer != null) { string cookieHeader = cookieContainer.GetCookieHeader (actualUri); if (cookieHeader != "") - webHeaders.RemoveAndAdd ("Cookie", cookieHeader); + webHeaders.ChangeInternal ("Cookie", cookieHeader); else webHeaders.RemoveInternal ("Cookie"); } @@ -1187,7 +1275,7 @@ namespace System.Net if ((auto_decomp & DecompressionMethods.Deflate) != 0) accept_encoding = accept_encoding != null ? "gzip, deflate" : "deflate"; if (accept_encoding != null) - webHeaders.RemoveAndAdd ("Accept-Encoding", accept_encoding); + webHeaders.ChangeInternal ("Accept-Encoding", accept_encoding); if (!usedPreAuth && preAuthenticate) DoPreAuthenticate (); @@ -1227,7 +1315,7 @@ namespace System.Net wex = new WebException (msg, status); } else { msg = String.Format ("Error: {0} ({1})", status, exc.Message); - wex = new WebException (msg, exc, status); + wex = new WebException (msg, status, WebExceptionInternalStatus.RequestFatal, exc); } r.SetCompleted (false, wex); r.DoCallback (); @@ -1306,8 +1394,7 @@ namespace System.Net bodyBuffer = null; writeStream.Close (); } - } else if (method != "HEAD" && method != "GET" && method != "MKCOL" && method != "CONNECT" && - method != "TRACE") { + } else if (MethodWithBuffer) { if (getResponseCalled && !writeStream.RequestWritten) return writeStream.WriteRequestAsync (result); } @@ -1387,7 +1474,7 @@ namespace System.Net if (wce != null) { WebConnection cnc = wce.Connection; cnc.PriorityRequest = this; - ICredentials creds = !isProxy ? credentials : proxy.Credentials; + ICredentials creds = (!isProxy || proxy == null) ? credentials : proxy.Credentials; if (creds != null) { cnc.NtlmCredential = creds.GetCredential (requestUri, "NTLM"); cnc.UnsafeAuthenticatedConnectionSharing = unsafe_auth_blah; @@ -1444,7 +1531,7 @@ namespace System.Net return; } - bool isProxy = ProxyQuery && !proxy.IsBypassed (actualUri); + bool isProxy = ProxyQuery && proxy != null && !proxy.IsBypassed (actualUri); bool redirected; try { @@ -1547,7 +1634,7 @@ namespace System.Net if (isProxy && (request.proxy == null || request.proxy.Credentials == null)) return false; - string [] authHeaders = response.Headers.GetValues_internal (isProxy ? "Proxy-Authenticate" : "WWW-Authenticate", false); + string [] authHeaders = response.Headers.GetValues (isProxy ? "Proxy-Authenticate" : "WWW-Authenticate"); if (authHeaders == null || authHeaders.Length == 0) return false; @@ -1562,7 +1649,7 @@ namespace System.Net return false; request.webHeaders [isProxy ? "Proxy-Authorization" : "Authorization"] = auth.Message; isCompleted = auth.Complete; - bool is_ntlm = (auth.Module.AuthenticationType == "NTLM"); + bool is_ntlm = (auth.ModuleAuthenticationType == "NTLM"); if (is_ntlm) ntlm_auth_state = (NtlmAuthState)((int) ntlm_auth_state + 1); return true; @@ -1606,12 +1693,28 @@ namespace System.Net (ProxyQuery && !proxy_auth_state.IsCompleted && code == HttpStatusCode.ProxyAuthenticationRequired)) { if (!usedPreAuth && CheckAuthorization (webResponse, code)) { // Keep the written body, so it can be rewritten in the retry - if (InternalAllowBuffering) { - if (writeStream.WriteBufferLength > 0) { - bodyBuffer = writeStream.WriteBuffer; - bodyBufferLength = writeStream.WriteBufferLength; + if (MethodWithBuffer) { + if (AllowWriteStreamBuffering) { + if (writeStream.WriteBufferLength > 0) { + bodyBuffer = writeStream.WriteBuffer; + bodyBufferLength = writeStream.WriteBufferLength; + } + + return true; + } + + // + // Buffering is not allowed but we have alternative way to get same content (we + // need to resent it due to NTLM Authentication). + // + if (ResendContentFactory != null) { + using (var ms = new MemoryStream ()) { + ResendContentFactory (ms); + bodyBuffer = ms.ToArray (); + bodyBufferLength = bodyBuffer.Length; + } + return true; } - return true; } else if (method != "PUT" && method != "POST") { bodyBuffer = null; return true;