HttpClientChannel.cs

  1. // ==++==
  2. // 
  3. //   
  4. //    Copyright (c) 2002 Microsoft Corporation.  All rights reserved.
  5. //   
  6. //    The use and distribution terms for this software are contained in the file
  7. //    named license.txt, which can be found in the root of this distribution.
  8. //    By using this software in any fashion, you are agreeing to be bound by the
  9. //    terms of this license.
  10. //   
  11. //    You must not remove this notice, or any other, from this software.
  12. //   
  13. // 
  14. // ==--==
  15. //==========================================================================
  16. //  File:       HttpClientChannel.cs
  17. //
  18. //  Summary:    Implements a client channel that transmits method calls over HTTP.
  19. //
  20. //  Classes:    public HttpClientChannel
  21. //              internal HttpClientTransportSink
  22. //
  23. //==========================================================================
  24. using System;
  25. using System.Collections;
  26. using System.IO;
  27. using System.Net;
  28. using System.Runtime.Remoting;
  29. using System.Runtime.Remoting.Channels;
  30. using System.Runtime.Remoting.Messaging;
  31. using System.Threading;
  32. using System.Globalization;
  33. namespace System.Runtime.Remoting.Channels.Http
  34. {
  35.     /// <include file='doc/HttpClientChannel.uex' path='docs/doc[@for="HttpClientChannel"]/*' />
  36.     public class HttpClientChannel : BaseChannelWithProperties, IChannelSender
  37.     {
  38.         // Property Keys (purposely all lower-case)
  39.         private const String ProxyNameKey = "proxyname";
  40.         private const String ProxyPortKey = "proxyport";
  41.         // If above keys get modified be sure to modify, the KeySet property on this
  42.         // class.
  43.         private static ICollection s_keySet = null;
  44.         
  45.     
  46.         // Settings
  47.         private int    _channelPriority = 1;  // channel priority
  48.         private String _channelName = "http"// channel name
  49.         // Proxy settings (_proxyObject gets recreated when _proxyName and _proxyPort are updated)
  50.         private IWebProxy _proxyObject = null// proxy object for request, can be overridden in transport sink
  51.         private String    _proxyName = null;
  52.         private int       _proxyPort = -1;
  53.         private int _clientConnectionLimit = 0; // bump connection limit to at least this number (only meaningful if > 0)
  54.         private bool _bUseDefaultCredentials = false// should default credentials be used?
  55.         
  56.         private IClientChannelSinkProvider _sinkProvider = null// sink chain provider                       
  57.         /// <include file='doc/HttpClientChannel.uex' path='docs/doc[@for="HttpClientChannel.HttpClientChannel"]/*' />
  58.         public HttpClientChannel()
  59.         {
  60.             SetupChannel();
  61.         } // HttpClientChannel()
  62.         /// <include file='doc/HttpClientChannel.uex' path='docs/doc[@for="HttpClientChannel.HttpClientChannel1"]/*' />
  63.         public HttpClientChannel(String name, IClientChannelSinkProvider sinkProvider)
  64.         {
  65.             _channelName = name;
  66.             _sinkProvider = sinkProvider;
  67.             SetupChannel();
  68.         } // HttpClientChannel(IClientChannelSinkProvider sinkProvider)
  69.        
  70.         // constructor used by config file
  71.         /// <include file='doc/HttpClientChannel.uex' path='docs/doc[@for="HttpClientChannel.HttpClientChannel2"]/*' />
  72.         public HttpClientChannel(IDictionary properties, IClientChannelSinkProvider sinkProvider)
  73.         {
  74.             if (properties != null)
  75.             {
  76.                 foreach (DictionaryEntry entry in properties)
  77.                 {
  78.                     switch ((String)entry.Key)
  79.                     {
  80.                     case "name": _channelName = (String)entry.Value; break;
  81.                     case "priority": _channelPriority = Convert.ToInt32(entry.Value); break;
  82.                     case "proxyName"this["proxyName"] = entry.Value; break;
  83.                     case "proxyPort"this["proxyPort"] = entry.Value; break;
  84.                     case "clientConnectionLimit"
  85.                     {
  86.                         _clientConnectionLimit = Convert.ToInt32(entry.Value); 
  87.                         break;
  88.                     }
  89.                     case "useDefaultCredentials":
  90.                     {
  91.                         _bUseDefaultCredentials = Convert.ToBoolean(entry.Value);
  92.                         break;
  93.                     }
  94.                     default
  95.                          throw new ArgumentException( 
  96.                             String.Format(
  97.                                 CoreChannel.GetResourceString(
  98.                                     "Remoting_Channels_BadCtorArgs"), 
  99.                                 entry.Key));
  100.                     }
  101.                 }
  102.             }
  103.             _sinkProvider = sinkProvider;
  104.             SetupChannel();
  105.         } // HttpClientChannel
  106.         
  107.         private void SetupChannel()
  108.         {
  109.             if (_sinkProvider != null)
  110.             {
  111.                 CoreChannel.AppendProviderToClientProviderChain(
  112.                     _sinkProvider, new HttpClientTransportSinkProvider());                                                
  113.             }
  114.             else
  115.                 _sinkProvider = CreateDefaultClientProviderChain();
  116.                 
  117.         
  118.             // proxy might have been created by setting proxyname/port in constructor with dictionary
  119.             if (_proxyObject == null
  120.             {
  121.                 // In this case, try to use the default proxy settings.
  122.                 WebProxy defaultProxy = WebProxy.GetDefaultProxy();
  123.                 if (defaultProxy != null)
  124.                 {
  125.                     Uri address = defaultProxy.Address;
  126.                     if (address != null)
  127.                     {
  128.                         _proxyName = address.Host;
  129.                         _proxyPort = address.Port;
  130.                     }
  131.                 }
  132.                 UpdateProxy();
  133.             }
  134.         } // SetupChannel()
  135.         //
  136.         // IChannel implementation
  137.         //
  138.         /// <include file='doc/HttpClientChannel.uex' path='docs/doc[@for="HttpClientChannel.ChannelPriority"]/*' />
  139.         public int ChannelPriority
  140.         {
  141.             get { return _channelPriority; }    
  142.         }
  143.         /// <include file='doc/HttpClientChannel.uex' path='docs/doc[@for="HttpClientChannel.ChannelName"]/*' />
  144.         public String ChannelName
  145.         {
  146.             get { return _channelName; }
  147.         }
  148.         // returns channelURI and places object uri into out parameter
  149.         /// <include file='doc/HttpClientChannel.uex' path='docs/doc[@for="HttpClientChannel.Parse"]/*' />
  150.         public String Parse(String url, out String objectURI)
  151.         {            
  152.             return HttpChannelHelper.ParseURL(url, out objectURI);
  153.         } // Parse
  154.         //
  155.         // end of IChannel implementation
  156.         // 
  157.         //
  158.         // IChannelSender implementation
  159.         //
  160.         /// <include file='doc/HttpClientChannel.uex' path='docs/doc[@for="HttpClientChannel.CreateMessageSink"]/*' />
  161.         public virtual IMessageSink CreateMessageSink(String url, Object remoteChannelData, out String objectURI)
  162.         {
  163.             // Set the out parameters
  164.             objectURI = null;
  165.             String channelURI = null;
  166.             
  167.             if (url != null// Is this a well known object?
  168.             {
  169.                 // Parse returns null if this is not one of our url's
  170.                 channelURI = Parse(url, out objectURI);
  171.             }
  172.             else // determine if we want to connect based on the channel data
  173.             {
  174.                 if (remoteChannelData != null)
  175.                 {
  176.                     if (remoteChannelData is IChannelDataStore)
  177.                     {
  178.                         IChannelDataStore cds = (IChannelDataStore)remoteChannelData;
  179.                         // see if this is an http uri
  180.                         String simpleChannelUri = Parse(cds.ChannelUris[0], out objectURI);
  181.                         if (simpleChannelUri != null)
  182.                             channelURI = cds.ChannelUris[0];
  183.                     }
  184.                 }
  185.             }
  186.             if (channelURI != null)
  187.             {
  188.                 if (url == null)
  189.                     url = channelURI;
  190.                 if (_clientConnectionLimit > 0)
  191.                 {
  192.                     ServicePoint sp = ServicePointManager.FindServicePoint(new Uri(channelURI));
  193.                     if (sp.ConnectionLimit < _clientConnectionLimit)
  194.                         sp.ConnectionLimit = _clientConnectionLimit;
  195.                 }
  196.                 // This will return null if one of the sink providers decides it doesn't
  197.                 // want to allow (or can't provide) a connection through this channel.
  198.                 IClientChannelSink sink = _sinkProvider.CreateSink(this, url, remoteChannelData);
  199.                 
  200.                 // return sink after making sure that it implements IMessageSink
  201.                 IMessageSink msgSink = sink as IMessageSink;
  202.                 if ((sink != null) && (msgSink == null))
  203.                 {
  204.                     throw new RemotingException(
  205.                         CoreChannel.GetResourceString("Remoting_Channels_ChannelSinkNotMsgSink"));
  206.                 }
  207.                     
  208.                 return msgSink;
  209.             }
  210.             return null;
  211.         } // CreateMessageSink
  212.         //
  213.         // end of IChannelSender implementation
  214.         //
  215.         private IClientChannelSinkProvider CreateDefaultClientProviderChain()
  216.         {
  217.             IClientChannelSinkProvider chain = new SoapClientFormatterSinkProvider();            
  218.             IClientChannelSinkProvider sink = chain;
  219.             
  220.             sink.Next = new HttpClientTransportSinkProvider();
  221.             
  222.             return chain;
  223.         } // CreateDefaultClientProviderChain
  224.         
  225.         //
  226.         // Support for properties (through BaseChannelSinkWithProperties)
  227.         //
  228.         
  229.         /// <include file='doc/HttpClientChannel.uex' path='docs/doc[@for="HttpClientChannel.this"]/*' />
  230.         public override Object this[Object key]
  231.         {
  232.             get
  233.             {
  234.                 String keyStr = key as String;
  235.                 if (keyStr == null)
  236.                     return null;
  237.             
  238.                 switch (keyStr.ToLower(CultureInfo.InvariantCulture))
  239.                 {
  240.                     case ProxyNameKey: return _proxyName;
  241.                     case ProxyPortKey: return _proxyPort;
  242.                 } // switch (keyStr.ToLower(CultureInfo.InvariantCulture))
  243.                 return null;
  244.             }
  245.             set
  246.             {
  247.                 String keyStr = key as String;
  248.                 if (keyStr == null)
  249.                     return;
  250.     
  251.                 switch (keyStr.ToLower(CultureInfo.InvariantCulture))
  252.                 {
  253.                     case ProxyNameKey: _proxyName = (String)value; UpdateProxy(); break;
  254.                     case ProxyPortKey: _proxyPort = Convert.ToInt32(value); UpdateProxy(); break;                        
  255.                 } // switch (keyStr.ToLower(CultureInfo.InvariantCulture))
  256.             }
  257.         } // this[]   
  258.         /// <include file='doc/HttpClientChannel.uex' path='docs/doc[@for="HttpClientChannel.Keys"]/*' />
  259.         public override ICollection Keys
  260.         {
  261.             get
  262.             {
  263.                 if (s_keySet == null)
  264.                 {
  265.                     // Don't need to synchronize. Doesn't matter if the list gets
  266.                     // generated twice.
  267.                     ArrayList keys = new ArrayList(2);
  268.                     keys.Add(ProxyNameKey);
  269.                     keys.Add(ProxyPortKey);
  270.                     
  271.                     s_keySet = keys;
  272.                 }
  273.                 return s_keySet;
  274.             }
  275.         } // Keys
  276.         //
  277.         // end of Support for properties
  278.         //
  279.         //
  280.         // Helper functions for processing settings and properties
  281.         //
  282.         // Called to recreate proxy object whenever the proxy name or port is changed.
  283.         private void UpdateProxy()
  284.         {
  285.             if ((_proxyName != null) && (_proxyName.Length > 0) &&                
  286.                 (_proxyPort > 0))
  287.             {
  288.                 WebProxy proxy = new WebProxy(_proxyName, _proxyPort);
  289.                 
  290.                 // disable proxy use when the host is local. i.e. without periods
  291.                 proxy.BypassProxyOnLocal = true;
  292.                 // setup bypasslist to include local ip address
  293.                 String[] bypassList = new String[]{ CoreChannel.GetMachineIp() };
  294.                 proxy.BypassList = bypassList;
  295.                 _proxyObject = proxy;
  296.             }
  297.             else
  298.             {
  299.                 _proxyObject = new WebProxy();
  300.             }
  301.         } // UpdateProxy
  302.         //
  303.         // end of Helper functions for processing settings and properties
  304.         //
  305.         //
  306.         // Methods to access properties (internals are for use by the transport sink)     
  307.         //
  308.         internal IWebProxy ProxyObject { get { return _proxyObject; } }
  309.         internal bool UseDefaultCredentials { get { return _bUseDefaultCredentials; } }
  310.         //
  311.         // end of Methods to access properties
  312.         //
  313.     } // class HttpClientChannel
  314.     internal class HttpClientTransportSinkProvider : IClientChannelSinkProvider
  315.     {
  316.         internal HttpClientTransportSinkProvider()
  317.         {
  318.         }    
  319.    
  320.         public IClientChannelSink CreateSink(IChannelSender channel, String url, 
  321.                                              Object remoteChannelData)
  322.         {
  323.             // url is set to the channel uri in CreateMessageSink        
  324.             return new HttpClientTransportSink((HttpClientChannel)channel, url);
  325.         }
  326.         public IClientChannelSinkProvider Next
  327.         {
  328.             get { return null; }
  329.             set { throw new NotSupportedException(); }
  330.         }
  331.     } // class HttpClientTransportSinkProvider
  332.     // transport sender sink used by HttpClientChannel
  333.     internal class HttpClientTransportSink : BaseChannelSinkWithProperties, IClientChannelSink
  334.     {
  335.         private const String s_defaultVerb = "POST";
  336.         private static String s_userAgent =
  337.             "Mozilla/4.0+(compatible; MSIE 6.0; Windows " + 
  338.             "; MS .NET Remoting; MS .NET CLR " + System.Environment.Version.ToString() + " )";
  339.         
  340.         // Property keys (purposely all lower-case)
  341.         private const String UserNameKey = "username";
  342.         private const String PasswordKey = "password";
  343.         private const String DomainKey = "domain";
  344.         private const String PreAuthenticateKey = "preauthenticate";
  345.         private const String CredentialsKey = "credentials";
  346.         private const String ClientCertificatesKey = "clientcertificates";
  347.         private const String ProxyNameKey = "proxyname";
  348.         private const String ProxyPortKey = "proxyport";
  349.         private const String TimeoutKey = "timeout";
  350.         private const String AllowAutoRedirectKey = "allowautoredirect";
  351.         // If above keys get modified be sure to modify, the KeySet property on this
  352.         // class.
  353.         private static ICollection s_keySet = null;
  354.         // Property values
  355.         private String _securityUserName = null;
  356.         private String _securityPassword = null;
  357.         private String _securityDomain = null;
  358.         private bool   _bSecurityPreAuthenticate = false;
  359.         private ICredentials _credentials = null// this overrides all of the other security settings
  360.         private int  _timeout = System.Threading.Timeout.Infinite; // timeout value in milliseconds (only used if greater than 0)
  361.         private bool _bAllowAutoRedirect = false;
  362.         // Proxy settings (_proxyObject gets recreated when _proxyName and _proxyPort are updated)
  363.         private IWebProxy _proxyObject = null// overrides channel proxy object if non-null
  364.         private String    _proxyName = null;
  365.         private int       _proxyPort = -1;
  366.         // Other members
  367.         private HttpClientChannel _channel; // channel that created this sink
  368.         private String            _channelURI; // complete url to remote object        
  369.         // settings
  370.         private bool _useChunked = false// FUTURE: Consider enabling chunked after implementing a method to avoid the perf hit on small requests.
  371.         private bool _useKeepAlive = true;
  372.         internal HttpClientTransportSink(HttpClientChannel channel, String channelURI) : base()
  373.         {
  374.             _channel = channel;
  375.         
  376.             _channelURI = channelURI;
  377.             
  378.             // make sure channel uri doesn't end with a slash.
  379.             if (_channelURI.EndsWith("/"))
  380.                 _channelURI = _channelURI.Substring(0, _channelURI.Length - 1);
  381.                 
  382.         } // HttpClientTransportSink
  383.         
  384.         public void ProcessMessage(IMessage msg,
  385.                                    ITransportHeaders requestHeaders, Stream requestStream,
  386.                                    out ITransportHeaders responseHeaders, out Stream responseStream)
  387.         {
  388.             InternalRemotingServices.RemotingTrace("HttpTransportSenderSink::ProcessMessage");
  389.             HttpWebRequest httpWebRequest = ProcessAndSend(msg, requestHeaders, requestStream);
  390.             // receive server response
  391.             HttpWebResponse response = null;
  392.             try
  393.             {
  394.                 response = (HttpWebResponse)httpWebRequest.GetResponse();
  395.             }
  396.             catch (WebException webException)
  397.             {
  398.                 ProcessResponseException(webException, out response);
  399.             }
  400.     
  401.             ReceiveAndProcess(response, out responseHeaders, out responseStream);
  402.         } // ProcessMessage
  403.         public void AsyncProcessRequest(IClientChannelSinkStack sinkStack, IMessage msg,
  404.                                         ITransportHeaders headers, Stream stream)
  405.         {
  406.             HttpWebRequest httpWebRequest = ProcessAndSend(msg, headers, stream);
  407.             sinkStack.Push(this, httpWebRequest);
  408.             
  409.             httpWebRequest.BeginGetResponse(
  410.                 new AsyncCallback(this.OnHttpMessageReturn), 
  411.                 sinkStack);
  412.         } // AsyncProcessRequest
  413.         private void OnHttpMessageReturn(IAsyncResult ar)
  414.         {                    
  415.             IClientChannelSinkStack sinkStack = (IClientChannelSinkStack)ar.AsyncState;
  416.             HttpWebResponse response = null;
  417.             HttpWebRequest httpWebRequest = (HttpWebRequest)sinkStack.Pop(this);
  418.             try
  419.             {
  420.                 response = (HttpWebResponse) httpWebRequest.EndGetResponse(ar);
  421.             }
  422.             catch (WebException webException)
  423.             {
  424.                 ProcessResponseException(webException, out response);
  425.             }
  426.             // process incoming response
  427.             ITransportHeaders responseHeaders;
  428.             Stream responseStream;
  429.             ReceiveAndProcess(response, out responseHeaders, out responseStream);
  430.             // call down the sink chain
  431.             sinkStack.AsyncProcessResponse(responseHeaders, responseStream);
  432.         } // OnHttpMessageReturn
  433.         private void ProcessResponseException(WebException webException, out HttpWebResponse response)
  434.         {
  435.             // if a timeout occurred throw a RemotingTimeoutException
  436.             if (webException.Status == WebExceptionStatus.Timeout)
  437.                 throw new RemotingTimeoutException(
  438.                     CoreChannel.GetResourceString(
  439.                         "Remoting_Channels_RequestTimedOut"),
  440.                     webException);
  441.         
  442.             response = webException.Response as HttpWebResponse;
  443.             if ((response == null))
  444.                 throw webException;                
  445.                 
  446.             // if server error (500-599 continue with processing the soap fault);
  447.             //   otherwise, rethrow the exception.
  448.             int statusCode = (int)(response.StatusCode);
  449.             if ((statusCode < 500) || 
  450.                 (statusCode > 599))
  451.             {
  452.                 throw webException;
  453.             }   
  454.         } // ProcessResponseException
  455.         public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack, Object state,
  456.                                          ITransportHeaders headers, Stream stream)
  457.         {
  458.             // We don't have to implement this since we are always last in the chain.
  459.         } // AsyncProcessRequest
  460.         
  461.         
  462.         public Stream GetRequestStream(IMessage msg, ITransportHeaders headers)
  463.         {
  464.             return null
  465.         } // GetRequestStream
  466.         public IClientChannelSink NextChannelSink
  467.         {
  468.             get { return null; }
  469.         }
  470.     
  471.         private HttpWebRequest SetupWebRequest(IMessage msg, ITransportHeaders headers)
  472.         {
  473.             IMethodCallMessage mcMsg = msg as IMethodCallMessage;        
  474.             String msgUri = (String)headers[CommonTransportKeys.RequestUri];
  475.             InternalRemotingServices.RemotingTrace("HttpClientChannel::SetupWebRequest Message uri is " + msgUri);
  476.             if (msgUri == null)
  477.             {
  478.                 if (mcMsg != null)
  479.                     msgUri = mcMsg.Uri;
  480.                 else
  481.                     msgUri = (String)msg.Properties["__Uri"];
  482.             }
  483.             
  484.             String fullPath;
  485.             if (HttpChannelHelper.StartsWithHttp(msgUri) != -1)
  486.             {
  487.                 // this is the full path
  488.                 fullPath = msgUri;
  489.             }
  490.             else
  491.             {
  492.                 // this is not the full path (_channelURI never has trailing slash)
  493.                 if (!msgUri.StartsWith("/"))
  494.                     msgUri = "/" + msgUri;
  495.              
  496.                 fullPath = _channelURI + msgUri;                
  497.             }
  498.             InternalRemotingServices.RemotingTrace("HttpClientChannel::SetupWebRequest FullPath " + fullPath);
  499.             // based on headers, initialize the network stream
  500.             String verb = (String)headers["__RequestVerb"];
  501.             if (verb == null)
  502.                 verb = s_defaultVerb;            
  503.             HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(fullPath);
  504.             httpWebRequest.AllowAutoRedirect = _bAllowAutoRedirect;
  505.             httpWebRequest.Method = verb;
  506.             httpWebRequest.SendChunked = _useChunked; 
  507.             httpWebRequest.KeepAlive = _useKeepAlive;
  508.             httpWebRequest.Pipelined = false;
  509.             httpWebRequest.UserAgent = s_userAgent;
  510.             httpWebRequest.Timeout = _timeout;
  511.             // see if we should use a proxy object
  512.             IWebProxy proxy = _proxyObject;
  513.             if (proxy == null// use channel proxy if one hasn't been explicity set for this sink
  514.                 proxy = _channel.ProxyObject;
  515.             if (proxy != null)
  516.                 httpWebRequest.Proxy = proxy; 
  517.                                             
  518.             // see if security should be used
  519.             //   order of applying credentials is:
  520.             //   1. check for explicitly set credentials
  521.             //   2. else check for explicitly set username, password, domain
  522.             //   3. else use default credentials if channel is configured to do so.
  523.             if (_credentials != null)
  524.             {
  525.                 httpWebRequest.Credentials = _credentials;
  526.                 httpWebRequest.PreAuthenticate = _bSecurityPreAuthenticate;
  527.             }
  528.             else
  529.             if (_securityUserName != null)
  530.             {
  531.                 if (_securityDomain == null)
  532.                     httpWebRequest.Credentials = new NetworkCredential(_securityUserName, _securityPassword);
  533.                 else
  534.                     httpWebRequest.Credentials = new NetworkCredential(_securityUserName, _securityPassword, _securityDomain);
  535.                 httpWebRequest.PreAuthenticate = _bSecurityPreAuthenticate;
  536.             }
  537.             else
  538.             if (_channel.UseDefaultCredentials)
  539.             {
  540.                 httpWebRequest.Credentials = CredentialCache.DefaultCredentials;
  541.                 httpWebRequest.PreAuthenticate = _bSecurityPreAuthenticate;
  542.             }
  543.             InternalRemotingServices.RemotingTrace("HttpClientTransportSink::SetupWebRequest - Get Http Request Headers");
  544.             // add headers
  545.             foreach (DictionaryEntry header in headers)
  546.             {
  547.                 String key = header.Key as String;
  548.                 
  549.                 // if header name starts with "__", it is a special value that shouldn't be
  550.                 //   actually sent out.
  551.                 if ((key != null) && !key.StartsWith("__")) 
  552.                 {
  553.                     if (key.Equals("Content-Type"))
  554.                         httpWebRequest.ContentType = header.Value.ToString();
  555.                     else
  556.                         httpWebRequest.Headers[key] = header.Value.ToString();
  557.                 }
  558.             }
  559.             return httpWebRequest;
  560.         } // SetupWebRequest
  561.         private HttpWebRequest ProcessAndSend(IMessage msg, ITransportHeaders headers, 
  562.                                               Stream inputStream)
  563.         {      
  564.             // If the stream is seekable, we can retry once on a failure to write.
  565.             long initialPosition = 0;
  566.             bool bCanSeek = false;
  567.             if (inputStream != null)
  568.             {
  569.                 bCanSeek = inputStream.CanSeek;
  570.                 if (bCanSeek)
  571.                     initialPosition = inputStream.Position;
  572.             }
  573.         
  574.             HttpWebRequest httpWebRequest = null;
  575.             Stream writeStream = null;
  576.             try
  577.             {
  578.                 httpWebRequest = SetupWebRequest(msg, headers);
  579.                 if (inputStream != null)
  580.                 {
  581.                     if (!_useChunked)
  582.                         httpWebRequest.ContentLength = (int)inputStream.Length;
  583.           
  584.                     writeStream = httpWebRequest.GetRequestStream();
  585.                     StreamHelper.CopyStream(inputStream, writeStream);                  
  586.                 }
  587.             }    
  588.             catch (Exception)
  589.             {
  590.                 // try to send one more time if possible
  591.                 if (bCanSeek)
  592.                 {
  593.                     httpWebRequest = SetupWebRequest(msg, headers);
  594.                     if (inputStream != null)
  595.                     {
  596.                         inputStream.Position = initialPosition;
  597.                     
  598.                         if (!_useChunked)
  599.                             httpWebRequest.ContentLength = (int)inputStream.Length;
  600.           
  601.                         writeStream = httpWebRequest.GetRequestStream();
  602.                         StreamHelper.CopyStream(inputStream, writeStream);                  
  603.                     }                
  604.                 } // end of "try to send one more time"
  605.             }
  606.             if (inputStream != null)
  607.                 inputStream.Close();                
  608.             if (writeStream != null)
  609.                 writeStream.Close(); 
  610.             return httpWebRequest;
  611.         } // ProcessAndSend
  612.         private void ReceiveAndProcess(HttpWebResponse response, 
  613.                                        out ITransportHeaders returnHeaders,
  614.                                        out Stream returnStream)
  615.         {
  616.             HttpStatusCode statusCode = response.StatusCode;
  617.             //
  618.             // Read Response Message
  619.             // Just hand back the network stream
  620.             //   (NOTE: The channel sinks are responsible for calling Close() on a stream
  621.             //    once they are done with it).
  622.             returnStream = new BufferedStream(response.GetResponseStream(), 1024);  
  623.             // collect headers
  624.             returnHeaders = new TransportHeaders();
  625.             foreach (Object key in response.Headers)
  626.             {
  627.                 String keyString = key.ToString();
  628.                 returnHeaders[keyString] = response.Headers[keyString];
  629.             }
  630.         } // ReceiveAndProcess
  631.         //
  632.         // Support for properties (through BaseChannelSinkWithProperties)
  633.         //
  634.         public override Object this[Object key]
  635.         {
  636.             get
  637.             {
  638.                 String keyStr = key as String;
  639.                 if (keyStr == null)
  640.                     return null;
  641.             
  642.                 switch (keyStr.ToLower(CultureInfo.InvariantCulture))
  643.                 {
  644.                 case UserNameKey: return _securityUserName; 
  645.                 case PasswordKey: return null// Intentionally refuse to return password.
  646.                 case DomainKey: return _securityDomain;
  647.                 case PreAuthenticateKey: return _bSecurityPreAuthenticate; 
  648.                 case CredentialsKey: return _credentials;
  649.                 case ClientCertificatesKey: return null// Intentionally refuse to return certificates
  650.                 case ProxyNameKey: return _proxyName; 
  651.                 case ProxyPortKey: return _proxyPort; 
  652.                 case TimeoutKey: return _timeout;
  653.                 case AllowAutoRedirectKey: return _bAllowAutoRedirect;
  654.                 } // switch (keyStr.ToLower(CultureInfo.InvariantCulture))
  655.                 return null
  656.             }
  657.         
  658.             set
  659.             {
  660.                 String keyStr = key as String;
  661.                 if (keyStr == null)
  662.                     return;
  663.     
  664.                 switch (keyStr.ToLower(CultureInfo.InvariantCulture))
  665.                 {
  666.                 case UserNameKey: _securityUserName = (String)value; break;
  667.                 case PasswordKey: _securityPassword = (String)value; break;    
  668.                 case DomainKey: _securityDomain = (String)value; break;                
  669.                 case PreAuthenticateKey: _bSecurityPreAuthenticate = Convert.ToBoolean(value); break;
  670.                 case CredentialsKey: _credentials = (ICredentials)value; break;
  671.                 case ProxyNameKey: _proxyName = (String)value; UpdateProxy(); break;
  672.                 case ProxyPortKey: _proxyPort = Convert.ToInt32(value); UpdateProxy(); break;
  673.                 case TimeoutKey: 
  674.                 {
  675.                     if (value is TimeSpan)
  676.                         _timeout = (int)((TimeSpan)value).TotalMilliseconds;
  677.                     else
  678.                         _timeout = Convert.ToInt32(value); 
  679.                     break;
  680.                 } // case TimeoutKey
  681.                 case AllowAutoRedirectKey: _bAllowAutoRedirect = Convert.ToBoolean(value); break;
  682.                 
  683.                 } // switch (keyStr.ToLower(CultureInfo.InvariantCulturey))
  684.             }
  685.         } // this[]   
  686.         
  687.         public override ICollection Keys
  688.         {
  689.             get
  690.             {
  691.                 if (s_keySet == null)
  692.                 {
  693.                     // Don't need to synchronize. Doesn't matter if the list gets
  694.                     // generated twice.
  695.                     ArrayList keys = new ArrayList(6);
  696.                     keys.Add(UserNameKey);
  697.                     keys.Add(PasswordKey);
  698.                     keys.Add(DomainKey);
  699.                     keys.Add(PreAuthenticateKey);
  700.                     keys.Add(CredentialsKey);
  701.                     keys.Add(ClientCertificatesKey);
  702.                     keys.Add(ProxyNameKey);
  703.                     keys.Add(ProxyPortKey);
  704.                     keys.Add(TimeoutKey);
  705.                     keys.Add(AllowAutoRedirectKey);                    
  706.                     
  707.                     s_keySet = keys;
  708.                 }
  709.                 return s_keySet;
  710.             }
  711.         } // Keys
  712.         //
  713.         // end of Support for properties
  714.         //
  715.         //
  716.         // Helper functions for processing settings and properties
  717.         //
  718.         // Called to recreate proxy object whenever the proxy name or port is changed.
  719.         private void UpdateProxy()
  720.         {
  721.             if ((_proxyName != null) && (_proxyPort > 0))
  722.             {
  723.                 WebProxy proxy = new WebProxy(_proxyName, _proxyPort);
  724.                 
  725.                 // disable proxy use when the host is local. i.e. without periods
  726.                 proxy.BypassProxyOnLocal = true;
  727.                 _proxyObject = proxy;
  728.             }
  729.         } // UpdateProxy
  730.         //
  731.         // end of Helper functions for processing settings and properties
  732.         //
  733.         internal static String UserAgent
  734.         {
  735.             get { return s_userAgent; }
  736.         }       
  737.         
  738.                 
  739.     } // class HttpClientTransportSink
  740. // namespace System.Runtime.Remoting.Channels.Http
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值