2009-06-02 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mcs / class / System / System.Net / VMWHttpProvider.jvm.cs
index 0e8ec2b2917000908945ecb36f35232e56be2ba6..38470440dd4890c35ba5837451f592c208b12a34 100644 (file)
@@ -6,6 +6,13 @@ using mainsoft.apache.commons.httpclient;
 using mainsoft.apache.commons.httpclient.methods;\r
 using mainsoft.apache.commons.httpclient.@params;\r
 using mainsoft.apache.commons.httpclient.auth;\r
+using mainsoft.apache.commons.httpclient.auth.negotiate;\r
+using javax.security.auth;\r
+using org.ietf.jgss;\r
+using java.security;\r
+using System.Collections.Specialized;\r
+using System.Collections;\r
+using mainsoft.apache.commons.httpclient.cookie;\r
 \r
 namespace System.Net\r
 {\r
@@ -30,7 +37,7 @@ namespace System.Net
                protected bool _hasResponse;\r
                protected bool _hasRequest;\r
                protected Stream _writeStream;\r
-               private GHWebAsyncResult _asyncWrite;\r
+               private GHWebAsyncResult _asyncWrite;           \r
 \r
                private bool _isConnectionOpened;\r
                \r
@@ -62,6 +69,8 @@ namespace System.Net
                        {\r
                                _disableHttpConnectionPooling = bool.Parse(s);\r
                        }\r
+                       InitDefaultCredentialsProvider ();\r
+                       InitSPNProviders ();\r
                }\r
 \r
                internal override ServicePoint ServicePoint\r
@@ -169,17 +178,9 @@ namespace System.Net
                                                new NTCredentials(nc.UserName, nc.Password, host, domain));\r
                                }\r
                        }\r
-                       else if (String.Compare (type, "negotiate", StringComparison.InvariantCultureIgnoreCase) == 0) {\r
-                               if (!proxyCredentials) {\r
-                                       _state.setCredentials (new AuthScope (AuthScope.ANY_HOST,\r
-                                               AuthScope.ANY_PORT, AuthScope.ANY_REALM, "negotiate"),\r
-                                               new NTCredentials (nc.UserName, nc.Password, host, domain));\r
-                               }\r
-                               else {\r
-                                       _state.setProxyCredentials (new AuthScope (AuthScope.ANY_HOST,\r
-                                               AuthScope.ANY_PORT, AuthScope.ANY_REALM, "negotiate"),\r
-                                               new NTCredentials (nc.UserName, nc.Password, host, domain));\r
-                               }\r
+                       else if(String.Compare (type, "negotiate", StringComparison.InvariantCultureIgnoreCase) == 0)\r
+                       {\r
+                               SetAuthenticationScheme (AuthPolicy.NEGOTIATE);\r
                        }\r
                        else\r
                        {\r
@@ -195,27 +196,92 @@ namespace System.Net
                                                AuthScope.ANY_PORT, AuthScope.ANY_REALM, type),\r
                                                new UsernamePasswordCredentials(nc.UserName, nc.Password));\r
                                }\r
-                       }\r
-                       SetAuthenticationScheme (Char.ToUpper (type [0]) + type.Substring (1));\r
+                       }                                               \r
+               }\r
 \r
+               private void SetAuthenticationScheme (string type) {                    \r
+                       _method.getHostAuthState ().setAuthScheme (AuthPolicy.getAuthScheme (type));                                                            \r
+                       if (type != null && type.ToLower () == AuthPolicy.NEGOTIATE.ToLower ()) {                                       \r
+                               _method.getParams ().setParameter (CredentialsProvider__Finals.PROVIDER, new HTTPClientCredentialsBridge( DefaultCredentialsProvider));\r
+                               _method.getParams ().setParameter (NegotiateScheme.SPN_LIST_PARAM, SPNProviders);\r
+                       }                       \r
                }\r
 \r
-               private void SetAuthenticationScheme (string type) {\r
-                       try {\r
-                               _method.getHostAuthState ().setAuthScheme (AuthPolicy.getAuthScheme (type));\r
+               private java.util.ArrayList SPNProviders {\r
+                       get {\r
+                               return (java.util.ArrayList) AppDomain.CurrentDomain.GetData ("GH$SPNProviders");\r
                        }\r
-                       catch (Exception) {//ignore no such scheme, will be selected by the chalenges order\r
+                       set {\r
+                               AppDomain.CurrentDomain.SetData ("GH$SPNProviders", value);\r
                        }\r
                }\r
-               private void InitProxyCredentials()\r
-               {\r
-                       if(this.Proxy == null)\r
+\r
+               private void InitSPNProviders () {\r
+                       if (SPNProviders != null)\r
                                return;\r
+                       java.util.ArrayList spnProviders = new java.util.ArrayList ();\r
+                       NameValueCollection configAttributes = System.Configuration.ConfigurationSettings.AppSettings;\r
+                       string providersList = configAttributes ["SPNProviders"];\r
+                       if (providersList == null)\r
+                               return;\r
+                       string[] tokens = providersList.Split (',');\r
+                       foreach (string spnClass in tokens) {\r
+                               try {\r
+                                       spnProviders.add (Activator.CreateInstance (Type.GetType (spnClass)));\r
+                               }\r
+                               catch (Exception) { }\r
+                       }\r
+                       SPNProviders = spnProviders;\r
+               }\r
 \r
-                       if(!(this.Proxy is WebProxy))\r
+               private vmw.@internal.auth.CredentialsProvider DefaultCredentialsProvider {\r
+                       get {\r
+                               return (vmw.@internal.auth.CredentialsProvider) AppDomain.CurrentDomain.GetData ("GH$DefaultCredentialsProvider");\r
+                       }\r
+                       set {\r
+                               AppDomain.CurrentDomain.SetData ("GH$DefaultCredentialsProvider", value);\r
+                       }\r
+               }\r
+\r
+               private void InitDefaultCredentialsProvider () {\r
+                       if (DefaultCredentialsProvider != null)\r
                                return;\r
+                       vmw.@internal.auth.CredentialsProvider defaultProvider = null;\r
+                       NameValueCollection configAttributes = System.Configuration.ConfigurationSettings.AppSettings;\r
                        \r
-                       WebProxy proxy = (WebProxy)this.Proxy;\r
+                       string defaultProviderClass = configAttributes ["DefaultCredentialsProvider"];\r
+                       if (defaultProviderClass != null) {\r
+                               try {                                   \r
+                                       defaultProvider = (vmw.@internal.auth.CredentialsProvider)\r
+                                               Activator.CreateInstance (Type.GetType (defaultProviderClass));\r
+                               }\r
+                               catch (Exception e) {\r
+                                       Console.WriteLine ("Failed to initialize Credentials Provider: " + defaultProviderClass + " Message: " + e.Message);                                    \r
+                               }\r
+                       }                       \r
+\r
+                       if (defaultProvider == null) \r
+                               defaultProvider = new vmw.@internal.auth.SubjectCredentialsPrvider ();\r
+\r
+                       defaultProvider.init (ConvertToTable (configAttributes));\r
+                       DefaultCredentialsProvider = defaultProvider;\r
+               }\r
+\r
+               private java.util.Properties ConvertToTable (NameValueCollection col) {\r
+                       java.util.Properties table = new java.util.Properties ();\r
+                       foreach (String key in col.Keys)\r
+                               table.put (key, col [key]);\r
+                       return table;\r
+               }\r
+\r
+               private void InitProxyCredentials () {\r
+                       if (this.Proxy == null)\r
+                               return;\r
+\r
+                       if (!(this.Proxy is WebProxy))\r
+                               return;\r
+\r
+                       WebProxy proxy = (WebProxy) this.Proxy;\r
                        ICredentials creds = proxy.Credentials;\r
 \r
                        if(creds == null)\r
@@ -256,9 +322,11 @@ namespace System.Net
                {\r
                        if(_credentials == null)\r
                                return;\r
-                       if(_credentials is CredentialCache)\r
-                       {\r
-                               NetworkCredential nc = ((CredentialCache)_credentials).GetCredential(GetOriginalAddress(), "basic");\r
+                       if (_credentials == CredentialCache.DefaultCredentials) {\r
+                               SetAuthenticationScheme (AuthPolicy.NEGOTIATE);\r
+                       }\r
+                       else if (_credentials is CredentialCache) {\r
+                               NetworkCredential nc = ((CredentialCache) _credentials).GetCredential (GetOriginalAddress (), "basic");\r
                                string type = "basic";\r
                                if(nc == null)\r
                                {\r
@@ -289,7 +357,7 @@ namespace System.Net
 \r
                private void InitHostConfig()\r
                {\r
-                       if(this.Proxy == null)\r
+                       if (this.Proxy == null || this.Proxy == WebRequest.DefaultWebProxy)\r
                                return;\r
                        if(this.Proxy.IsBypassed(GetOriginalAddress()))\r
                                return;\r
@@ -421,14 +489,14 @@ namespace System.Net
                                        _client.getParams().setParameter(HttpClientParams.CONNECTION_MANAGER_TIMEOUT, new java.lang.Long(30000));\r
                                        _client.getParams().setParameter(HttpClientParams.USER_AGENT, \r
                                                        "VMW4J HttpClient (based on Jakarta Commons HttpClient)");\r
+                                       _client.getParams ().setBooleanParameter (HttpClientParams.SINGLE_COOKIE_HEADER, true);\r
                                        java.util.ArrayList schemas = new java.util.ArrayList ();\r
                                        schemas.add ("Ntlm");\r
                                        schemas.add ("Digest");\r
-                                       schemas.add ("Basic");                                  \r
+                                       schemas.add ("Basic");\r
                                        schemas.add ("Negotiate");\r
                                        _client.getParams ().setParameter (AuthPolicy.AUTH_SCHEME_PRIORITY, schemas);\r
-                                       if(!_disableHttpConnectionPooling) \r
-                                       {\r
+                                       if (!_disableHttpConnectionPooling) {\r
                                                _sclient = _client;\r
                                        }\r
                                }\r
@@ -453,8 +521,14 @@ namespace System.Net
                                        switch(name)\r
                                        {\r
                                                case "GET" : _method = new GetMethod(uriString); break;\r
-                                               case "PUT" : _method = new PutMethod(uriString); break;\r
-                                               case "POST": _method = new PostMethod(uriString); break;\r
+                                               case "PUT" : _method = new PutMethod(uriString);\r
+                                                       if (ServicePointManager.Expect100Continue)\r
+                                                               _method.getParams ().setBooleanParameter (HttpMethodParams.USE_EXPECT_CONTINUE, true);\r
+                                                       break;\r
+                                               case "POST": _method = new PostMethod(uriString);\r
+                                                       if (ServicePointManager.Expect100Continue)\r
+                                                               _method.getParams ().setBooleanParameter (HttpMethodParams.USE_EXPECT_CONTINUE, true);\r
+                                                       break;\r
                                                case "HEAD": _method = new HeadMethod(uriString); break;\r
                                                case "TRACE": _method = new TraceMethod(uriString);break;\r
                                                case "DELETE": _method = new DeleteMethod(uriString);break;\r
@@ -486,6 +560,8 @@ namespace System.Net
                                throw new ProtocolViolationException();\r
                        lock(this)\r
                        {\r
+                               if (_isAborted)\r
+                                       throw new WebException ("The operation has been aborted.", WebExceptionStatus.RequestCanceled);\r
                                if(_writeStream != null)\r
                                        return _writeStream;\r
                                this.OpenConnection();\r
@@ -511,7 +587,7 @@ namespace System.Net
                                return _writeStream;\r
                        }\r
                }\r
-               private bool isRedirectNeeded(HttpMethod method)\r
+               private static bool isRedirectNeeded(HttpMethod method)\r
                {\r
                        switch (method.getStatusCode()) \r
                        {\r
@@ -519,10 +595,7 @@ namespace System.Net
                                case 301:\r
                                case 303:\r
                                case 307:\r
-                                       if (method.getFollowRedirects()) \r
-                                               return true;\r
-                                       else \r
-                                               return false;\r
+                                       return true;\r
                                default:\r
                                        return false;\r
                        } //end of switch\r
@@ -599,10 +672,22 @@ namespace System.Net
                        #endregion\r
                }\r
                \r
+               WebResponse GetAsyncResponse()\r
+               {\r
+                       try {\r
+                               return GetResponse ();\r
+                       }\r
+                       catch {\r
+                               return null;\r
+                       }\r
+               }\r
+\r
                public override WebResponse GetResponse()\r
                {\r
                        lock(this)\r
                        {\r
+                               if (_isAborted)\r
+                                       throw new WebException ("The operation has been aborted.", WebExceptionStatus.RequestCanceled);\r
                                if(!_isConnectionOpened)\r
                                        OpenConnection();\r
                                if(_response == null)\r
@@ -610,7 +695,14 @@ namespace System.Net
                                        try\r
                                        {       \r
                                                synchHeaders();\r
-                                               _client.executeMethod(_hostConfig, _method, _state);\r
+                                               InternalExecuteMethod ();                                               \r
+                                               int numOfRedirects = 0;\r
+                                               while (isRedirectNeeded (_method) && _allowAutoRedirect && numOfRedirects < MaxAutoRedirections) {\r
+                                                       if (!HandleManualyRedirect ())\r
+                                                               break;\r
+                                                       numOfRedirects++;\r
+                                               }\r
+                                               \r
                                                //todo right place to re-put all headers again...\r
                                                mainsoft.apache.commons.httpclient.Header hostHeader =\r
                                                        _method.getRequestHeader("Host");\r
@@ -646,7 +738,8 @@ namespace System.Net
                                                        //this.Abort();\r
                                                        throw new WebException("The remote server returned an error: (" + respCodeAsInt +") " +_response.StatusCode, null, WebExceptionStatus.ProtocolError, _response);\r
                                                }\r
-                                               if(isRedirectNeeded(_method) && _method.getResponseHeader("location") == null)\r
+                                               Header location = _method.getResponseHeader ("location");\r
+                                               if (isRedirectNeeded (_method) && location == null && _method.getFollowRedirects ())\r
                                                {\r
                                                        // See comments above for the error >= 400\r
                                                        _response.ReadAllAndClose();\r
@@ -676,19 +769,62 @@ namespace System.Net
 \r
                }\r
 \r
+               private void InternalExecuteMethod () {\r
+                       _client.executeMethod (_hostConfig, _method, _state);                   \r
+               }               \r
+\r
+               private bool HandleManualyRedirect () {                 \r
+                       Header redirectHeader = _method.getResponseHeader ("location");\r
+                       if (redirectHeader == null) {\r
+                               // See comments above for the error >= 400\r
+                               _response.ReadAllAndClose ();\r
+                               //this.Abort();\r
+                               throw new WebException ("Got response code " + _response.StatusCode + ", but no location provided", null, WebExceptionStatus.ProtocolError, _response);\r
+                       }\r
+\r
+                       mainsoft.apache.commons.httpclient.HttpMethod originalMethod = _method;\r
+                       try {\r
+                               string location = redirectHeader.getValue ();\r
+                               URI currentUri = _method.getURI ();\r
+                               URI redirectUri = null;\r
+\r
+                               redirectUri = new URI (location, true);\r
+                               if (redirectUri.isRelativeURI ()) {\r
+                                       //location is incomplete, use current values for defaults       \r
+                                       redirectUri = new URI (currentUri, redirectUri);\r
+                               }\r
+                               \r
+                               _method = new GetMethod ();\r
+                               foreach(Header h in originalMethod.getRequestHeaders())\r
+                                       _method.addRequestHeader(h);                            \r
+                               _method.setURI (redirectUri);                           \r
+                               InternalExecuteMethod ();\r
+                               return true;\r
+                       }\r
+                       catch (URIException e) {\r
+                               _method = originalMethod;\r
+                               return false;\r
+                       }\r
+               }\r
+\r
                public override void Abort()\r
                {\r
-                       _isAborted = true;\r
-                       try\r
-                       {\r
-                               if(_hasResponse)\r
-                               {\r
-                                       _response.Close();\r
+                       lock (this) {\r
+                               if (_isAborted)\r
+                                       return;\r
+                               _isAborted = true;\r
+                               try {\r
+                                       if (_hasResponse) {\r
+                                               _response.Close ();\r
+                                       }\r
+                               }\r
+                               finally {\r
+                                       if (_method != null)\r
+                                               _method.releaseConnection ();\r
+                                       _method = null;\r
+                                       _hasResponse = false;\r
+                                       _response = null;\r
                                }\r
-                       }\r
-                       finally\r
-                       {\r
-                               _method.releaseConnection();                            \r
                        }\r
                }\r
 \r
@@ -721,6 +857,8 @@ namespace System.Net
                                catch(Exception e)\r
                                {\r
                                        _asyncWrite.SetCompleted(false, e);\r
+                                       _asyncWrite.DoCallback ();\r
+                                       return _asyncWrite;\r
                                }\r
 \r
                                _asyncWrite.SetCompleted (true, _writeStream);\r
@@ -753,7 +891,7 @@ namespace System.Net
 \r
                public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state)\r
                {\r
-                       GetResponseDelegate d = new GetResponseDelegate (GetResponse);\r
+                       GetResponseDelegate d = new GetResponseDelegate (GetAsyncResponse);\r
                        DelegateAsyncResult result = new DelegateAsyncResult ();\r
                        AsyncContext userContext = new AsyncContext (d, result, callback, state);\r
                        result.AsyncResult = d.BeginInvoke (new AsyncCallback (DelegateAsyncResult.Callback), userContext);\r
@@ -762,6 +900,8 @@ namespace System.Net
 \r
                public override WebResponse EndGetResponse(IAsyncResult asyncResult)\r
                {\r
+                       if (_isAborted)\r
+                               throw new WebException ("The operation has been aborted.", WebExceptionStatus.RequestCanceled);\r
                        if (asyncResult == null)\r
                                throw new ArgumentNullException ("asyncResult");\r
 \r
@@ -845,9 +985,14 @@ namespace System.Net
                                        {\r
                                                if(!_closed)\r
                                                {\r
-                                                       _closed = true;\r
-                                                       _javaOutput.flush();\r
-                                                       _javaOutput.close();\r
+                                                       try {\r
+                                                               _closed = true;\r
+                                                               _javaOutput.close ();\r
+                                                       }\r
+                                                       catch (Exception e) {\r
+                                                               throw new WebException ("The request was aborted: The request was canceled.",\r
+                                                               e, WebExceptionStatus.RequestCanceled, null);\r
+                                                       }\r
                                                }\r
                                        }\r
                                }\r
@@ -900,13 +1045,7 @@ namespace System.Net
 \r
                        void IDisposable.Dispose()\r
                        {\r
-                               try\r
-                               {\r
-                                       Close();\r
-                               }\r
-                               catch(Exception)\r
-                               {\r
-                               }\r
+                               Close ();\r
                        }\r
                }\r
                \r
@@ -1127,6 +1266,15 @@ namespace System.Net
                                _out.write(i);\r
                        }\r
 \r
+                       public override void close () \r
+                       {\r
+                               int size = _out.size ();\r
+                               _out.close ();\r
+\r
+                               if (size < _contentLength) {\r
+                                       throw new IOException ("Cannot close stream until all bytes are written.");\r
+                               }\r
+                       }\r
                }\r
 \r
                #endregion\r
@@ -1137,5 +1285,21 @@ namespace System.Net
 \r
 \r
 \r
+       }\r
+\r
+       class HTTPClientCredentialsBridge : CredentialsProvider\r
+       {\r
+               private vmw.@internal.auth.CredentialsProvider m_internalProvider;\r
+\r
+               public HTTPClientCredentialsBridge (vmw.@internal.auth.CredentialsProvider internalProvider) {\r
+                       m_internalProvider = internalProvider;\r
+               }\r
+\r
+               public Credentials getCredentials (AuthScheme scheme, string __p2, int __p3, bool __p4) {\r
+                       if (scheme.isComplete ())\r
+                               return null;                    \r
+                       GSSCredential creds = m_internalProvider.getCredentials ();                     \r
+                       return new DelegatedCredentials (creds);\r
+               }\r
        }\r
 }\r