The Labs \ Source Viewer \ SSCLI \ System.Net \ Booleans

  1. //------------------------------------------------------------------------------
  2. // <copyright file="HttpWebRequest.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 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. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Net
  16. {
  17.     using System.Collections;
  18.     using System.Collections.Specialized;
  19.     using System.Globalization;
  20.     using System.IO;
  21.     using System.IO.Compression;
  22.     using System.Net.Cache;
  23.     using System.Net.Configuration;
  24.     using System.Runtime.Serialization;
  25.     using System.Security;
  26.     using System.Security.Cryptography.X509Certificates;
  27.     using System.Security.Permissions;
  28.     using System.Text;
  29.     using System.Text.RegularExpressions;
  30.     using System.Threading;
  31.     using System.Net.Security;
  32.     using System.Reflection;
  33.     using System.ComponentModel;
  34.    
  35.     /// <devdoc>
  36.     /// <para>
  37.     /// <see cref='System.Net.HttpWebRequest'/> is an HTTP-specific implementation of the <see cref='System.Net.WebRequest'/> class.
  38.     ///
  39.     /// Performs the major body of HTTP request processing. Handles
  40.     /// everything between issuing the HTTP header request to parsing the
  41.     /// the HTTP response. At that point, we hand off the request to the response
  42.     /// object, where the programmer can query for headers or continue reading, usw.
  43.     /// </para>
  44.     /// </devdoc>
  45.    
  46.    
  47.     [Flags()]
  48.     public enum DecompressionMethods
  49.     {
  50.         None = 0,
  51.         GZip = 1,
  52.         Deflate = 2
  53.     }
  54.    
  55.    
  56.     [Serializable()]
  57.     public class HttpWebRequest : WebRequest, ISerializable
  58.     {
  59.        
  60.         //these could have race conditions
  61.         bool m_Saw100Continue;
  62.         bool m_KeepAlive = true;
  63.         bool m_LockConnection;
  64.         bool m_NtlmKeepAlive;
  65.         bool m_PreAuthenticate;
  66.         DecompressionMethods m_AutomaticDecompression;
  67.        
  68.         private static class AbortState
  69.         {
  70.             public const int Public = 1;
  71.             public const int Internal = 2;
  72.         }
  73.         // interlocked
  74.         private int m_Aborted;
  75.        
  76.         //
  77.         // This is set on failure of the request before reattempting a retransmit,
  78.         // we do this on write/read failures so that we can recover from certain failures
  79.         // that may be caused by intermittent server/network failures.
  80.         // Returns: true, if we have seen some kind of failure.
  81.         //
  82.         // set to true if this request failed during a connect
  83.        
  84.         bool m_OnceFailed;
  85.        
  86.         bool m_Pipelined = true;
  87.         bool m_Retry = true;
  88.         bool m_HeadersCompleted;
  89.         bool m_IsCurrentAuthenticationStateProxy;
  90.         bool m_SawInitialResponse;
  91.         bool m_BodyStarted;
  92.         bool m_RequestSubmitted;
  93.         bool m_OriginallyBuffered;
  94.         bool m_Extra401Retry;
  95.        
  96.         //these should be safe.
  97.         [Flags()]
  98.         private enum Booleans : uint
  99.         {
  100.             AllowAutoRedirect = 1,
  101.             AllowWriteStreamBuffering = 2,
  102.             ExpectContinue = 4,
  103.            
  104.             ProxySet = 16,
  105.            
  106.             UnsafeAuthenticatedConnectionSharing = 64,
  107.             IsVersionHttp10 = 128,
  108.             SendChunked = 256,
  109.             EnableDecompression = 512,
  110.             IsTunnelRequest = 1024,
  111.             Default = AllowAutoRedirect | AllowWriteStreamBuffering | ExpectContinue
  112.         }
  113.        
  114.        
  115.         internal const HttpStatusCode MaxOkStatus = (HttpStatusCode)299;
  116.         private const HttpStatusCode MaxRedirectionStatus = (HttpStatusCode)399;
  117.         private const int RequestLineConstantSize = 12;
  118.         private const string ContinueHeader = "100-continue";
  119.         internal const string ChunkedHeader = "chunked";
  120.         internal const string GZipHeader = "gzip";
  121.         internal const string DeflateHeader = "deflate";
  122.        
  123.        
  124.         // default delay on the Stream.Read and Stream.Write operations
  125.         private const int DefaultReadWriteTimeout = 5 * 60 * 1000;
  126.         // 5 minutes
  127.         // time delay that we would wait for continue
  128.         internal const int DefaultContinueTimeout = 350;
  129.         // ms
  130.         // Size of ' HTTP/x.x\r\n'
  131.         // which are the
  132.         // unchanging pieces of the
  133.         // request line.
  134.         private static readonly byte[] HttpBytes = new byte[] {(byte)'H', (byte)'T', (byte)'T', (byte)'P', (byte)'/'};
  135.        
  136.         // Statics used in the 100 Continue timeout mechanism.
  137.         private static readonly WaitCallback s_EndWriteHeaders_Part2Callback = new WaitCallback(EndWriteHeaders_Part2Wrapper);
  138.         private static readonly TimerThread.Callback s_ContinueTimeoutCallback = new TimerThread.Callback(ContinueTimeoutCallback);
  139.         private static readonly TimerThread.Queue s_ContinueTimerQueue = TimerThread.GetOrCreateQueue(DefaultContinueTimeout);
  140.         private static readonly TimerThread.Callback s_TimeoutCallback = new TimerThread.Callback(TimeoutCallback);
  141.         private static readonly WaitCallback s_AbortWrapper = new WaitCallback(AbortWrapper);
  142.        
  143.         private static int s_UniqueGroupId;
  144.        
  145.         private Booleans _Booleans = Booleans.Default;
  146.        
  147.         private DateTime _CachedIfModifedSince = DateTime.MinValue;
  148.        
  149.         // Used in the 100 Continue timeout mechanism.
  150.         private TimerThread.Timer m_ContinueTimer;
  151.         private InterlockedGate m_ContinueGate;
  152.        
  153.         // Holds a WriteStream result to be processed by GetResponse.
  154.         private object m_PendingReturnResult;
  155.        
  156.         // Read and Write async results - corspond to BeginGetResponse(read), and BeginGetRequestStream(write)
  157.         private LazyAsyncResult _WriteAResult;
  158.         private LazyAsyncResult _ReadAResult;
  159.        
  160.         // Used by our Connection to block the Request on getting a Connection
  161.         private LazyAsyncResult _ConnectionAResult;
  162.         // Used by our Connection to block on being able to Read from our Connection
  163.         private LazyAsyncResult _ConnectionReaderAResult;
  164.        
  165.         // Once set, the Request either works Async or Sync internally
  166.         private TriState _RequestIsAsync;
  167.        
  168.         // Delegate that can be called on Continue Response
  169.         private HttpContinueDelegate _ContinueDelegate;
  170.        
  171.         // Link back to the server point used for this request.
  172.         internal ServicePoint _ServicePoint;
  173.        
  174.         // this is generated by SetResponse
  175.         internal HttpWebResponse _HttpResponse;
  176.        
  177.        
  178.         // set by Connection code upon completion (can be either CoreResponseData or an Exception)
  179.         private object _CoreResponse;
  180.         private int _NestedWriteSideCheck;
  181.         //To keep track nested responses for Sync case
  182.         // request values
  183.         private KnownHttpVerb _Verb;
  184.         // the actual verb set by caller or default
  185.         private KnownHttpVerb _OriginVerb;
  186.        
  187.         // our HTTP header response, request, parsing and storage objects
  188.         private WebHeaderCollection _HttpRequestHeaders;
  189.        
  190.         // send buffer for output request with headers.
  191.         private byte[] _WriteBuffer;
  192.        
  193.         // Property to set whether writes can be handled
  194.         private HttpWriteMode _HttpWriteMode;
  195.        
  196.         // the host, port, and path
  197.         private Uri _Uri;
  198.         // the origin Uri host, port and path that never changes
  199.         private Uri _OriginUri;
  200.        
  201.         // for which response ContentType we will look for and parse the CharacterSet
  202.         private string _MediaType;
  203.        
  204.         // content length
  205.         private long _ContentLength;
  206.        
  207.         // proxy that we are using...
  208.         private IWebProxy _Proxy;
  209.         private ProxyChain _ProxyChain;
  210.        
  211.         private string _ConnectionGroupName;
  212.         private bool m_InternalConnectionGroup;
  213.        
  214.         private AuthenticationState _ProxyAuthenticationState;
  215.         private AuthenticationState _ServerAuthenticationState;
  216.        
  217.         private ICredentials _AuthInfo;
  218.         private HttpAbortDelegate _AbortDelegate;
  219.        
  220.         //
  221.         // used to prevent Write Buffering,
  222.         // used otherwise for reposting POST, and PUTs in redirects
  223.         //
  224.         private ConnectStream _SubmitWriteStream;
  225.         private ConnectStream _OldSubmitWriteStream;
  226.         private int _MaximumAllowedRedirections;
  227.         private int _AutoRedirects;
  228.        
  229.         //
  230.         // generic version of _AutoRedirects above
  231.         // used to count the number of requests made off this WebRequest
  232.         //
  233.         private int _RerequestCount;
  234.        
  235.         //
  236.         // Timeout in milliseconds, if a synchronous request takes longer
  237.         // than timeout, a WebException is thrown
  238.         //
  239.         private int _Timeout;
  240.        
  241.         //
  242.         // Used to track relative time out across the use of the request
  243.         //
  244.         private TimerThread.Timer _Timer;
  245.        
  246.         //
  247.         // Timer factory, tied to the _Timeout time.
  248.         //
  249.         private TimerThread.Queue _TimerQueue;
  250.        
  251.         private int _RequestContinueCount;
  252.        
  253.         //
  254.         // Timeout for Read & Write on the Stream that we return through
  255.         // GetResponse().GetResponseStream() && GetRequestStream()
  256.         //
  257.         private int _ReadWriteTimeout;
  258.        
  259.         private CookieContainer _CookieContainer;
  260.        
  261.         private int _MaximumResponseHeadersLength;
  262.        
  263.         private UnlockConnectionDelegate _UnlockDelegate;
  264.        
  265.        
  266.        
  267.         // size of post data, that needs to be greater, before we wait for a continue response
  268.         // private static int DefaultRequireWaitForContinueSize = 2048; // bytes
  269.        
  270.        
  271.        
  272.         //
  273.         // Properties
  274.         //
  275.        
  276.         internal TimerThread.Timer RequestTimer {
  277.             get { return _Timer; }
  278.         }
  279.        
  280.         internal bool Aborted {
  281.             get { return m_Aborted != 0; }
  282.         }
  283.        
  284.        
  285.         /// <devdoc>
  286.         /// <para>
  287.         /// Enables or disables automatically following redirection responses.
  288.         /// </para>
  289.         /// </devdoc>
  290.         public bool AllowAutoRedirect {
  291.             get { return (_Booleans & Booleans.AllowAutoRedirect) != 0; }
  292.             set {
  293.                 if (value) {
  294.                     _Booleans |= Booleans.AllowAutoRedirect;
  295.                 }
  296.                 else {
  297.                     _Booleans &= ~Booleans.AllowAutoRedirect;
  298.                 }
  299.             }
  300.         }
  301.        
  302.         /// <devdoc>
  303.         /// <para>
  304.         /// Enables or disables buffering the data stream sent to the server.
  305.         /// </para>
  306.         /// </devdoc>
  307.         public bool AllowWriteStreamBuffering {
  308.             get { return (_Booleans & Booleans.AllowWriteStreamBuffering) != 0; }
  309.             set {
  310.                 if (value) {
  311.                     _Booleans |= Booleans.AllowWriteStreamBuffering;
  312.                 }
  313.                 else {
  314.                     _Booleans &= ~Booleans.AllowWriteStreamBuffering;
  315.                 }
  316.             }
  317.         }
  318.        
  319.         private bool ExpectContinue {
  320.             get { return (_Booleans & Booleans.ExpectContinue) != 0; }
  321.             set {
  322.                 if (value) {
  323.                     _Booleans |= Booleans.ExpectContinue;
  324.                 }
  325.                 else {
  326.                     _Booleans &= ~Booleans.ExpectContinue;
  327.                 }
  328.             }
  329.         }
  330.        
  331.         /// <devdoc>
  332.         /// <para>
  333.         /// Returns <see langword='true'/> if a response has been received from the
  334.         /// server.
  335.         /// </para>
  336.         /// </devdoc>
  337.         public bool HaveResponse {
  338.             get { return _ReadAResult != null && _ReadAResult.InternalPeekCompleted; }
  339.         }
  340.        
  341.         // this overrides the public KeepAlive setting.
  342.         // we use this override for NTLM only
  343.         internal bool NtlmKeepAlive {
  344.             get { return m_NtlmKeepAlive; }
  345.             set { m_NtlmKeepAlive = value; }
  346.         }
  347.        
  348.        
  349.        
  350.         internal bool SawInitialResponse {
  351.             get {
  352.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SawInitialResponse_get() :" + m_SawInitialResponse);
  353.                 return m_SawInitialResponse;
  354.             }
  355.             set {
  356.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SawInitialResponse_set() :" + value);
  357.                 m_SawInitialResponse = value;
  358.             }
  359.         }
  360.        
  361.         internal bool BodyStarted {
  362.             get { return m_BodyStarted; }
  363.         }
  364.        
  365. /*
  366.             Accessor:  KeepAlive
  367.             To the app, this means "I want to use a persistent connection if
  368.             available" if set to true, or "I don't want to use a persistent
  369.             connection", if set to false.
  370.             This accessor allows the application simply to register its
  371.             desires so far as persistence is concerned. We will act on this
  372.             and the pipelined requirement (below) at the point that we come
  373.             to choose or create a connection on the application's behalf
  374.             Read:      returns the sense of the keep-alive request switch
  375.             Write:      set the sense of the keep-alive request switch
  376.         */       
  377.        
  378.         /// <devdoc>
  379.         /// <para>
  380.         /// Gets or sets the value of the Keep-Alive header.
  381.         /// </para>
  382.         /// </devdoc>
  383.         public bool KeepAlive {
  384.             get { return m_KeepAlive; }
  385.             set { m_KeepAlive = value; }
  386.         }
  387.        
  388.         //
  389.         // LockConnection - set to true when the
  390.         // request needs exclusive access to the Connection
  391.         //
  392.         internal bool LockConnection {
  393.             get { return m_LockConnection; }
  394.             set { m_LockConnection = value; }
  395.         }
  396.        
  397.        
  398. /*
  399.             Accessor:  Pipelined
  400.             To the app, this means "I want to use pipelining if available" if
  401.             set to true, or "I don't want to use pipelining", if set to false.
  402.             We could infer the state of the keep-alive flag from this setting
  403.             too, but we will decide that only at connection-initiation time.
  404.             If the application sets pipelining but resets keep-alive then we
  405.             will generate a non-pipelined, non-keep-alive request
  406.             Read:      returns the sense of the pipelined request switch
  407.             Write:      sets the sense of the pipelined request switch
  408.         */       
  409.        
  410.         /// <devdoc>
  411.         /// <para>
  412.         /// Gets or sets the value of Pipelined property.
  413.         /// </para>
  414.         /// </devdoc>
  415.         public bool Pipelined {
  416.             get { return m_Pipelined; }
  417.             set { m_Pipelined = value; }
  418.         }
  419.        
  420.         /// <devdoc>
  421.         /// <para>
  422.         /// Enables or disables pre-authentication.
  423.         /// </para>
  424.         /// </devdoc>
  425.         public override bool PreAuthenticate {
  426.             get { return m_PreAuthenticate; }
  427.             set { m_PreAuthenticate = value; }
  428.         }
  429.        
  430.         private bool ProxySet {
  431.             get { return (_Booleans & Booleans.ProxySet) != 0; }
  432.             set {
  433.                 if (value) {
  434.                     _Booleans |= Booleans.ProxySet;
  435.                 }
  436.                 else {
  437.                     _Booleans &= ~Booleans.ProxySet;
  438.                 }
  439.             }
  440.         }
  441.        
  442.         private bool RequestSubmitted {
  443.             get { return m_RequestSubmitted; }
  444.         }
  445.        
  446.         // Call under lock.
  447.         private bool SetRequestSubmitted()
  448.         {
  449.             bool ret = RequestSubmitted;
  450.             m_RequestSubmitted = true;
  451.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitted() returning:" + ret.ToString());
  452.             return ret;
  453.         }
  454.        
  455.        
  456.         //
  457.         // if the 100 Continue comes in around 350ms there might be race conditions
  458.         // that make us set Understands100Continue to true when parsing the 100 response
  459.         // in the Connection object and later make us set it to false if the
  460.         // thread that is waiting comes in later than 350ms. to solve this we save info
  461.         // on wether we did actually see the 100 continue. In that case, even if there's a
  462.         // timeout, we won't set it to false.
  463.         //
  464.         internal bool Saw100Continue {
  465.             get { return m_Saw100Continue; }
  466.             set { m_Saw100Continue = value; }
  467.         }
  468.        
  469.         /// <devdoc>
  470.         /// <para>Allows hi-speed NTLM connection sharing with keep-alive</para>
  471.         /// </devdoc>
  472.         public bool UnsafeAuthenticatedConnectionSharing {
  473.             get { return (_Booleans & Booleans.UnsafeAuthenticatedConnectionSharing) != 0; }
  474.             set {
  475.                 ExceptionHelper.WebPermissionUnrestricted.Demand();
  476.                 if (value) {
  477.                     _Booleans |= Booleans.UnsafeAuthenticatedConnectionSharing;
  478.                 }
  479.                 else {
  480.                     _Booleans &= ~Booleans.UnsafeAuthenticatedConnectionSharing;
  481.                 }
  482.             }
  483.         }
  484.         //
  485.         // When authenticating TO THE proxy we create a shared connection
  486.         //
  487.         internal bool UnsafeOrProxyAuthenticatedConnectionSharing {
  488.             get { return m_IsCurrentAuthenticationStateProxy || UnsafeAuthenticatedConnectionSharing; }
  489.         }
  490.        
  491.        
  492.         // HTTP version of the request
  493.         private bool IsVersionHttp10 {
  494.             get { return (_Booleans & Booleans.IsVersionHttp10) != 0; }
  495.             set {
  496.                 if (value) {
  497.                     _Booleans |= Booleans.IsVersionHttp10;
  498.                 }
  499.                 else {
  500.                     _Booleans &= ~Booleans.IsVersionHttp10;
  501.                 }
  502.             }
  503.         }
  504.        
  505.         //
  506.         // SendChunked - set/gets the state of chunk transfer send mode,
  507.         // if true, we will attempt to upload/write bits using chunked property
  508.         //
  509.        
  510.         /// <devdoc>
  511.         /// <para>
  512.         /// Enable and disable sending chunked data to the server.
  513.         /// </para>
  514.         /// </devdoc>
  515.         public bool SendChunked {
  516.             get { return (_Booleans & Booleans.SendChunked) != 0; }
  517.             set {
  518.                 if (RequestSubmitted) {
  519.                     throw new InvalidOperationException(SR.GetString(SR.net_writestarted));
  520.                 }
  521.                 if (value) {
  522.                     _Booleans |= Booleans.SendChunked;
  523.                 }
  524.                 else {
  525.                     _Booleans &= ~Booleans.SendChunked;
  526.                 }
  527.             }
  528.         }
  529.        
  530.         public DecompressionMethods AutomaticDecompression {
  531.             get { return m_AutomaticDecompression; }
  532.             set {
  533.                 if (RequestSubmitted) {
  534.                     throw new InvalidOperationException(SR.GetString(SR.net_writestarted));
  535.                 }
  536.                 m_AutomaticDecompression = value;
  537.             }
  538.         }
  539.        
  540.        
  541. /*
  542.         //                         
  543.         internal DecompressionMethods DecompressionMethod{
  544.             get{
  545.                 DecompressionMethods method = DecompressionMethods.None;
  546.                 string acceptEncoding = Headers[HttpKnownHeaderNames.AcceptEncoding];
  547.                 if (acceptEncoding != null){
  548.                     if((AutomaticDecompression & DecompressionMethods.GZip) != 0){
  549.                         method = DecompressionMethods.GZip;
  550.                     }
  551.                     //was it set directly?
  552.                     else if(acceptEncoding.IndexOf(HttpWebRequest.GZipHeader) != -1) {
  553.                         method=DecompressionMethods.GZip;
  554.                     }
  555.                     if (acceptEncoding.IndexOf(HttpWebRequest.DeflateHeader) != -1){
  556.                         method |= DecompressionMethods.Deflate;
  557.                     }
  558.                 }
  559.                 return method;
  560.             }
  561.         }
  562.         */       
  563.        
  564.        
  565.         // This property holds our actual behaviour.
  566.         // In some cases we might have to disable chunking even if the user has requested it.
  567.         // In this case SendChunked returns true, but HttpWriteMode is != HttpWriteMode.Chunked
  568.         internal HttpWriteMode HttpWriteMode {
  569.             get { return _HttpWriteMode; }
  570.             set { _HttpWriteMode = value; }
  571.         }
  572.        
  573.        
  574.         internal string AuthHeader(HttpResponseHeader header)
  575.         {
  576.             if (_HttpResponse == null) {
  577.                 return null;
  578.             }
  579.             // currently if'd out in HttpWebRequest.cs
  580.             return _HttpResponse.Headers[(int)header];
  581.         }
  582.        
  583.         // This is a shortcut that would set the default policy for HTTP/HTTPS.
  584.         // The default policy is overridden by any prefix-registered policy.
  585.         // Will demand permission for set{}
  586.         public static new RequestCachePolicy DefaultCachePolicy {
  587.             get {
  588.                 #if DEBUG
  589.                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  590.                     #endif
  591.                     RequestCachePolicy policy = RequestCacheManager.GetBinding(Uri.UriSchemeHttp).Policy;
  592.                     if (policy == null)
  593.                         return WebRequest.DefaultCachePolicy;
  594.                     return policy;
  595.                     #if DEBUG
  596.                 }
  597.                 #endif
  598.             }
  599.             set {
  600.                 #if DEBUG
  601.                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  602.                     #endif
  603.                     // This is a replacement of RequestCachePermission demand since we are not including the latest in the product.
  604.                     ExceptionHelper.WebPermissionUnrestricted.Demand();
  605.                    
  606.                     RequestCacheBinding binding = RequestCacheManager.GetBinding(Uri.UriSchemeHttp);
  607.                     RequestCacheManager.SetBinding(Uri.UriSchemeHttp, new RequestCacheBinding(binding.Cache, binding.Validator, value));
  608.                     #if DEBUG
  609.                 }
  610.                 #endif
  611.             }
  612.         }
  613.        
  614.         /// <devdoc>
  615.         /// <para>
  616.         /// Gets or sets the default for the MaximumResponseHeadersLength property.
  617.         /// </para>
  618.         /// <remarks>
  619.         /// This value can be set in the config file, the default can be overridden using the MaximumResponseHeadersLength property.
  620.         /// </remarks>
  621.         /// </devdoc>
  622.         public static int DefaultMaximumResponseHeadersLength {
  623.             get {
  624.                 #if DEBUG
  625.                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  626.                     #endif
  627.                     return SettingsSectionInternal.Section.MaximumResponseHeadersLength;
  628.                     #if DEBUG
  629.                 }
  630.                 #endif
  631.             }
  632.             set {
  633.                 #if DEBUG
  634.                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  635.                     #endif
  636.                     ExceptionHelper.WebPermissionUnrestricted.Demand();
  637.                     if (value < 0 && value != -1) {
  638.                         throw new ArgumentOutOfRangeException(SR.GetString(SR.net_toosmall));
  639.                     }
  640.                     SettingsSectionInternal.Section.MaximumResponseHeadersLength = value;
  641.                     #if DEBUG
  642.                 }
  643.                 #endif
  644.             }
  645.         }
  646.        
  647.         public static int DefaultMaximumErrorResponseLength {
  648.             get { return SettingsSectionInternal.Section.MaximumErrorResponseLength; }
  649.             set {
  650.                 ExceptionHelper.WebPermissionUnrestricted.Demand();
  651.                 if (value < 0 && value != -1) {
  652.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_toosmall));
  653.                 }
  654.                 SettingsSectionInternal.Section.MaximumErrorResponseLength = value;
  655.             }
  656.         }
  657.        
  658.         /// <devdoc>
  659.         /// <para>
  660.         /// Gets or sets the maximum allowed length of the response headers.
  661.         /// </para>
  662.         /// <remarks>
  663.         /// The length is measured in kilobytes (1024 bytes) and it includes the response status line and the response
  664.         /// headers as well as all extra control characters received as part of the HTTP protocol. A value of -1 means
  665.         /// no such limit will be imposed on the response headers, a value of 0 means that all requests will fail.
  666.         /// </remarks>
  667.         /// </devdoc>
  668.         public int MaximumResponseHeadersLength {
  669.             get { return _MaximumResponseHeadersLength; }
  670.             set {
  671.                 if (RequestSubmitted) {
  672.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  673.                 }
  674.                 if (value < 0 && value != -1) {
  675.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_toosmall));
  676.                 }
  677.                 _MaximumResponseHeadersLength = value;
  678.             }
  679.         }
  680.        
  681.         //
  682.         // AbortDelegate - set by ConnectionGroup when
  683.         // the request is blocked waiting for a Connection
  684.         //
  685.         internal HttpAbortDelegate AbortDelegate {
  686.             set { _AbortDelegate = value; }
  687.         }
  688.        
  689.         // This is invoked by the Connection whenever we get access to Write to the Connection
  690.         internal LazyAsyncResult ConnectionAsyncResult {
  691.             get { return _ConnectionAResult; }
  692.         }
  693.        
  694.         // This is invoked by the Connection whenever we get to Read from the Connection
  695.         internal LazyAsyncResult ConnectionReaderAsyncResult {
  696.             get { return _ConnectionReaderAResult; }
  697.         }
  698.        
  699.         private bool UserRetrievedWriteStream {
  700.             get { return _WriteAResult != null && _WriteAResult.InternalPeekCompleted; }
  701.         }
  702.        
  703.         // True if we're being used in an async manner
  704.         internal bool Async {
  705. // So Long as we've not been set to false, we operate as an async request
  706.             get { return _RequestIsAsync != TriState.False; }
  707.             set {
  708.                 if (_RequestIsAsync == TriState.Unspecified) {
  709.                     _RequestIsAsync = value ? TriState.True : TriState.False;
  710.                 }
  711.             }
  712.         }
  713.        
  714.         //
  715.         // UnlockConnectionDelegate - set by the Connection
  716.         // iff the Request is asking for exclusive access (ie LockConnection == true)
  717.         // in this case UnlockConnectionDelegate must be called when the Request
  718.         // has finished authentication.
  719.         //
  720.         internal UnlockConnectionDelegate UnlockConnectionDelegate {
  721.             get { return _UnlockDelegate; }
  722.             set { _UnlockDelegate = value; }
  723.         }
  724.        
  725.         private bool UsesProxy {
  726.             get { return ServicePoint.InternalProxyServicePoint; }
  727.         }
  728.        
  729.         internal HttpStatusCode ResponseStatusCode {
  730.             get { return _HttpResponse.StatusCode; }
  731.         }
  732.        
  733.         internal bool UsesProxySemantics {
  734.             get { return ServicePoint.InternalProxyServicePoint && (((object)_Uri.Scheme != (object)Uri.UriSchemeHttps) || (IsTunnelRequest)); }
  735.         }
  736.        
  737.         internal Uri ChallengedUri {
  738.             get { return CurrentAuthenticationState.ChallengedUri; }
  739.         }
  740.        
  741.         internal AuthenticationState ProxyAuthenticationState {
  742.             get {
  743.                 if (_ProxyAuthenticationState == null) {
  744.                     _ProxyAuthenticationState = new AuthenticationState(true);
  745.                 }
  746.                 return _ProxyAuthenticationState;
  747.             }
  748.         }
  749.        
  750.         internal AuthenticationState ServerAuthenticationState {
  751.             get {
  752.                 if (_ServerAuthenticationState == null) {
  753.                     _ServerAuthenticationState = new AuthenticationState(false);
  754.                 }
  755.                 return _ServerAuthenticationState;
  756.             }
  757.             set { _ServerAuthenticationState = value; }
  758.         }
  759.        
  760.         // the AuthenticationState we're using for authentication (proxy/server)
  761.         // used to match entries in the Hashtable in NtlmClient & NegotiateClient
  762.         internal AuthenticationState CurrentAuthenticationState {
  763.             get { return m_IsCurrentAuthenticationStateProxy ? _ProxyAuthenticationState : _ServerAuthenticationState; }
  764.             set { m_IsCurrentAuthenticationStateProxy = (object)_ProxyAuthenticationState == (object)value; }
  765.         }
  766.        
  767.        
  768.         /// <devdoc>
  769.         /// <para>[To be supplied.]</para>
  770.         /// </devdoc>
  771.         public CookieContainer CookieContainer {
  772.             get { return _CookieContainer; }
  773.             set { _CookieContainer = value; }
  774.         }
  775.        
  776.         /// <devdoc>
  777.         /// <para>
  778.         /// Gets the original Uri of the request.
  779.         /// This read-only propery returns the Uri for this request. The
  780.         /// Uri object was created by the constructor and is always non-null.
  781.         ///
  782.         /// Note that it will always be the base Uri, and any redirects,
  783.         /// or such will not be indicated.
  784.         /// </para>
  785.         /// </devdoc>
  786.         public override Uri RequestUri {
  787.             // read-only
  788.             get { return _OriginUri; }
  789.         }
  790.        
  791. /*
  792.             Accessor:  ContentLength
  793.             The property that controls the Content-Length of the request entity
  794.             body. Getting this property returns the last value set, or -1 if
  795.             no value has been set. Setting it sets the content length, and
  796.             the application must write that much data to the stream.
  797.             Setting this property has a side effect on InternalSendChunked, it sets it to false.
  798.             Input:
  799.                 Content length
  800.             Returns: The value of the content length on get.
  801.         */       
  802.        
  803.         /// <devdoc>
  804.         /// <para>
  805.         /// Gets or sets the Content-Length header of the request.
  806.         /// </para>
  807.         /// </devdoc>
  808.         public override long ContentLength {
  809.             get { return _ContentLength; }
  810.             set {
  811.                 if (RequestSubmitted) {
  812.                     throw new InvalidOperationException(SR.GetString(SR.net_writestarted));
  813.                 }
  814.                 if (value < 0) {
  815.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_clsmall));
  816.                 }
  817.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ContentLength_set() was:" + _ContentLength + " now:" + value);
  818.                 _ContentLength = value;
  819.             }
  820.         }
  821.        
  822.         /// <devdoc>
  823.         /// <para>Timeout is set to 100 seconds by default</para>
  824.         /// </devdoc>
  825.         public override int Timeout {
  826.             get { return _Timeout; }
  827.             set {
  828.                 if (value < 0 && value != System.Threading.Timeout.Infinite) {
  829.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_io_timeout_use_ge_zero));
  830.                 }
  831.                 if (_Timeout != value) {
  832.                     _Timeout = value;
  833.                     _TimerQueue = null;
  834.                 }
  835.             }
  836.         }
  837.        
  838.         private TimerThread.Queue TimerQueue {
  839.             get {
  840.                 TimerThread.Queue queue = _TimerQueue;
  841.                 if (queue == null) {
  842.                     queue = TimerThread.GetOrCreateQueue(_Timeout == 0 ? 1 : _Timeout);
  843.                     _TimerQueue = queue;
  844.                 }
  845.                 return queue;
  846.             }
  847.         }
  848.        
  849.         /// <devdoc>
  850.         /// <para>Used to control the Timeout when calling Stream.Read (AND) Stream.Write.
  851.         /// Effects Streams returned from GetResponse().GetResponseStream() (AND) GetRequestStream().
  852.         /// Default is 5 mins.
  853.         /// </para>
  854.         /// </devdoc>
  855.         public int ReadWriteTimeout {
  856.             get { return _ReadWriteTimeout; }
  857.             set {
  858.                 if (RequestSubmitted) {
  859.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  860.                 }
  861.                 if (value <= 0 && value != System.Threading.Timeout.Infinite) {
  862.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_io_timeout_use_gt_zero));
  863.                 }
  864.                 _ReadWriteTimeout = value;
  865.             }
  866.         }
  867.        
  868.        
  869.         internal long SwitchToContentLength()
  870.         {
  871.             //prevents clearing of transferencoding if we can't resubmit.
  872.             if (HaveResponse) {
  873.                 return -1;
  874.             }
  875.            
  876.            
  877.             //we should only switch to content length if the server is unknown of less than IIS6.0
  878.             //we only do this if it was orginially chunked. If it was bufferonly, we should allow the switch
  879.             if (HttpWriteMode == HttpWriteMode.Chunked) {
  880.                 ConnectStream stream = _OldSubmitWriteStream;
  881.                 if (stream == null) {
  882.                     stream = _SubmitWriteStream;
  883.                 }
  884.                 if (stream.Connection != null && stream.Connection.IISVersion >= 6) {
  885.                     return -1;
  886.                 }
  887.             }
  888.            
  889.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SwitchToContentLength() Switching to HttpWriteMode.ContentLength from:" + HttpWriteMode.ToString());
  890.            
  891.             long returnValue = -1;
  892.             long oldContentLength = _ContentLength;
  893.            
  894.             if (HttpWriteMode != HttpWriteMode.None) {
  895.                
  896.                 if (HttpWriteMode == HttpWriteMode.Buffer) {
  897.                     _ContentLength = _SubmitWriteStream.BufferedData.Length;
  898.                     m_OriginallyBuffered = true;
  899.                     HttpWriteMode = HttpWriteMode.ContentLength;
  900.                     return -1;
  901.                 }
  902.                
  903.                 //1st ntlm leg w/ preauthenticated connection
  904.                 // we don't have data yet
  905.                 if (NtlmKeepAlive && _OldSubmitWriteStream == null) {
  906.                     _ContentLength = 0;
  907.                     _SubmitWriteStream.SuppressWrite = true;
  908.                    
  909.                     //if this was previously a bufferonly request, we won't set the contentlength
  910.                     //back after header serialization
  911.                     if (_SubmitWriteStream.BufferOnly != true) {
  912.                         returnValue = oldContentLength;
  913.                     }
  914.                    
  915.                     if (HttpWriteMode == HttpWriteMode.Chunked) {
  916.                         HttpWriteMode = HttpWriteMode.ContentLength;
  917.                         _SubmitWriteStream.SwitchToContentLength();
  918.                         //restore request settings after headers are serialized
  919.                         returnValue = -2;
  920.                         _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.TransferEncoding);
  921.                     }
  922.                 }
  923.                
  924.                 //this is a resubmit w/ data already available
  925.                 if (_OldSubmitWriteStream != null) {
  926.                     //first ntlm leg after noauth
  927.                     if (NtlmKeepAlive) {
  928.                         _ContentLength = 0;
  929.                     }
  930.                     //2nd leg of ntlm, or resubmit for chunked on <IIS6.0
  931.                     else if (_ContentLength == 0 || HttpWriteMode == HttpWriteMode.Chunked) {
  932.                         _ContentLength = _OldSubmitWriteStream.BufferedData.Length;
  933.                     }
  934.                    
  935.                     //Chunked rerequests should always be contentlength
  936.                     if (HttpWriteMode == HttpWriteMode.Chunked) {
  937.                         HttpWriteMode = HttpWriteMode.ContentLength;
  938.                         _SubmitWriteStream.SwitchToContentLength();
  939.                         _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.TransferEncoding);
  940.                     }
  941.                 }
  942.             }
  943.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SwitchToContentLength() ContentLength was:" + oldContentLength + " now:" + _ContentLength.ToString() + " returning:" + returnValue);
  944.             return returnValue;
  945.         }
  946.        
  947.        
  948.         void PostSwitchToContentLength(long value)
  949.         {
  950.             if (value > -1) {
  951.                 _ContentLength = value;
  952.             }
  953.             if (value == -2) {
  954.                 _ContentLength = -1;
  955.                 HttpWriteMode = HttpWriteMode.Chunked;
  956.             }
  957.         }
  958.        
  959.         /// <devdoc>
  960.         /// <para>
  961.         /// Removes the ConnectionGroup and the Connection resources
  962.         /// held open usually do to NTLM operations.
  963.         /// </para>
  964.         /// </devdoc>
  965.         private void ClearAuthenticatedConnectionResources()
  966.         {
  967.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::ClearAuthenticatedConnectionResources()");
  968.            
  969.             if (ProxyAuthenticationState.UniqueGroupId != null || ServerAuthenticationState.UniqueGroupId != null) {
  970.                 GlobalLog.Assert(!UnsafeAuthenticatedConnectionSharing, "Created a unique connection AND UnsafeConnectionNtlmAuthentication is true.");
  971.                 // A unique connection was create so we must tear it down or it gets leaked
  972.                 ServicePoint.ReleaseConnectionGroup(GetConnectionGroupLine());
  973.             }
  974.            
  975.             UnlockConnectionDelegate unlockConnectionDelegate = this.UnlockConnectionDelegate;
  976.             try {
  977.                 if (unlockConnectionDelegate != null) {
  978.                     unlockConnectionDelegate();
  979.                 }
  980.                 this.UnlockConnectionDelegate = null;
  981.             }
  982.             catch (Exception exception) {
  983.                 if (NclUtilities.IsFatal(exception))
  984.                     throw;
  985.             }
  986.             catch {
  987.             }
  988.            
  989.             ProxyAuthenticationState.ClearSession(this);
  990.             ServerAuthenticationState.ClearSession(this);
  991.         }
  992.        
  993.         //
  994.         // Is set to true under the _connection_ lock to indicate that header are written
  995.         // Is set to false when we start submitting
  996.         //
  997.         internal bool HeadersCompleted {
  998.             get { return m_HeadersCompleted; }
  999.             set { m_HeadersCompleted = value; }
  1000.         }
  1001.        
  1002.         // This method checks the consistency of the protocol usage.
  1003.         // It also might adjust the upload behaviour to comply with what the server supports.
  1004.         private void CheckProtocol(bool onRequestStream)
  1005.         {
  1006.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckProtocol(" + onRequestStream + ") HttpWriteMode:" + HttpWriteMode + " SendChunked:" + SendChunked + " ContentLength:" + ContentLength);
  1007.             if (!CanGetRequestStream) {
  1008.                 if (onRequestStream) {
  1009.                     // prevent someone from getting a request stream, if the protocol verb/method doesn't support it
  1010.                     throw new ProtocolViolationException(SR.GetString(SR.net_nouploadonget));
  1011.                 }
  1012.                 else {
  1013.                     // prevent someone from setting ContentLength/Chunked, and then doing a Get
  1014.                     if (HttpWriteMode != HttpWriteMode.Unknown && HttpWriteMode != HttpWriteMode.None) {
  1015.                         throw new ProtocolViolationException(SR.GetString(SR.net_nocontentlengthonget));
  1016.                     }
  1017.                     // GET & HEAD requests will end up here
  1018.                     HttpWriteMode = HttpWriteMode.None;
  1019.                 }
  1020.             }
  1021.             else {
  1022.                 if (HttpWriteMode == HttpWriteMode.Unknown) {
  1023.                     if (SendChunked) {
  1024.                         // prevent someone from sending chunked to a HTTP/1.0 server
  1025.                         if (ServicePoint.HttpBehaviour == HttpBehaviour.HTTP11 || ServicePoint.HttpBehaviour == HttpBehaviour.Unknown) {
  1026.                             HttpWriteMode = HttpWriteMode.Chunked;
  1027.                         }
  1028.                         else {
  1029.                             if (AllowWriteStreamBuffering) {
  1030.                                 // change this request to buffer instead of using chunking
  1031.                                 HttpWriteMode = HttpWriteMode.Buffer;
  1032.                             }
  1033.                             else {
  1034.                                 throw new ProtocolViolationException(SR.GetString(SR.net_nochunkuploadonhttp10));
  1035.                             }
  1036.                         }
  1037.                     }
  1038.                     else {
  1039.                         // we need to do some fixups if we don't have a HttpWriteMode
  1040.                         // unknown verbs (like TRACE) will also end up here. since we don't know if we need to send
  1041.                         // a content we'll assume we won't and upload will work only if ContentLength or Chunked
  1042.                         // were set. note that this means that we won't ever buffer for unknown verbs unless
  1043.                         // you call [Begin]GetRequestStream before [Begin]GetResponse.
  1044.                         HttpWriteMode = ContentLength >= 0 ? HttpWriteMode.ContentLength : onRequestStream ? HttpWriteMode.Buffer : HttpWriteMode.None;
  1045.                     }
  1046.                 }
  1047.             }
  1048.             if (HttpWriteMode != HttpWriteMode.Chunked) {
  1049.                 if (onRequestStream && ContentLength == -1 && !AllowWriteStreamBuffering && KeepAlive) {
  1050.                     // Missing Entity Body Delimiter:
  1051.                     // prevent someone from trying to send data without setting
  1052.                     // a ContentLength or InternalSendChunked when buffering is disabled and on a KeepAlive connection
  1053.                     throw new ProtocolViolationException(SR.GetString(SR.net_contentlengthmissing));
  1054.                 }
  1055.                 if (!ValidationHelper.IsBlankString(TransferEncoding)) {
  1056.                     // Transfer Encoding Without Chunked
  1057.                     // prevent someone from setting a Transfer Encoding without having InternalSendChunked==true
  1058.                     throw new InvalidOperationException(SR.GetString(SR.net_needchunked));
  1059.                 }
  1060.             }
  1061.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckProtocol(" + onRequestStream + ") no error, returning null. HttpWriteMode:" + HttpWriteMode + " SendChunked:" + SendChunked + " ContentLength:" + ContentLength);
  1062.             return;
  1063.         }
  1064.        
  1065.        
  1066.         /// <devdoc>
  1067.         /// <para>
  1068.         /// Retreives the Request Stream from an HTTP Request uses an Async
  1069.         /// operation to do this, and the result is retrived async.
  1070.         ///
  1071.         /// Async operations include work in progess, this call is used to retrieve
  1072.         /// results by pushing the async operations to async worker thread on the callback.
  1073.         /// There are many open issues involved here including the handling of possible blocking
  1074.         /// within the bounds of the async worker thread or the case of Write and Read stream
  1075.         /// operations still blocking.
  1076.         /// </para>
  1077.         /// </devdoc>
  1078.         [HostProtection(ExternalThreading = true)]
  1079.         public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state)
  1080.         {
  1081.             #if DEBUG
  1082.             using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  1083.                 #endif
  1084.                 GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetRequestStream");
  1085.                 if (Logging.On)
  1086.                     Logging.Enter(Logging.Web, this, "BeginGetRequestStream", "");
  1087.                
  1088.                 CheckProtocol(true);
  1089.                
  1090.                 ContextAwareResult asyncResult = new ContextAwareResult(false, true, this, state, callback);
  1091.                
  1092.                
  1093.                 lock (asyncResult.StartPostingAsyncOp()) {
  1094.                     // and have a result (weird but was supported in V1.X as repeated calls for the submit stream.
  1095.                     if (_WriteAResult != null && _WriteAResult.InternalPeekCompleted) {
  1096.                         if (_WriteAResult.Result is Exception) {
  1097.                             throw (Exception)_WriteAResult.Result;
  1098.                         }
  1099.                        
  1100.                         try {
  1101.                             asyncResult.InvokeCallback(_WriteAResult.Result);
  1102.                         }
  1103.                         catch (Exception e) {
  1104.                             Abort(e, AbortState.Public);
  1105.                             throw;
  1106.                         }
  1107.                     }
  1108.                     else {
  1109.                         // prevent new requests when low on resources
  1110.                         if (!RequestSubmitted && NclUtilities.IsThreadPoolLow()) {
  1111.                             Exception exception = new InvalidOperationException(SR.GetString(SR.net_needmorethreads));
  1112.                             Abort(exception, AbortState.Public);
  1113.                             throw exception;
  1114.                         }
  1115.                        
  1116.                         lock (this) {
  1117.                             if (_WriteAResult != null) {
  1118.                                 throw new InvalidOperationException(SR.GetString(SR.net_repcall));
  1119.                             }
  1120.                            
  1121.                             // See if we're already submitted a request (e.g. via GetResponse).
  1122.                             if (SetRequestSubmitted()) {
  1123.                                 // Not completed write stream, this is an application error.
  1124.                                 throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  1125.                             }
  1126.                            
  1127.                             // If there's already been a _ReadAResult completed, it better have been with an exception, like an abort.
  1128.                             // We need to check within this lock. Before the lock, _WriteAResult didn't exist so won't have been notified.
  1129.                             // BeginSubmitRequest() will fail silently if we go ahead and call it after an abort. Since we know this is the
  1130.                             // first call to any of the [Begin]GetRe... methods by the above checks, we know ProcessResponse can't have been
  1131.                             // called or any other valid _ReadAResult created yet.
  1132.                             if (_ReadAResult != null) {
  1133.                                 GlobalLog.Assert(_ReadAResult.InternalPeekCompleted, "HttpWebRequest#{0}::BeginGetRequestStream()|Incomplete _ReadAResult present on request.", ValidationHelper.HashString(this));
  1134.                                 GlobalLog.Assert(_ReadAResult.Result is Exception, "HttpWebRequest#{0}::BeginGetRequestStream()|_ReadAResult with successful completion already present on request.", ValidationHelper.HashString(this));
  1135.                                 throw (Exception)_ReadAResult.Result;
  1136.                             }
  1137.                            
  1138.                             // get async going
  1139.                             _WriteAResult = asyncResult;
  1140.                             Async = true;
  1141.                         }
  1142.                        
  1143.                         // OK, we haven't submitted the request yet, so do so now
  1144.                         // save off verb from origin Verb
  1145.                         GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetRequestStream() resetting CurrentMethod to " + _OriginVerb);
  1146.                         CurrentMethod = _OriginVerb;
  1147.                         BeginSubmitRequest();
  1148.                     }
  1149.                    
  1150.                     asyncResult.FinishPostingAsyncOp();
  1151.                 }
  1152.                
  1153.                 GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetRequestStream", ValidationHelper.HashString(asyncResult));
  1154.                 if (Logging.On)
  1155.                     Logging.Exit(Logging.Web, this, "BeginGetRequestStream", asyncResult);
  1156.                 return asyncResult;
  1157.                 #if DEBUG
  1158.             }
  1159.             #endif
  1160.         }
  1161.        
  1162.         /// <devdoc>
  1163.         /// <para>Retreives the Request Stream after an Async operation has completed </para>
  1164.         /// </devdoc>
  1165.         public override Stream EndGetRequestStream(IAsyncResult asyncResult)
  1166.         {
  1167.             #if DEBUG
  1168.             using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
  1169.                 #endif
  1170.                 GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetRequestStream", ValidationHelper.HashString(asyncResult));
  1171.                 if (Logging.On)
  1172.                     Logging.Enter(Logging.Web, this, "EndGetRequestStream", "");
  1173.                
  1174.                 //
  1175.                 // parameter validation
  1176.                 //
  1177.                 if (asyncResult == null) {
  1178.                     throw new ArgumentNullException("asyncResult");
  1179.                 }
  1180.                 LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult;
  1181.                 if (castedAsyncResult == null || castedAsyncResult.AsyncObject != this) {
  1182.                     throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  1183.                 }
  1184.                 if (castedAsyncResult.EndCalled) {
  1185.                     throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetRequestStream"));
  1186.                 }
  1187.                
  1188.                 ConnectStream connectStream = castedAsyncResult.InternalWaitForCompletion() as ConnectStream;
  1189.                 castedAsyncResult.EndCalled = true;
  1190.                
  1191.                 if (connectStream == null) {
  1192.                     if (Logging.On)
  1193.                         Logging.Exception(Logging.Web, this, "EndGetRequestStream", castedAsyncResult.Result as Exception);
  1194.                     throw (Exception)castedAsyncResult.Result;
  1195.                 }
  1196.                
  1197.                 // Otherwise it worked, so return the HttpWebResponse.
  1198.                 GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetRequestStream", ValidationHelper.HashString(connectStream));
  1199.                 if (Logging.On)
  1200.                     Logging.Exit(Logging.Web, this, "EndGetRequestStream", connectStream);
  1201.                 return connectStream;
  1202.                 #if DEBUG
  1203.             }
  1204.             #endif
  1205.         }
  1206.        
  1207.         /// <devdoc>
  1208.         /// <para>Gets a <see cref='System.IO.Stream'/> that the application can use to write request data.
  1209.         /// This property returns a stream that the calling application can write on.
  1210.         /// This property is not settable. Getting this property may cause the
  1211.         /// request to be sent, if it wasn't already. Getting this property after
  1212.         /// a request has been sent that doesn't have an entity body causes an
  1213.         /// exception to be thrown.
  1214.         ///</para>
  1215.         /// </devdoc>
  1216.         public override Stream GetRequestStream()
  1217.         {
  1218.             #if DEBUG
  1219.             using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) {
  1220.                 #endif
  1221.                 GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetRequestStream");
  1222.                 if (Logging.On)
  1223.                     Logging.Enter(Logging.Web, this, "GetRequestStream", "");
  1224.                
  1225.                 CheckProtocol(true);
  1226.                
  1227.                 // See if we're already submitted a request and have a result cached.
  1228.                 if (_WriteAResult == null || !_WriteAResult.InternalPeekCompleted) {
  1229.                     lock (this) {
  1230.                         if (_WriteAResult != null) {
  1231.                             throw new InvalidOperationException(SR.GetString(SR.net_repcall));
  1232.                         }
  1233.                        
  1234.                         // See if we're already submitted a request (e.g. via GetResponse).
  1235.                         if (SetRequestSubmitted()) {
  1236.                             // Not completed write stream, this is an application error.
  1237.                             throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  1238.                         }
  1239.                        
  1240.                         // If there's already been a _ReadAResult completed, it better have been with an exception, like an abort.
  1241.                         // We need to check within this lock. Before the lock, _WriteAResult didn't exist so won't have been notified.
  1242.                         // BeginSubmitRequest() will fail silently if we go ahead and call it after an abort. Since we know this is the
  1243.                         // first call to any of the [Begin]GetRe... methods by the above checks, we know ProcessResponse can't have been
  1244.                         // called or any other valid _ReadAResult created yet.
  1245.                         if (_ReadAResult != null) {
  1246.                             GlobalLog.Assert(_ReadAResult.InternalPeekCompleted, "HttpWebRequest#{0}::GetRequestStream()|Incomplete _ReadAResult present on request.", ValidationHelper.HashString(this));
  1247.                             GlobalLog.Assert(_ReadAResult.Result is Exception, "HttpWebRequest#{0}::GetRequestStream()|_ReadAResult with successful completion already present on request.", ValidationHelper.HashString(this));
  1248.                             throw (Exception)_ReadAResult.Result;
  1249.                         }
  1250.                        
  1251.                         // use the AsyncResult to return our Stream
  1252.                         _WriteAResult = new LazyAsyncResult(this, null, null);
  1253.                         Async = false;
  1254.                     }
  1255.                    
  1256.                     // OK, we haven't submitted the request yet, so do so now
  1257.                     // save off verb from origin Verb
  1258.                     GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "GetRequestStream() resetting CurrentMethod to " + _OriginVerb);
  1259.                     CurrentMethod = _OriginVerb;
  1260.                    
  1261.                     // Submit the Request, causes us to queue ourselves to a Connection and may block
  1262.                     // It has happened that Sync path uses this loop the Retry memeber for handling resubmissions.
  1263.                     while (m_Retry && !_WriteAResult.InternalPeekCompleted) {
  1264.                         _OldSubmitWriteStream = null;
  1265.                         _SubmitWriteStream = null;
  1266.                         BeginSubmitRequest();
  1267.                     }
  1268.                    
  1269.                     while (Aborted && !_WriteAResult.InternalPeekCompleted) {
  1270.                         // spin untill the _CoreResponse is set
  1271.                         if (!(_CoreResponse is Exception))
  1272.                             Thread.SpinWait(1);
  1273.                         else
  1274.                             CheckWriteSideResponseProcessing();
  1275.                     }
  1276.                 }
  1277.                
  1278.                 ConnectStream connectStream = _WriteAResult.InternalWaitForCompletion() as ConnectStream;
  1279.                 _WriteAResult.EndCalled = true;
  1280.                 if (connectStream == null) {
  1281.                     if (Logging.On)
  1282.                         Logging.Exception(Logging.Web, this, "EndGetRequestStream", _WriteAResult.Result as Exception);
  1283.                     throw (Exception)_WriteAResult.Result;
  1284.                 }
  1285.                
  1286.                 if (Logging.On)
  1287.                     Logging.Exit(Logging.Web, this, "GetRequestStream", connectStream);
  1288.                 GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetRequestStream", ValidationHelper.HashString(connectStream));
  1289.                 return connectStream;
  1290.                 #if DEBUG
  1291.             }
  1292.             #endif
  1293.         }
  1294.        
  1295.        
  1296.         //
  1297.         // This read-only propery does a test against the object to verify that
  1298.         // we're not sending data with a GET or HEAD, these are dissallowed by the HTTP spec.
  1299.         // Returns: true if we allow sending data for this request, false otherwise
  1300.         //
  1301.         private bool CanGetRequestStream {
  1302.             get {
  1303.                 bool result = !CurrentMethod.ContentBodyNotAllowed;
  1304.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CanGetRequestStream(" + _OriginVerb + "): " + result);
  1305.                 return result;
  1306.             }
  1307.         }
  1308.        
  1309.         //
  1310.         // This read-only propery does a test against the object to verify if
  1311.         // we're allowed to get a Response Stream to read,
  1312.         // this is dissallowed per the HTTP spec for a HEAD request.
  1313.         // Returns: true if we allow sending data for this request, false otherwise
  1314.         //
  1315.         internal bool CanGetResponseStream {
  1316.             get {
  1317.                 bool result = !CurrentMethod.ExpectNoContentResponse;
  1318.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CanGetResponseStream(" + CurrentMethod + "): " + result);
  1319.                 return result;
  1320.             }
  1321.         }
  1322.        
  1323.         //
  1324.         // This read-only propery describes whether we can
  1325.         // send this verb without content data.
  1326.         // Assumes Method is already set.
  1327.         // Returns: true, if we must send some kind of content
  1328.         //
  1329.         internal bool RequireBody {
  1330.             get {
  1331.                 bool result = CurrentMethod.RequireContentBody;
  1332.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::RequireBody(" + CurrentMethod + "): " + result);
  1333.                 return result;
  1334.             }
  1335.         }
  1336.        
  1337. /*++
  1338.             CheckBuffering - Determine if we need buffering based on having no contentlength
  1339.                 consider the case in which we have no entity body delimiters:
  1340.                     RequireBody && ContentLength==-1 && !SendChunked == true
  1341.                 now we need to consider 3 cases:
  1342.                 AllowWriteStreamBuffering (1)
  1343.                     - buffer internally all the data written to the request stream when the user
  1344.                       closes the request stream send it on the wire with a ContentLength
  1345.                 !AllowWriteStreamBuffering
  1346.                     - can't buffer internally all the data written to the request stream
  1347.                       so the data MUST go to the wire and the server sees it: 2 cases
  1348.                     !KeepAlive (2)
  1349.                         - send a "Connection: close" header to the server. the server SHOULD
  1350.                           1) send a final response
  1351.                           2) read all the data on the connection and treat it as being part of the
  1352.                             entity body of this request.
  1353.                     KeepAlive (3)
  1354.                         - throw, we can't do this, 'cause the server wouldn't know when the data is over.
  1355.             Input:
  1356.                     None.
  1357.             Returns:
  1358.                     true if we need buffering, false otherwise.
  1359.         --*/       
  1360.        
  1361. /*
  1362.         //                                   
  1363.         internal bool CheckBuffering {
  1364.             //
  1365.             // ContentLength is not set, and user is not chunking, buffering is on
  1366.             // so force the code into writing (give the user a stream to write to)
  1367.             // and we'll buffer for him
  1368.             //
  1369.             get {
  1370.                 bool checkBuffering = RequireBody && ContentLength==-1 && HttpWriteMode!=HttpWriteMode.Chunked && AllowWriteStreamBuffering && ServicePoint.HttpBehaviour!=HttpBehaviour.HTTP11;
  1371.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckBuffering() returns:" + checkBuffering.ToString());
  1372.                 return checkBuffering;
  1373.             }
  1374.         }
  1375.         */       
  1376.        
  1377.         private bool HasEntityBody {
  1378.             get { return HttpWriteMode == HttpWriteMode.Chunked || HttpWriteMode == HttpWriteMode.Buffer || (HttpWriteMode == HttpWriteMode.ContentLength && ContentLength > 0); }
  1379.         }
  1380.        
  1381.        
  1382.         // This is a notify from the connection ReadCallback about
  1383.         // - error response received and
  1384.         // - the KeepAlive status agreed by both sides
  1385.         internal void ErrorStatusCodeNotify(Connection connection, bool isKeepAlive, bool fatal)
  1386.         {
  1387.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::ErrorStatusCodeNotify");
  1388.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ErrorStatusCodeNotify() Connection has reported Error Response Status" + (fatal ? " (fatal)" : ""));
  1389.             ConnectStream submitStream = _SubmitWriteStream;
  1390.             if (submitStream != null && submitStream.Connection == connection) {
  1391.                 if (!fatal) {
  1392.                     submitStream.ErrorResponseNotify(isKeepAlive);
  1393.                 }
  1394.                 else {
  1395.                     if (!Aborted) {
  1396.                         submitStream.FatalResponseNotify();
  1397.                     }
  1398.                 }
  1399.             }
  1400.             else {
  1401.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ErrorStatusCodeNotify() IGNORE connection is not used");
  1402.             }
  1403.         }
  1404.        
  1405. /*
  1406.             Method: DoSubmitRequestProcessing
  1407.             Does internal processing of redirect and request retries for authentication
  1408.             Assumes that it cannot block, this returns a state var indicating when it
  1409.             needs to block
  1410.             Assumes that we are never called with a null response
  1411.             Input:
  1412.                 none
  1413.             Returns:
  1414.                 HttpProcessingResult -
  1415.         */       
  1416.        
  1417.         //
  1418.         // ASSUMPTION: If this method throws the exception must be caught and handled
  1419.         // appropriatelly by the caller.
  1420.         //
  1421.         private HttpProcessingResult DoSubmitRequestProcessing(ref Exception exception)
  1422.         {
  1423.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::DoSubmitRequestProcessing");
  1424.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::ErrorStatusCodeNotify");
  1425.             HttpProcessingResult result = HttpProcessingResult.Continue;
  1426.            
  1427.             m_Retry = false;
  1428.            
  1429.             try {
  1430.                 //
  1431.                 // We have a response of some sort, see if we need to resubmit
  1432.                 // it do to authentication, redirection or something
  1433.                 // else, then handle clearing out state and draining out old response.
  1434.                 //
  1435.                 if (_HttpResponse != null) {
  1436.                     // give apps the chance to examine the headers of the new response
  1437.                     if (_CookieContainer != null) {
  1438.                         CookieModule.OnReceivedHeaders(this);
  1439.                     }
  1440.                    
  1441.                     ProxyAuthenticationState.Update(this);
  1442.                     ServerAuthenticationState.Update(this);
  1443.                 }
  1444.                
  1445.                 bool resubmit = false;
  1446.                 bool checkNextProxy = true;
  1447.                 if (_HttpResponse == null) {
  1448.                     resubmit = true;
  1449.                 }
  1450.                 else if (CheckResubmitForCache(ref exception) || CheckResubmit(ref exception)) {
  1451.                     resubmit = true;
  1452.                     checkNextProxy = false;
  1453.                 }
  1454.                
  1455.                 ServicePoint servicePoint = null;
  1456.                 if (checkNextProxy) {
  1457.                     WebException webException = exception as WebException;
  1458.                     if (webException != null && webException.InternalStatus == WebExceptionInternalStatus.ServicePointFatal) {
  1459.                         ProxyChain chain = _ProxyChain;
  1460.                         if (chain != null) {
  1461.                             servicePoint = ServicePointManager.FindServicePoint(chain);
  1462.                         }
  1463.                         resubmit = servicePoint != null;
  1464.                     }
  1465.                 }
  1466.                
  1467.                 if (resubmit) {
  1468.                     GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::DoSubmitRequestProcessing() resubmiting this request.");
  1469.                    
  1470.                     if (CacheProtocol != null && _HttpResponse != null)
  1471.                         CacheProtocol.Reset();
  1472.                    
  1473.                     ClearRequestForResubmit();
  1474.                    
  1475.                     // In these cases, we don't know whether to keep the credentials for the follow-up request or not.
  1476.                     // Different auth schemes have different requirements. The typical case is to keep them - NTLM
  1477.                     // requires this path in order to work at all. But Kerberos for example can give a 401 here.
  1478.                     // Set a flag saying that if we get a 401, start over without credentials.
  1479.                     WebException e = exception as WebException;
  1480.                     if (e != null) {
  1481.                         if (e.Status == WebExceptionStatus.PipelineFailure || e.Status == WebExceptionStatus.KeepAliveFailure) {
  1482.                             m_Extra401Retry = true;
  1483.                         }
  1484.                     }
  1485.                    
  1486.                     if (servicePoint == null) {
  1487.                         servicePoint = FindServicePoint(true);
  1488.                     }
  1489.                     else {
  1490.                         _ServicePoint = servicePoint;
  1491.                     }
  1492.                    
  1493.                     if (Async) {
  1494.                         SubmitRequest(servicePoint);
  1495.                     }
  1496.                     else {
  1497.                         // under sync conditions, we let GetResponse() loop calling BeginSubmitRequest() until we're done
  1498.                         m_Retry = true;
  1499.                     }
  1500.                     result = HttpProcessingResult.WriteWait;
  1501.                 }
  1502.             }
  1503.             finally {
  1504.                 if (result == HttpProcessingResult.Continue) {
  1505.                     ClearAuthenticatedConnectionResources();
  1506.                 }
  1507.             }
  1508.            
  1509.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::DoSubmitRequestProcessing", result.ToString());
  1510.             return result;
  1511.         }
  1512.        
  1513.        
  1514.        
  1515.         /// <devdoc>
  1516.         /// <para>Used to query for the Response of an HTTP Request using Async</para>
  1517.         /// </devdoc>
  1518.         [HostProtection(ExternalThreading = true)]
  1519.         public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
  1520.         {
  1521.             #if DEBUG
  1522.             using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  1523.                 #endif
  1524.                 GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetResponse");
  1525.                 if (Logging.On)
  1526.                     Logging.Enter(Logging.Web, this, "BeginGetResponse", "");
  1527.                
  1528.                 CheckProtocol(false);
  1529.                
  1530.                 ConnectStream stream = _OldSubmitWriteStream != null ? _OldSubmitWriteStream : _SubmitWriteStream;
  1531.                
  1532.                 // Close the request stream if the user forgot to do that and all data is written.
  1533.                 if (stream != null && !stream.IsClosed && stream.BytesLeftToWrite == 0) {
  1534.                     stream.Close();
  1535.                 }
  1536.                
  1537.                 ContextAwareResult asyncResult = new ContextAwareResult(false, true, this, state, callback);
  1538.                
  1539.                 if (!RequestSubmitted && NclUtilities.IsThreadPoolLow()) {
  1540.                     // prevent new requests when low on resources
  1541.                     Exception exception = new InvalidOperationException(SR.GetString(SR.net_needmorethreads));
  1542.                     Abort(exception, AbortState.Public);
  1543.                     throw exception;
  1544.                 }
  1545.                
  1546.                 // Need to lock the context until it's created (if necessary) in Returning().
  1547.                 lock (asyncResult.StartPostingAsyncOp()) {
  1548.                     bool gotResponse = false;
  1549.                     bool requestSubmitted;
  1550.                     lock (this) {
  1551.                         requestSubmitted = SetRequestSubmitted();
  1552.                        
  1553.                         if (HaveResponse) {
  1554.                             gotResponse = true;
  1555.                         }
  1556.                         else {
  1557.                             if (_ReadAResult != null) {
  1558.                                 throw new InvalidOperationException(SR.GetString(SR.net_repcall));
  1559.                             }
  1560.                            
  1561.                             _ReadAResult = asyncResult;
  1562.                             Async = true;
  1563.                         }
  1564.                     }
  1565.                    
  1566.                     // Must check this after setting _ReadAResult, which holds the context which may be used for permission checks etc.
  1567.                     // See if we need to do the call-done processing here.
  1568.                     CheckDeferredCallDone(stream);
  1569.                    
  1570.                     if (gotResponse) {
  1571.                         if (Logging.On)
  1572.                             Logging.Exit(Logging.Web, this, "BeginGetResponse", _ReadAResult.Result);
  1573.                         GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetResponse", "Already Completed, response = " + ValidationHelper.HashString(_ReadAResult.Result));
  1574.                         Exception e = _ReadAResult.Result as Exception;
  1575.                         if (e != null) {
  1576.                             throw e;
  1577.                         }
  1578.                        
  1579.                         try {
  1580.                             asyncResult.InvokeCallback(_ReadAResult.Result);
  1581.                         }
  1582.                         catch (Exception exception) {
  1583.                             Abort(exception, AbortState.Public);
  1584.                             throw;
  1585.                         }
  1586.                     }
  1587.                     else {
  1588.                         // If we're here it's because we don't have the response yet. We may have
  1589.                         // already submitted the request, but if not do so now.
  1590.                         if (!requestSubmitted) {
  1591.                             // Save Off verb, and use it to make the request
  1592.                             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + ": resetting CurrentMethod to " + _OriginVerb);
  1593.                             CurrentMethod = _OriginVerb;
  1594.                         }
  1595.                        
  1596.                         // If we're here it's because we don't have the response yet. We may have
  1597.                         // already submitted the request, but if not do so now.
  1598.                         if (_RerequestCount > 0 || !requestSubmitted) {
  1599.                             while (m_Retry) {
  1600.                                 // Keep looping in case there are redirects, auth re-requests, etc
  1601.                                 BeginSubmitRequest();
  1602.                             }
  1603.                         }
  1604.                     }
  1605.                     asyncResult.FinishPostingAsyncOp();
  1606.                 }
  1607.                
  1608.                 GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetResponse", ValidationHelper.HashString(asyncResult));
  1609.                 if (Logging.On)
  1610.                     Logging.Exit(Logging.Web, this, "BeginGetResponse", asyncResult);
  1611.                 return asyncResult;
  1612.                 #if DEBUG
  1613.             }
  1614.             #endif
  1615.         }
  1616.        
  1617.         /// <devdoc>
  1618.         /// <para>Retreives the Response Result from an HTTP Result after an Async operation has completed</para>
  1619.         /// </devdoc>
  1620.         public override WebResponse EndGetResponse(IAsyncResult asyncResult)
  1621.         {
  1622.             #if DEBUG
  1623.             using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
  1624.                 #endif
  1625.                 GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse", ValidationHelper.HashString(asyncResult));
  1626.                 if (Logging.On)
  1627.                     Logging.Enter(Logging.Web, this, "EndGetResponse", "");
  1628.                
  1629.                 //
  1630.                 // parameter validation
  1631.                 //
  1632.                 if (asyncResult == null) {
  1633.                     throw new ArgumentNullException("asyncResult");
  1634.                 }
  1635.                
  1636.                 LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult;
  1637.                 if (castedAsyncResult == null || castedAsyncResult.AsyncObject != this) {
  1638.                     throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  1639.                 }
  1640.                 if (castedAsyncResult.EndCalled) {
  1641.                     throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetResponse"));
  1642.                 }
  1643.                
  1644.                 HttpWebResponse httpWebResponse = castedAsyncResult.InternalWaitForCompletion() as HttpWebResponse;
  1645.                 castedAsyncResult.EndCalled = true;
  1646.                
  1647.                 if (httpWebResponse == null) {
  1648.                     if (Logging.On)
  1649.                         Logging.Exception(Logging.Web, this, "EndGetResponse", castedAsyncResult.Result as Exception);
  1650.                     throw (Exception)castedAsyncResult.Result;
  1651.                 }
  1652.                
  1653.                 GlobalLog.Assert(httpWebResponse.ResponseStream != null, "HttpWebRequest#{0}::EndGetResponse()|httpWebResponse.ResponseStream == null", ValidationHelper.HashString(this));
  1654.                 // Otherwise it worked, so return the HttpWebResponse.
  1655.                 GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse", ValidationHelper.HashString(httpWebResponse));
  1656.                 if (Logging.On)
  1657.                     Logging.Exit(Logging.Web, this, "EndGetResponse", httpWebResponse);
  1658.                 return httpWebResponse;
  1659.                 #if DEBUG
  1660.             }
  1661.             #endif
  1662.         }
  1663.        
  1664.         private void CheckDeferredCallDone(ConnectStream stream)
  1665.         {
  1666.             object returnResult = Interlocked.Exchange(ref m_PendingReturnResult, DBNull.Value);
  1667.             if (returnResult == NclConstants.Sentinel) {
  1668.                 #if DEBUG
  1669.                 if (!Async) {
  1670.                     using (GlobalLog.SetThreadKind(ThreadKinds.Sync)) {
  1671.                         EndSubmitRequest();
  1672.                     }
  1673.                 }
  1674.                 else
  1675.                     #endif
  1676.                     EndSubmitRequest();
  1677.             }
  1678.             else if (returnResult != null && returnResult != DBNull.Value) {
  1679.                 // It could still be Missing.Value, which indicates ProcessWriteCallDone() should be called with null.
  1680.                 stream.ProcessWriteCallDone(returnResult as ConnectionReturnResult);
  1681.             }
  1682.         }
  1683.        
  1684.         /// <devdoc>
  1685.         /// <para>
  1686.         /// Returns a response from a request to an Internet resource.
  1687.         /// The response property. This property returns the WebResponse for this
  1688.         /// request. This may require that a request be submitted first.
  1689.         ///
  1690.         /// The idea is that we look and see if a request has already been
  1691.         /// submitted. If one has, we'll just return the existing response
  1692.         /// (if it's not null). If we haven't submitted a request yet, we'll
  1693.         /// do so now, possible multiple times while we handle redirects
  1694.         /// etc.
  1695.         /// </para>
  1696.         /// </devdoc>
  1697.         public override WebResponse GetResponse()
  1698.         {
  1699.             #if DEBUG
  1700.             using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) {
  1701.                 #endif
  1702.                 GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetResponse");
  1703.                 if (Logging.On)
  1704.                     Logging.Enter(Logging.Web, this, "GetResponse", "");
  1705.                
  1706.                 CheckProtocol(false);
  1707.                
  1708.                 // Many of these logics require GetResponse() to be called after all write-stream activity is done. You can't call it
  1709.                 // simultaneously on another thread and expect it to block until it can run. Doing that can cause the request to
  1710.                 // hang.
  1711.                
  1712.                 ConnectStream stream = _OldSubmitWriteStream != null ? _OldSubmitWriteStream : _SubmitWriteStream;
  1713.                
  1714.                 // Close the request stream if the user forgot to do that and all data is written.
  1715.                 if (stream != null && !stream.IsClosed && stream.BytesLeftToWrite == 0)
  1716.                     stream.Close();
  1717.                
  1718.                
  1719.                 // return response, if the response is already set
  1720.                 bool gotResponse = false;
  1721.                 HttpWebResponse httpWebResponse = null;
  1722.                 bool requestSubmitted;
  1723.                 lock (this) {
  1724.                     requestSubmitted = SetRequestSubmitted();
  1725.                     if (HaveResponse) {
  1726.                         gotResponse = true;
  1727.                         httpWebResponse = _ReadAResult.Result as HttpWebResponse;
  1728.                     }
  1729.                     else {
  1730.                         if (_ReadAResult != null) {
  1731.                             throw new InvalidOperationException(SR.GetString(SR.net_repcall));
  1732.                         }
  1733.                        
  1734.                         Async = false;
  1735.                        
  1736.                         // Since we don't really allow switching between sync and async, if the request is already async, this needs to
  1737.                         // capture context for use in the ongoing async operations as if it were BeginGetResponse().
  1738.                         if (Async) {
  1739.                             ContextAwareResult readResult = new ContextAwareResult(false, true, this, null, null);
  1740.                             readResult.StartPostingAsyncOp(false);
  1741.                             readResult.FinishPostingAsyncOp();
  1742.                             _ReadAResult = readResult;
  1743.                         }
  1744.                         else {
  1745.                             _ReadAResult = new LazyAsyncResult(this, null, null);
  1746.                         }
  1747.                     }
  1748.                 }
  1749.                
  1750.                 // See if we need to do the call-done processing here.
  1751.                 CheckDeferredCallDone(stream);
  1752.                
  1753.                 if (!gotResponse) {
  1754.                     //The previous call may have been async. If we are now doing a sync call, we should
  1755.                     //use the timeout
  1756.                     if (_Timer == null) {
  1757.                         _Timer = TimerQueue.CreateTimer(s_TimeoutCallback, this);
  1758.                     }
  1759.                    
  1760.                    
  1761.                     // Save Off verb, and use it to make the request
  1762.                     if (!requestSubmitted) {
  1763.                         GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + ": resetting CurrentMethod to " + _OriginVerb);
  1764.                         CurrentMethod = _OriginVerb;
  1765.                     }
  1766.                    
  1767.                     // If we're here it's because we don't have the response yet. We may have
  1768.                     // already submitted the request, but if not do so now.
  1769.                     while (m_Retry) {
  1770.                         // Keep looping in case there are redirects, auth re-requests, etc
  1771.                         BeginSubmitRequest();
  1772.                     }
  1773.                    
  1774.                     while (!Async && Aborted && !_ReadAResult.InternalPeekCompleted) {
  1775.                         // spin untill the _CoreResponse is set
  1776.                         if (!(_CoreResponse is Exception))
  1777.                             Thread.SpinWait(1);
  1778.                         else
  1779.                             CheckWriteSideResponseProcessing();
  1780.                     }
  1781.                    
  1782.                     httpWebResponse = _ReadAResult.InternalWaitForCompletion() as HttpWebResponse;
  1783.                     _ReadAResult.EndCalled = true;
  1784.                 }
  1785.                
  1786.                 if (httpWebResponse == null) {
  1787.                     if (Logging.On)
  1788.                         Logging.Exception(Logging.Web, this, "EndGetResponse", _ReadAResult.Result as Exception);
  1789.                     throw (Exception)_ReadAResult.Result;
  1790.                 }
  1791.                
  1792.                 GlobalLog.Assert(httpWebResponse.ResponseStream != null, "HttpWebRequest#{0}::GetResponse()|httpWebResponse.ResponseStream == null", ValidationHelper.HashString(this));
  1793.                 if (Logging.On)
  1794.                     Logging.Exit(Logging.Web, this, "GetResponse", httpWebResponse);
  1795.                 GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetResponse", ValidationHelper.HashString(httpWebResponse));
  1796.                 return httpWebResponse;
  1797.                 #if DEBUG
  1798.             }
  1799.             #endif
  1800.         }
  1801.        
  1802.         internal void WriteCallDone(ConnectStream stream, ConnectionReturnResult returnResult)
  1803.         {
  1804.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone()");
  1805.            
  1806.             // Make sure this is the user stream.
  1807.             if (!object.ReferenceEquals(stream, _OldSubmitWriteStream != null ? _OldSubmitWriteStream : _SubmitWriteStream)) {
  1808.                 GlobalLog.Assert(object.ReferenceEquals(stream, _SubmitWriteStream), "HttpWebRequest#{0}::CallDone|Called from invalid stream.", ValidationHelper.HashString(this));
  1809.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone() - called for resubmit stream");
  1810.                 stream.ProcessWriteCallDone(returnResult);
  1811.                 return;
  1812.             }
  1813.            
  1814.             // If we're still writing headers in GetRequestStream, don't delay, or GetRequestStream will hang.
  1815.             if (!UserRetrievedWriteStream) {
  1816.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone() - called during headers");
  1817.                 stream.ProcessWriteCallDone(returnResult);
  1818.                 return;
  1819.             }
  1820.            
  1821.             object pendResult = returnResult == null ? (object)Missing.Value : returnResult;
  1822.             object oldResult = Interlocked.CompareExchange(ref m_PendingReturnResult, pendResult, null);
  1823.             if (oldResult == DBNull.Value) {
  1824.                 stream.ProcessWriteCallDone(returnResult);
  1825.             }
  1826.         }
  1827.        
  1828.         internal void NeedEndSubmitRequest()
  1829.         {
  1830.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::NeedEndSubmitRequest()");
  1831.            
  1832.             object oldResult = Interlocked.CompareExchange(ref m_PendingReturnResult, NclConstants.Sentinel, null);
  1833.             if (oldResult == DBNull.Value) {
  1834.                 EndSubmitRequest();
  1835.             }
  1836.             else {
  1837.                 GlobalLog.Assert(oldResult == null, "HttpWebRequest#{0}::NeedEndSubmitRequest()|Duplicate call. typeof(oldResult):", ValidationHelper.HashString(this), oldResult != null ? oldResult.GetType().ToString() : "null");
  1838.             }
  1839.         }
  1840.        
  1841. /*
  1842.             Accessor:  Address
  1843.             This is just a simple Uri that is returned, indicating the end result
  1844.             of the request, after any possible Redirects, etc, that may transpire
  1845.             during the request.  This was added to handle this case since RequestUri
  1846.             will not change from the moment this Request is created.
  1847.             Input:
  1848.             Returns: The Uri for this request..
  1849.         */       
  1850.         /// <devdoc>
  1851.         /// <para>
  1852.         /// Gets the Uri that actually responded to the request.
  1853.         /// </para>
  1854.         /// </devdoc>
  1855.         public Uri Address {
  1856.             get { return _Uri; }
  1857.         }
  1858.        
  1859.        
  1860.         /// <devdoc>
  1861.         /// <para>Gets/Sets Deletegate used to signal us on Continue callback</para>
  1862.         /// </devdoc>
  1863.         public HttpContinueDelegate ContinueDelegate {
  1864.             get { return _ContinueDelegate; }
  1865.             set { _ContinueDelegate = value; }
  1866.         }
  1867.        
  1868.         internal void CallContinueDelegateCallback(object state)
  1869.         {
  1870.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CallContinueDelegateCallback");
  1871.             CoreResponseData response = (CoreResponseData)state;
  1872.             ContinueDelegate((int)response.m_StatusCode, response.m_ResponseHeaders);
  1873.         }
  1874.        
  1875.        
  1876.         /// <devdoc>
  1877.         /// <para>
  1878.         /// Gets the service point used for this request. Looks up the ServicePoint for given Uri,
  1879.         /// one isn't already created and assigned to this HttpWebRequest.
  1880.         /// </para>
  1881.         /// </devdoc>
  1882.         public ServicePoint ServicePoint {
  1883.             get {
  1884.                 #if DEBUG
  1885.                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  1886.                     #endif
  1887.                     return FindServicePoint(false);
  1888.                     #if DEBUG
  1889.                 }
  1890.                 #endif
  1891.             }
  1892.         }
  1893.        
  1894.         /// <devdoc>
  1895.         /// </devdoc>
  1896.         public int MaximumAutomaticRedirections {
  1897.             get { return _MaximumAllowedRedirections; }
  1898.             set {
  1899.                 if (value <= 0) {
  1900.                     throw new ArgumentException(SR.GetString(SR.net_toosmall), "value");
  1901.                 }
  1902.                 _MaximumAllowedRedirections = value;
  1903.             }
  1904.         }
  1905.        
  1906.         /// <devdoc>
  1907.         /// <para>
  1908.         /// Gets or sets the request method.
  1909.         /// This method represents the initial origin Verb, this is unchanged/uneffected by redirects
  1910.         /// </para>
  1911.         /// </devdoc>
  1912.         public override string Method {
  1913.             get { return _OriginVerb.Name; }
  1914.             set {
  1915.                 if (ValidationHelper.IsBlankString(value)) {
  1916.                     throw new ArgumentException(SR.GetString(SR.net_badmethod), "value");
  1917.                 }
  1918.                
  1919.                 if (ValidationHelper.IsInvalidHttpString(value)) {
  1920.                     throw new ArgumentException(SR.GetString(SR.net_badmethod), "value");
  1921.                 }
  1922.                 _OriginVerb = KnownHttpVerb.Parse(value);
  1923.             }
  1924.         }
  1925.        
  1926.         internal KnownHttpVerb CurrentMethod {
  1927.             get { return _Verb != null ? _Verb : _OriginVerb; }
  1928.             set { _Verb = value; }
  1929.         }
  1930.        
  1931.         /// <devdoc>
  1932.         /// <para>
  1933.         /// Provides authentication information for the request.
  1934.         /// </para>
  1935.         /// </devdoc>
  1936.         public override ICredentials Credentials {
  1937.             get { return _AuthInfo; }
  1938.             set { _AuthInfo = value; }
  1939.         }
  1940.        
  1941.         /// <devdoc>
  1942.         /// <para>
  1943.         /// Allows us to use generic default credentials.
  1944.         /// </para>
  1945.         /// </devdoc>
  1946.         public override bool UseDefaultCredentials {
  1947.             get { return (Credentials is SystemNetworkCredential) ? true : false; }
  1948.             set {
  1949.                 if (RequestSubmitted) {
  1950.                     throw new InvalidOperationException(SR.GetString(SR.net_writestarted));
  1951.                 }
  1952.                 _AuthInfo = value ? CredentialCache.DefaultCredentials : null;
  1953.             }
  1954.         }
  1955.        
  1956.         /// <devdoc>
  1957.         /// <para>
  1958.         /// True if we're tunneling SSL through a proxy
  1959.         /// </para>
  1960.         /// </devdoc>
  1961.         internal bool IsTunnelRequest {
  1962.             get { return (_Booleans & Booleans.IsTunnelRequest) != 0; }
  1963.             set {
  1964.                 if (value) {
  1965.                     _Booleans |= Booleans.IsTunnelRequest;
  1966.                 }
  1967.                 else {
  1968.                     _Booleans &= ~Booleans.IsTunnelRequest;
  1969.                 }
  1970.             }
  1971.         }
  1972.        
  1973.         //
  1974.         // ConnectionGroupName - used to control which group
  1975.         // of connections we use, by default should be null
  1976.         //
  1977.         /// <devdoc>
  1978.         /// <para>[To be supplied.]</para>
  1979.         /// </devdoc>
  1980.         public override string ConnectionGroupName {
  1981.             get { return _ConnectionGroupName; }
  1982.             set { _ConnectionGroupName = value; }
  1983.         }
  1984.        
  1985.         internal bool InternalConnectionGroup {
  1986. /* Consider removing
  1987.             get
  1988.             {
  1989.                 return m_InternalConnectionGroup;
  1990.             }
  1991.             */           
  1992.            
  1993.             set { m_InternalConnectionGroup = value; }
  1994.         }
  1995.        
  1996.        
  1997.         /// <devdoc>
  1998.         /// <para>
  1999.         /// A collection of HTTP headers stored as name value pairs.
  2000.         /// </para>
  2001.         /// </devdoc>
  2002.         public override WebHeaderCollection Headers {
  2003.             get { return _HttpRequestHeaders; }
  2004.             set {
  2005.                
  2006.                 // we can't change headers after they've already been sent
  2007.                 if (RequestSubmitted) {
  2008.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  2009.                 }
  2010.                
  2011.                 WebHeaderCollection webHeaders = value;
  2012.                 WebHeaderCollection newWebHeaders = new WebHeaderCollection(WebHeaderCollectionType.HttpWebRequest);
  2013.                
  2014.                 // Copy And Validate -
  2015.                 // Handle the case where their object tries to change
  2016.                 // name, value pairs after they call set, so therefore,
  2017.                 // we need to clone their headers.
  2018.                 //
  2019.                
  2020.                 foreach (string headerName in webHeaders.AllKeys) {
  2021.                     newWebHeaders.Add(headerName, webHeaders[headerName]);
  2022.                 }
  2023.                
  2024.                 _HttpRequestHeaders = newWebHeaders;
  2025.             }
  2026.         }
  2027.        
  2028.         /// <devdoc>
  2029.         /// <para>
  2030.         /// Gets or sets the proxy information for a request.
  2031.         /// </para>
  2032.         /// </devdoc>
  2033.         public override IWebProxy Proxy {
  2034.             get {
  2035.                 #if DEBUG
  2036.                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  2037.                     #endif
  2038.                     ExceptionHelper.WebPermissionUnrestricted.Demand();
  2039.                     return _Proxy;
  2040.                     #if DEBUG
  2041.                 }
  2042.                 #endif
  2043.             }
  2044.             set {
  2045.                 #if DEBUG
  2046.                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  2047.                     #endif
  2048.                     ExceptionHelper.WebPermissionUnrestricted.Demand();
  2049.                     // we can't change the proxy, while the request is already fired
  2050.                     if (RequestSubmitted) {
  2051.                         throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  2052.                     }
  2053.                     InternalProxy = value;
  2054.                     #if DEBUG
  2055.                 }
  2056.                 #endif
  2057.             }
  2058.         }
  2059.        
  2060.         internal IWebProxy InternalProxy {
  2061.             get { return _Proxy; }
  2062.             set {
  2063.                 ProxySet = true;
  2064.                 _Proxy = value;
  2065.                 if (_ProxyChain != null) {
  2066.                     _ProxyChain.Dispose();
  2067.                 }
  2068.                 _ProxyChain = null;
  2069.                
  2070.                 // since the service point is based on our proxy, make sure,
  2071.                 // that we reresolve it
  2072.                 ServicePoint servicePoint = FindServicePoint(true);
  2073.             }
  2074.         }
  2075.        
  2076.        
  2077.         // HTTP Version
  2078.         /// <devdoc>
  2079.         /// <para>
  2080.         /// Gets and sets
  2081.         /// the HTTP protocol version used in this request.
  2082.         /// </para>
  2083.         /// </devdoc>
  2084.         public Version ProtocolVersion {
  2085.             get { return IsVersionHttp10 ? HttpVersion.Version10 : HttpVersion.Version11; }
  2086.             set {
  2087.                 if (value.Equals(HttpVersion.Version11)) {
  2088.                     IsVersionHttp10 = false;
  2089.                 }
  2090.                 else if (value.Equals(HttpVersion.Version10)) {
  2091.                     IsVersionHttp10 = true;
  2092.                 }
  2093.                 else {
  2094.                     throw new ArgumentException(SR.GetString(SR.net_wrongversion), "value");
  2095.                 }
  2096.             }
  2097.         }
  2098.        
  2099.         /// <devdoc>
  2100.         /// <para>
  2101.         /// Gets and sets the value of the Content-Type header. Null clears it out.
  2102.         /// </para>
  2103.         /// </devdoc>
  2104.         public override string ContentType {
  2105.             get { return _HttpRequestHeaders[HttpKnownHeaderNames.ContentType]; }
  2106.             set { SetSpecialHeaders(HttpKnownHeaderNames.ContentType, value); }
  2107.         }
  2108.        
  2109.         /// <devdoc>
  2110.         /// <para>Sets the media type header</para>
  2111.         /// </devdoc>
  2112.         public string MediaType {
  2113.             get { return _MediaType; }
  2114.             set { _MediaType = value; }
  2115.         }
  2116.        
  2117.         /// <devdoc>
  2118.         /// <para>
  2119.         /// Gets or sets the value of the Transfer-Encoding header. Setting null clears it out.
  2120.         /// </para>
  2121.         /// </devdoc>
  2122.         public string TransferEncoding {
  2123.             get { return _HttpRequestHeaders[HttpKnownHeaderNames.TransferEncoding]; }
  2124.             set {
  2125.                 #if DEBUG
  2126.                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  2127.                     #endif
  2128.                     bool fChunked;
  2129.                     //
  2130.                     // on blank string, remove current header
  2131.                     //
  2132.                     if (ValidationHelper.IsBlankString(value)) {
  2133.                         //
  2134.                         // if the value is blank, then remove the header
  2135.                         //
  2136.                         _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.TransferEncoding);
  2137.                         return;
  2138.                     }
  2139.                    
  2140.                     //
  2141.                     // if not check if the user is trying to set chunked:
  2142.                     //
  2143.                     string newValue = value.ToLower(CultureInfo.InvariantCulture);
  2144.                     fChunked = (newValue.IndexOf(ChunkedHeader) != -1);
  2145.                    
  2146.                     //
  2147.                     // prevent them from adding chunked, or from adding an Encoding without
  2148.                     // turing on chunked, the reason is due to the HTTP Spec which prevents
  2149.                     // additional encoding types from being used without chunked
  2150.                     //
  2151.                     if (fChunked) {
  2152.                         throw new ArgumentException(SR.GetString(SR.net_nochunked), "value");
  2153.                     }
  2154.                     else if (!SendChunked) {
  2155.                         throw new InvalidOperationException(SR.GetString(SR.net_needchunked));
  2156.                     }
  2157.                     else {
  2158.                         _HttpRequestHeaders.CheckUpdate(HttpKnownHeaderNames.TransferEncoding, value);
  2159.                     }
  2160.                     #if DEBUG
  2161.                 }
  2162.                 #endif
  2163.             }
  2164.         }
  2165.        
  2166.         /// <devdoc>
  2167.         /// <para>
  2168.         /// Gets and sets the value of the Connection header. Setting null clears the header out.
  2169.         /// </para>
  2170.         /// </devdoc>
  2171.         public string Connection {
  2172.             get { return _HttpRequestHeaders[HttpKnownHeaderNames.Connection]; }
  2173.             set {
  2174.                 #if DEBUG
  2175.                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  2176.                     #endif
  2177.                     bool fKeepAlive;
  2178.                     bool fClose;
  2179.                    
  2180.                     //
  2181.                     // on blank string, remove current header
  2182.                     //
  2183.                     if (ValidationHelper.IsBlankString(value)) {
  2184.                         _HttpRequestHeaders.Remove(HttpKnownHeaderNames.Connection);
  2185.                         return;
  2186.                     }
  2187.                    
  2188.                     string newValue = value.ToLower(CultureInfo.InvariantCulture);
  2189.                    
  2190.                     fKeepAlive = (newValue.IndexOf("keep-alive") != -1);
  2191.                     fClose = (newValue.IndexOf("close") != -1);
  2192.                    
  2193.                     //
  2194.                     // Prevent keep-alive and close from being added
  2195.                     //
  2196.                    
  2197.                     if (fKeepAlive || fClose) {
  2198.                         throw new ArgumentException(SR.GetString(SR.net_connarg), "value");
  2199.                     }
  2200.                     else {
  2201.                         _HttpRequestHeaders.CheckUpdate(HttpKnownHeaderNames.Connection, value);
  2202.                     }
  2203.                     #if DEBUG
  2204.                 }
  2205.                 #endif
  2206.             }
  2207.         }
  2208.        
  2209.         /// <devdoc>
  2210.         /// <para>
  2211.         /// Gets or sets the value of the Accept header.
  2212.         /// </para>
  2213.         /// </devdoc>
  2214.         public string Accept {
  2215.             get { return _HttpRequestHeaders[HttpKnownHeaderNames.Accept]; }
  2216.             set { SetSpecialHeaders(HttpKnownHeaderNames.Accept, value); }
  2217.         }
  2218.        
  2219.         /// <devdoc>
  2220.         /// <para>
  2221.         /// Gets or sets the value of the Referer header.
  2222.         /// </para>
  2223.         /// </devdoc>
  2224.         public string Referer {
  2225.             get { return _HttpRequestHeaders[HttpKnownHeaderNames.Referer]; }
  2226.             set { SetSpecialHeaders(HttpKnownHeaderNames.Referer, value); }
  2227.         }
  2228.        
  2229.         /// <devdoc>
  2230.         /// <para>
  2231.         /// Gets or sets the value of the User-Agent header.
  2232.         /// </para>
  2233.         /// </devdoc>
  2234.         public string UserAgent {
  2235.             get { return _HttpRequestHeaders[HttpKnownHeaderNames.UserAgent]; }
  2236.             set { SetSpecialHeaders(HttpKnownHeaderNames.UserAgent, value); }
  2237.         }
  2238.        
  2239.        
  2240. /*
  2241.             Accessor:  Expect
  2242.             The property that controls the Expect header
  2243.             Input:
  2244.                 string Expect, null clears the Expect except for 100-continue value
  2245.             Returns: The value of the Expect on get.
  2246.         */       
  2247.        
  2248.         /// <devdoc>
  2249.         /// <para>
  2250.         /// Gets or sets the value of the Expect header.
  2251.         /// </para>
  2252.         /// </devdoc>
  2253.         public string Expect {
  2254.             get { return _HttpRequestHeaders[HttpKnownHeaderNames.Expect]; }
  2255.             set {
  2256.                 #if DEBUG
  2257.                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  2258.                     #endif
  2259.                     // only remove everything other than 100-cont
  2260.                     bool fContinue100;
  2261.                    
  2262.                     //
  2263.                     // on blank string, remove current header
  2264.                     //
  2265.                    
  2266.                     if (ValidationHelper.IsBlankString(value)) {
  2267.                         _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Expect);
  2268.                         return;
  2269.                     }
  2270.                    
  2271.                     //
  2272.                     // Prevent 100-continues from being added
  2273.                     //
  2274.                    
  2275.                     string newValue = value.ToLower(CultureInfo.InvariantCulture);
  2276.                    
  2277.                     fContinue100 = (newValue.IndexOf(ContinueHeader) != -1);
  2278.                    
  2279.                     if (fContinue100) {
  2280.                         throw new ArgumentException(SR.GetString(SR.net_no100), "value");
  2281.                     }
  2282.                     else {
  2283.                         _HttpRequestHeaders.CheckUpdate(HttpKnownHeaderNames.Expect, value);
  2284.                     }
  2285.                     #if DEBUG
  2286.                 }
  2287.                 #endif
  2288.             }
  2289.         }
  2290.        
  2291.         /// <devdoc>
  2292.         /// <para>
  2293.         /// Gets or sets the value of the If-Modified-Since header.
  2294.         /// </para>
  2295.         /// </devdoc>
  2296.         public DateTime IfModifiedSince {
  2297.             get {
  2298.                 #if DEBUG
  2299.                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  2300.                     #endif
  2301.                     string ifmodHeaderValue = _HttpRequestHeaders[HttpKnownHeaderNames.IfModifiedSince];
  2302.                    
  2303.                     if (ifmodHeaderValue == null) {
  2304.                         return DateTime.Now;
  2305.                     }
  2306.                     else if (_CachedIfModifedSince != DateTime.MinValue) {
  2307.                         return _CachedIfModifedSince;
  2308.                     }
  2309.                    
  2310.                     return HttpProtocolUtils.string2date(ifmodHeaderValue);
  2311.                     #if DEBUG
  2312.                 }
  2313.                 #endif
  2314.             }
  2315.             set {
  2316.                 #if DEBUG
  2317.                 using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
  2318.                     #endif
  2319.                     SetSpecialHeaders(HttpKnownHeaderNames.IfModifiedSince, HttpProtocolUtils.date2string(value));
  2320.                     _CachedIfModifedSince = value;
  2321.                     #if DEBUG
  2322.                 }
  2323.                 #endif
  2324.             }
  2325.         }
  2326.        
  2327.         internal byte[] WriteBuffer {
  2328.             get { return _WriteBuffer; }
  2329.         }
  2330.        
  2331.         //
  2332.         // Frequently usedheaders made available as properties,
  2333.         // the following headers add or remove headers taking care
  2334.         // of special cases due to their unquie qualities within
  2335.         // the net handlers,
  2336.         //
  2337.         // Note that all headers supported here will be disallowed,
  2338.         // and not accessable through the normal Header objects.
  2339.         //
  2340.        
  2341. /*
  2342.             Accessor:  SetSpecialHeaders
  2343.             Private method for removing duplicate code which removes and
  2344.               adds headers that are marked private
  2345.             Input:  HeaderName, value to set headers
  2346.             Returns: none
  2347.         */       
  2348.        
  2349.         private void SetSpecialHeaders(string HeaderName, string value)
  2350.         {
  2351.             value = WebHeaderCollection.CheckBadChars(value, true);
  2352.             _HttpRequestHeaders.RemoveInternal(HeaderName);
  2353.             if (value.Length != 0) {
  2354.                 _HttpRequestHeaders.AddInternal(HeaderName, value);
  2355.             }
  2356.         }
  2357.        
  2358. /*
  2359.             Abort - Attempts to abort pending request,
  2360.             This calls into the delegate, and then closes any pending streams.
  2361.             Input: none
  2362.             Returns: none
  2363.         */       
  2364.         public override void Abort()
  2365.         {
  2366.             #if DEBUG
  2367.             using (GlobalLog.SetThreadKind(ThreadKinds.User))/* | ThreadKinds.Async would be nice */ {
  2368.                 #endif
  2369.                 Abort(null, AbortState.Public);
  2370.                 #if DEBUG
  2371.             }
  2372.             #endif
  2373.         }
  2374.        
  2375.         private void Abort(Exception exception, int abortState)
  2376.         {
  2377.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::Abort()");
  2378.             if (Logging.On)
  2379.                 Logging.Enter(Logging.Web, this, "Abort", (exception == null ? "" : exception.Message));
  2380.            
  2381.             // public abort will never drain streams
  2382.             if (Interlocked.CompareExchange(ref m_Aborted, abortState, 0) == 0) {
  2383.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::Abort() - " + exception);
  2384.                
  2385.                 m_OnceFailed = true;
  2386.                 CancelTimer();
  2387.                
  2388.                 WebException webException = exception as WebException;
  2389.                 if (exception == null) {
  2390.                     webException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
  2391.                 }
  2392.                 else if (webException == null) {
  2393.                     webException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), exception, WebExceptionStatus.RequestCanceled, _HttpResponse);
  2394.                 }
  2395.                
  2396.                 try {
  2397.                     #if DEBUG
  2398.                     bool setResponseCalled = false;
  2399.                     try {
  2400.                         #endif
  2401.                         // Want to make sure that other threads see that we're aborted before they set an abort delegate, or that we see
  2402.                         // the delegate if they might have missed that we're aborted.
  2403.                         Thread.MemoryBarrier();
  2404.                         HttpAbortDelegate abortDelegate = _AbortDelegate;
  2405.                         #if DEBUG
  2406.                         m_AbortDelegateUsed = abortDelegate == null ? (object)DBNull.Value : abortDelegate;
  2407.                         #endif
  2408.                         if (abortDelegate == null || abortDelegate(this, webException)) {
  2409.                             // We don't have a connection associated with this request
  2410.                            
  2411.                             LazyAsyncResult chkConnectionAsyncResult = Async ? null : ConnectionAsyncResult;
  2412.                             LazyAsyncResult chkReaderAsyncResult = Async ? null : ConnectionReaderAsyncResult;
  2413.                            
  2414.                             #if DEBUG
  2415.                             setResponseCalled = true;
  2416.                             #endif
  2417.                             SetResponse(webException);
  2418.                            
  2419.                             if (chkConnectionAsyncResult != null)
  2420.                                 chkConnectionAsyncResult.InvokeCallback(webException);
  2421.                             if (chkReaderAsyncResult != null)
  2422.                                 chkReaderAsyncResult.InvokeCallback(webException);
  2423.                         }
  2424.                         #if DEBUG
  2425.                     }
  2426.                     catch (Exception stressException) {
  2427.                         t_LastStressException = stressException;
  2428.                         if (!NclUtilities.IsFatal(stressException)) {
  2429.                             GlobalLog.Assert(setResponseCalled, "HttpWebRequest#{0}::Abort|{1}", ValidationHelper.HashString(this), stressException.Message);
  2430.                         }
  2431.                         throw;
  2432.                     }
  2433.                     #endif
  2434.                 }
  2435.                 catch (Exception ex) {
  2436.                     if (NclUtilities.IsFatal(ex))
  2437.                         throw;
  2438.                 }
  2439.                 catch {
  2440.                 }
  2441.             }
  2442.            
  2443.             if (Logging.On)
  2444.                 Logging.Exit(Logging.Web, this, "Abort", "");
  2445.         }
  2446.        
  2447.         // Cancel any pending timer.
  2448.         private void CancelTimer()
  2449.         {
  2450.             TimerThread.Timer timer = _Timer;
  2451.             if (timer != null) {
  2452.                 timer.Cancel();
  2453.             }
  2454.         }
  2455.        
  2456.         // TimeoutCallback - Called by the TimerThread to abort a request. This just posts ThreadPool work item - Abort() does too
  2457.         // much to be done on the timer thread (timer thread should never block or call user code).
  2458.         private static void TimeoutCallback(TimerThread.Timer timer, int timeNoticed, object context)
  2459.         {
  2460.             ThreadPool.UnsafeQueueUserWorkItem(s_AbortWrapper, context);
  2461.         }
  2462.        
  2463.         private static void AbortWrapper(object context)
  2464.         {
  2465.             #if DEBUG
  2466.             GlobalLog.SetThreadSource(ThreadKinds.Worker);
  2467.             using (GlobalLog.SetThreadKind(ThreadKinds.System)) {
  2468.                 #endif
  2469.                 ((HttpWebRequest)context).Abort(new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout), AbortState.Public);
  2470.                 #if DEBUG
  2471.             }
  2472.             #endif
  2473.         }
  2474.        
  2475. /*
  2476.             FindServicePoint - Finds the ServicePoint for this request
  2477.             This calls the FindServicePoint off of the ServicePointManager
  2478.             to determine what ServicePoint to use.  When our proxy changes,
  2479.             or there is a redirect, this should be recalled to determine it.
  2480.             Input:  forceFind        - regardless of the status, always call FindServicePoint
  2481.             Returns: ServicePoint
  2482.         */       
  2483.         private ServicePoint FindServicePoint(bool forceFind)
  2484.         {
  2485.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::FindServicePoint");
  2486.            
  2487.             ServicePoint servicePoint = _ServicePoint;
  2488.             if (servicePoint == null || forceFind) {
  2489.                 lock (this) {
  2490.                     //
  2491.                     // we will call FindServicePoint - iff
  2492.                     // - there is no service point ||
  2493.                     // - we are forced to find one, usually due to changes of the proxy or redirection
  2494.                     //
  2495.                    
  2496.                     if (_ServicePoint == null || forceFind) {
  2497.                        
  2498.                         if (!ProxySet) {
  2499.                             _Proxy = WebRequest.InternalDefaultWebProxy;
  2500.                         }
  2501.                         if (_ProxyChain != null) {
  2502.                             _ProxyChain.Dispose();
  2503.                         }
  2504.                         _ServicePoint = ServicePointManager.FindServicePoint(_Uri, _Proxy, out _ProxyChain, ref _AbortDelegate, ref m_Aborted);
  2505.                         if (Logging.On)
  2506.                             Logging.Associate(Logging.Web, this, _ServicePoint);
  2507.                     }
  2508.                 }
  2509.                 servicePoint = _ServicePoint;
  2510.             }
  2511.            
  2512.             return servicePoint;
  2513.         }
  2514.        
  2515. /*
  2516.             InvokeGetRequestStreamCallback - Notify our GetRequestStream caller
  2517.             This is needed to tell our caller that we're finished,
  2518.             and he can go ahead and write to the stream.
  2519.         */       
  2520.         private void InvokeGetRequestStreamCallback()
  2521.         {
  2522.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::InvokeGetRequestStreamCallback");
  2523.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::InvokeGetRequestStreamCallback");
  2524.            
  2525.             LazyAsyncResult asyncResult = _WriteAResult;
  2526.             GlobalLog.Assert(asyncResult == null || this == (HttpWebRequest)asyncResult.AsyncObject, "HttpWebRequest#{0}::InvokeGetRequestStreamCallback()|this != asyncResult.AsyncObject", ValidationHelper.HashString(this));
  2527.            
  2528.             if (asyncResult != null) {
  2529.                 try {
  2530.                     asyncResult.InvokeCallback(_SubmitWriteStream);
  2531.                 }
  2532.                 catch (Exception exception) {
  2533.                     if (NclUtilities.IsFatal(exception))
  2534.                         throw;
  2535.                    
  2536.                     Abort(exception, AbortState.Public);
  2537.                     GlobalLog.LeaveException("HttpWebRequest#" + ValidationHelper.HashString(this) + "::InvokeGetRequestStreamCallback", exception);
  2538.                     throw;
  2539.                 }
  2540.             }
  2541.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::InvokeGetRequestStreamCallback", "success");
  2542.         }
  2543.        
  2544. /*
  2545.             RequestSubmitDone - Handle submit done callback.
  2546.             This is our submit done handler, called by the underlying connection
  2547.             code when a stream is available for our use. We save the stream for
  2548.             later use and signal the wait event.
  2549.             We also handle the continuation/termination of a BeginGetRequestStream,
  2550.             by saving out the result and calling its callback if needed.
  2551.             Input:  SubmitStream        - The stream we may write on.
  2552.                     Status              - The status of the submission.
  2553.             Returns: Nothing.
  2554.         */       
  2555.         internal void SetRequestSubmitDone(ConnectStream submitStream)
  2556.         {
  2557.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone", ValidationHelper.HashString(submitStream));
  2558.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone");
  2559.            
  2560.             if (!Async) {
  2561.                 ConnectionAsyncResult.InvokeCallback();
  2562.             }
  2563.            
  2564.             if (AllowWriteStreamBuffering) {
  2565.                 submitStream.EnableWriteBuffering();
  2566.             }
  2567.            
  2568.             if (submitStream.CanTimeout) {
  2569.                 submitStream.ReadTimeout = ReadWriteTimeout;
  2570.                 submitStream.WriteTimeout = ReadWriteTimeout;
  2571.             }
  2572.             if (Logging.On)
  2573.                 Logging.Associate(Logging.Web, this, submitStream);
  2574.             _SubmitWriteStream = submitStream;
  2575.            
  2576.             //
  2577.             // This line is needed ONLY if we got a connect failure (Abort can still happen at random time)
  2578.             // CallDone will check for the write side response processing and this is what we want.
  2579.             // Note that Sync case already has a separate path to check for the response
  2580.             //
  2581.             if (Async && _CoreResponse != null && (object)_CoreResponse != (object)DBNull.Value) {
  2582.                 GlobalLog.Assert(_CoreResponse is Exception, "SetRequestSubmitDone()|Found offensive response right after getting connection ({0}).", _CoreResponse);
  2583.                 submitStream.CallDone();
  2584.                 GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone() - already have a core response", _CoreResponse.GetType().FullName);
  2585.                 return;
  2586.             }
  2587.            
  2588.             EndSubmitRequest();
  2589.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone");
  2590.         }
  2591.        
  2592.        
  2593.         internal void WriteHeadersCallback(WebExceptionStatus errorStatus, ConnectStream stream, bool async)
  2594.         {
  2595.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteHeadersCallback", ValidationHelper.HashString(stream));
  2596.             if (errorStatus == WebExceptionStatus.Success) {
  2597.                 bool completed = EndWriteHeaders(async);
  2598.                 if (!completed) {
  2599.                     errorStatus = WebExceptionStatus.Pending;
  2600.                 }
  2601.                 else {
  2602.                     GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(stream) + "::WriteHeaders completed:true BytesLeftToWrite:" + stream.BytesLeftToWrite.ToString());
  2603.                     if (stream.BytesLeftToWrite == 0) {
  2604.                         //
  2605.                         // didn't go pending, no data to write. we're done.
  2606.                         //
  2607.                         stream.CallDone();
  2608.                     }
  2609.                 }
  2610.             }
  2611.            
  2612.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteHeadersCallback", errorStatus.ToString());
  2613.         }
  2614.        
  2615. /*
  2616.             SetRequestContinue - Handle 100-continues on Posting
  2617.             This indicates to us that we need to continue posting,
  2618.             and there is no need to buffer because we are now
  2619.         */       
  2620.         internal void SetRequestContinue()
  2621.         {
  2622.             SetRequestContinue(null);
  2623.         }
  2624.        
  2625.         internal void SetRequestContinue(CoreResponseData continueResponse)
  2626.         {
  2627.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue");
  2628.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue");
  2629.            
  2630.             _RequestContinueCount++;
  2631.            
  2632.             if (HttpWriteMode == HttpWriteMode.None) {
  2633.                 GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue - not a POST type request, return");
  2634.                 return;
  2635.             }
  2636.            
  2637.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue() _RequestContinueCount:" + _RequestContinueCount);
  2638.            
  2639.             if (m_ContinueGate.Complete()) {
  2640.                 // Generally, in Sync mode there will not be a timer (instead PollAndRead times out). However, in mixed mode
  2641.                 // there can be. If there is a timer, whether or not to call EndWriteHeaders_Part2 depends on whether
  2642.                 // we can successfully cancel it here. Otherwise, the timeout callback should call it.
  2643.                 //
  2644.                 // m_ContinueGate guards the synchronization of m_ContinueTimer.
  2645.                 TimerThread.Timer timer = m_ContinueTimer;
  2646.                 m_ContinueTimer = null;
  2647.                
  2648.                 // In the case there was no timer, just call EndWriteHeaders_Part2.
  2649.                 if (timer == null || timer.Cancel()) {
  2650.                     // Invoke the 100 continue delegate if the user supplied one and we received a 100 Continue.
  2651.                     if (continueResponse != null && ContinueDelegate != null) {
  2652.                         GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue() calling ContinueDelegate()");
  2653.                         ExecutionContext x = null;
  2654.                         if (x == null) {
  2655.                             ContinueDelegate((int)continueResponse.m_StatusCode, continueResponse.m_ResponseHeaders);
  2656.                         }
  2657.                         else {
  2658.                             ExecutionContext.Run(x, new ContextCallback(CallContinueDelegateCallback), continueResponse);
  2659.                         }
  2660.                     }
  2661.                    
  2662.                     EndWriteHeaders_Part2();
  2663.                 }
  2664.             }
  2665.            
  2666.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue");
  2667.         }
  2668.        
  2669.         //
  2670.         // Used to keep us looping and parsing until we get a 100 continue.
  2671.         // Since we can get more than one 100 continue during redirects or auth, we need to keep it on a counter.
  2672.         //
  2673.         internal int RequestContinueCount {
  2674.             get { return _RequestContinueCount; }
  2675.         }
  2676.         //
  2677.         // This will open the write side response window, so any response processing
  2678.         // coming before the window is closed will be delayed.
  2679.         // CheckWriteSideResponseProcessing() becomes a must do call sometime after this method was invoked.
  2680.         //
  2681.         internal void OpenWriteSideResponseWindow()
  2682.         {
  2683.             //
  2684.             // Multithreading: This method is called from the connection and under the connection lock
  2685.             // It should not be subject to a race condition. Note that request.Abort() also ends up with the connection lock.
  2686.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::OpenWriteSideResponseWindow()");
  2687.            
  2688.             _CoreResponse = DBNull.Value;
  2689.             _NestedWriteSideCheck = 0;
  2690.         }
  2691.         //
  2692.         // If the response is already received this method starts its processing.
  2693.         // Otheriwse the window for write side response processing is closed
  2694.         //
  2695.         // We do not clear current response if any hence SetAndOrProcessResponse() will not go into concurent
  2696.         // reponse processing
  2697.         //
  2698.         internal void CheckWriteSideResponseProcessing()
  2699.         {
  2700.             // In Sync case never close the write side window
  2701.             object responseData = Async ? Interlocked.CompareExchange(ref _CoreResponse, null, DBNull.Value) : _CoreResponse;
  2702.            
  2703.             if (responseData == DBNull.Value) {
  2704.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckWriteSideResponseProcessing() - responseData = DBNull means no response yet, " + (Async ? "async: closing write side window" : "sync: leaving write side window opened"));
  2705.                 return;
  2706.             }
  2707.            
  2708.             if (responseData == null) {
  2709.                 // change later on responseData = new a generic Abort WebException
  2710.                 throw new InternalException();
  2711.                 // we set it to DBNull.Value and want to find it now as either that value or as the real response
  2712.             }
  2713.            
  2714.             if (!Async && ++_NestedWriteSideCheck != 1) {
  2715.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckWriteSideResponseProcessing() - Repeated SYNC check _NestedWriteSideCheck = " + _NestedWriteSideCheck + ", response =" + responseData.GetType().FullName);
  2716.                 return;
  2717.             }
  2718.            
  2719.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckWriteSideResponseProcessing() - Response is ready, process here: " + responseData.GetType().FullName);
  2720.            
  2721.             // The response has been already set and the processing was deferred until now
  2722.             Exception exception = responseData as Exception;
  2723.             if (exception != null)
  2724.                 SetResponse(exception);
  2725.             else
  2726.                 SetResponse(responseData as CoreResponseData);
  2727.         }
  2728.         //
  2729.         //
  2730.         // Some kind of response is ready and this method will ether process it or defer until the write side response check.
  2731.         //
  2732.         // Note, when an exception comes here then the request is already taken off the list and the connection is BEING closed.
  2733.         internal void SetAndOrProcessResponse(object responseOrException)
  2734.         {
  2735.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Entered with responseOrException: " + responseOrException);
  2736.            
  2737.             if (responseOrException == null)
  2738.                 throw new InternalException();
  2739.             //Consider making an Assert later. If the condtion is met then this request may hang.
  2740.             CoreResponseData newResponse = responseOrException as CoreResponseData;
  2741.             WebException newException = responseOrException as WebException;
  2742.            
  2743.             object responseData = Interlocked.CompareExchange(ref _CoreResponse, responseOrException, DBNull.Value);
  2744.            
  2745.             //
  2746.             // (1) This method cannot be called with two exceptions in a row or with two responses in a row.
  2747.             // (2) If a response comes then an exception means a fatal exception overrides the response or otherwise ignored
  2748.             // (3) If an exception comes then a response means the exception takes precedence so the response can be ignored
  2749.             //
  2750.            
  2751.             if (responseData != null) {
  2752.                 if (responseData.GetType() == typeof(CoreResponseData)) {
  2753.                     if (newResponse != null)
  2754.                         throw new InternalException();
  2755.                     // make an assert later
  2756.                     if (newException != null && newException.InternalStatus != WebExceptionInternalStatus.ServicePointFatal && newException.InternalStatus != WebExceptionInternalStatus.RequestFatal)
  2757.                         return;
  2758.                     // Else the exception will override the response
  2759.                 }
  2760.                 else if (responseData.GetType() != typeof(DBNull)) {
  2761.                     // Here responseData == Exception so newResponse must not be an exception
  2762.                     if (newResponse == null)
  2763.                         throw new InternalException();
  2764.                     // make an assert later that will be ignored in retail
  2765.                     //We have an exception and now getting a response
  2766.                     // Release that response stream to unblock the connection
  2767.                     ICloseEx closeEx = newResponse.m_ConnectStream as ICloseEx;
  2768.                     if (closeEx != null) {
  2769.                         closeEx.CloseEx(CloseExState.Silent);
  2770.                     }
  2771.                     else {
  2772.                         newResponse.m_ConnectStream.Close();
  2773.                     }
  2774.                    
  2775.                     return;
  2776.                 }
  2777.             }
  2778.            
  2779.             //
  2780.             // Can the write side process that response?
  2781.             //
  2782.             if (responseData == DBNull.Value) {
  2783.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Write Thread will procees the response.");
  2784.                 //
  2785.                 // Note for a sync request a write side window is always open
  2786.                 //
  2787.                 if (!Async) {
  2788.                     LazyAsyncResult chkConnectionAsyncResult = ConnectionAsyncResult;
  2789.                     LazyAsyncResult chkReaderAsyncResult = ConnectionReaderAsyncResult;
  2790.                    
  2791.                     chkConnectionAsyncResult.InvokeCallback(responseOrException);
  2792.                     // ref "responseOrException": could be anything except for AsyncTriState or stream
  2793.                     chkReaderAsyncResult.InvokeCallback(responseOrException);
  2794.                     // ref "responseOrException": could be anything except for null
  2795.                 }
  2796.                 return;
  2797.             }
  2798.             else if (responseData != null) {
  2799.                 Exception e = responseOrException as Exception;
  2800.                 if (e != null) {
  2801.                     // This may happen if we failed while trying to process a response.
  2802.                     GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Fatal Exception -> Override old response = " + responseData);
  2803.                     SetResponse(e);
  2804.                 }
  2805.                 else {
  2806.                     GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Error!!! Unexpected (1) Response already set response = " + responseData);
  2807.                     throw new InternalException();
  2808.                     // make an assert later
  2809.                 }
  2810.                 return;
  2811.             }
  2812.            
  2813.             //
  2814.             // Can that thread process the response?
  2815.             //
  2816.             responseData = Interlocked.CompareExchange(ref _CoreResponse, responseOrException, null);
  2817.             if (responseData != null) {
  2818.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Warning!!! Unexpected (2) SetResponse, already set response = " + responseData);
  2819.                
  2820.                 // This is a race with Abort, if we got an exception then re-enter SetResponse, otherwise return
  2821.                 if (newResponse != null) {
  2822.                     GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Ignoring current response while SetResponse() is processing an exception");
  2823.                    
  2824.                     // We have an exception and now getting a response
  2825.                     // Release that response stream to unblock the connection
  2826.                     ICloseEx closeEx = newResponse.m_ConnectStream as ICloseEx;
  2827.                     if (closeEx != null) {
  2828.                         closeEx.CloseEx(CloseExState.Silent);
  2829.                     }
  2830.                     else {
  2831.                         newResponse.m_ConnectStream.Close();
  2832.                     }
  2833.                    
  2834.                     return;
  2835.                 }
  2836.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Forcing new exception to re-enter SetResponse() that is being processed with CoreResponseData");
  2837.             }
  2838.            
  2839.             if (!Async)
  2840.                 throw new InternalException();
  2841.             //Consider making an Assert later. If the condition is met it _might_ process a sync request on non submitting thread.
  2842.             // For this request the write side response window was already closed so we have to procees the response
  2843.             if (newResponse != null)
  2844.                 SetResponse(newResponse);
  2845.             else
  2846.                 SetResponse(responseOrException as Exception);
  2847.         }
  2848.         //
  2849.         // When we got a live response, this method will construct the response object
  2850.         // and then consult with caching protocol on the appropriate action.
  2851.         // On return the response can be re-created.
  2852.         // Under some cases this method may initate retrying of the current request.
  2853.         //
  2854.         private void SetResponse(CoreResponseData coreResponseData)
  2855.         {
  2856.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse");
  2857.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse - coreResponseData=" + ValidationHelper.HashString(coreResponseData));
  2858.            
  2859.             try {
  2860.                 if (!Async) {
  2861.                     LazyAsyncResult chkConnectionAsyncResult = ConnectionAsyncResult;
  2862.                     LazyAsyncResult chkReaderAsyncResult = ConnectionReaderAsyncResult;
  2863.                    
  2864.                     chkConnectionAsyncResult.InvokeCallback(coreResponseData);
  2865.                     // ref "coreResponseData": could be anything except for AsyncTriState or stream
  2866.                     chkReaderAsyncResult.InvokeCallback(coreResponseData);
  2867.                     // ref "coreResponseData": could be anything except for null
  2868.                 }
  2869.                
  2870.                 if (coreResponseData != null) {
  2871.                     if (coreResponseData.m_ConnectStream.CanTimeout) {
  2872.                         coreResponseData.m_ConnectStream.WriteTimeout = ReadWriteTimeout;
  2873.                         coreResponseData.m_ConnectStream.ReadTimeout = ReadWriteTimeout;
  2874.                     }
  2875.                     _HttpResponse = new HttpWebResponse(_Uri, CurrentMethod, coreResponseData, _MediaType, UsesProxySemantics, AutomaticDecompression);
  2876.                    
  2877.                     if (Logging.On)
  2878.                         Logging.Associate(Logging.Web, this, coreResponseData.m_ConnectStream);
  2879.                     if (Logging.On)
  2880.                         Logging.Associate(Logging.Web, this, _HttpResponse);
  2881.                     ProcessResponse();
  2882.                 }
  2883.                 else {
  2884.                     GlobalLog.Assert("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse()", "coreResponseData == null");
  2885.                     Abort(null, AbortState.Public);
  2886.                     GlobalLog.LeaveException("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", new InternalException());
  2887.                 }
  2888.             }
  2889.             catch (Exception exception) {
  2890.                 Abort(exception, AbortState.Internal);
  2891.                 GlobalLog.LeaveException("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", exception);
  2892.             }
  2893.             return;
  2894.         }
  2895.        
  2896. /*++
  2897.         Routine Description:
  2898.             Wakes up blocked threads, so they can read response object,
  2899.               from the result
  2900.             We also handle the continuation/termination of a BeginGetResponse,
  2901.             by saving out the result and calling its callback if needed.
  2902.         --*/       
  2903.         private void ProcessResponse()
  2904.         {
  2905.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ProcessResponse", "From Cache = " + _HttpResponse.IsFromCache);
  2906.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::ProcessResponse");
  2907.            
  2908.             HttpProcessingResult httpResult = HttpProcessingResult.Continue;
  2909.             Exception exception = null;
  2910.            
  2911.             // handle redirects, authentication, and such
  2912.             httpResult = DoSubmitRequestProcessing(ref exception);
  2913.            
  2914.             if (httpResult == HttpProcessingResult.Continue) {
  2915.                 CancelTimer();
  2916.                
  2917.                 object result = exception != null ? (object)exception : (object)_HttpResponse;
  2918.                
  2919.                 if (_ReadAResult == null) {
  2920.                     lock (this) {
  2921.                         if (_ReadAResult == null) {
  2922.                             _ReadAResult = new LazyAsyncResult(null, null, null, result);
  2923.                             //never throws
  2924.                         }
  2925.                     }
  2926.                 }
  2927.                
  2928.                 try {
  2929.                     FinishRequest(_HttpResponse, exception);
  2930.                     // never throws
  2931.                     _ReadAResult.InvokeCallback(result);
  2932.                    
  2933.                     try {
  2934.                         SetRequestContinue();
  2935.                     }
  2936.                     catch {
  2937.                     }
  2938.                 }
  2939.                 catch (Exception e) {
  2940.                     Abort(e, AbortState.Public);
  2941.                     throw;
  2942.                 }
  2943.                 finally {
  2944.                     // If request was already aborted the response will not be set on asyncResult, hence abort it now
  2945.                     if (exception == null && _ReadAResult.Result != (object)_HttpResponse) {
  2946.                         WebException webException = _ReadAResult.Result as WebException;
  2947.                         if (webException != null && webException.Response != null) {
  2948.                             GlobalLog.Assert(object.ReferenceEquals(webException.Response, _HttpResponse), "HttpWebRequset#{0}::ProcessResponse|Different HttpWebResponse in exception versus _HttpResponse.", ValidationHelper.HashString(this));
  2949.                             _HttpResponse.Abort();
  2950.                             // never throws
  2951.                         }
  2952.                     }
  2953.                 }
  2954.             }
  2955.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ProcessResponse");
  2956.         }
  2957.        
  2958.         //
  2959.         // Process an exception and optionally set request for retrying
  2960.         //
  2961.         private void SetResponse(Exception E)
  2962.         {
  2963.             #if DEBUG
  2964.             bool callbackInvoked = false;
  2965.             try {
  2966.                 #endif
  2967.                 GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", E.ToString() + "/*** SETRESPONSE IN ERROR ***");
  2968.                 GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse");
  2969.                
  2970.                 HttpProcessingResult httpResult = HttpProcessingResult.Continue;
  2971.                
  2972.                 //
  2973.                 // Preserve the very first web exception occured if it was fatal
  2974.                 //
  2975.                 WebException webException = HaveResponse ? _ReadAResult.Result as WebException : null;
  2976.                 WebException newWebException = E as WebException;
  2977.                 if (webException != null && (webException.InternalStatus == WebExceptionInternalStatus.RequestFatal || webException.InternalStatus == WebExceptionInternalStatus.ServicePointFatal) && (newWebException == null || newWebException.InternalStatus != WebExceptionInternalStatus.RequestFatal)) {
  2978.                     E = webException;
  2979.                 }
  2980.                 else {
  2981.                     webException = newWebException;
  2982.                 }
  2983.                
  2984.                 if (E != null) {
  2985.                     if (Logging.On)
  2986.                         Logging.Exception(Logging.Web, this, "", webException);
  2987.                 }
  2988.                
  2989.                 try {
  2990.                     if (webException != null && (webException.InternalStatus == WebExceptionInternalStatus.Isolated || webException.InternalStatus == WebExceptionInternalStatus.ServicePointFatal || (webException.InternalStatus == WebExceptionInternalStatus.Recoverable && !m_OnceFailed))) {
  2991.                        
  2992.                         if (webException.InternalStatus == WebExceptionInternalStatus.Recoverable)
  2993.                             m_OnceFailed = true;
  2994.                        
  2995.                         Pipelined = false;
  2996.                        
  2997.                         if (_SubmitWriteStream != null && _OldSubmitWriteStream == null && _SubmitWriteStream.BufferOnly) {
  2998.                             _OldSubmitWriteStream = _SubmitWriteStream;
  2999.                         }
  3000.                        
  3001.                         httpResult = DoSubmitRequestProcessing(ref E);
  3002.                     }
  3003.                 }
  3004.                 catch (Exception unexpectedException) {
  3005.                     if (NclUtilities.IsFatal(unexpectedException))
  3006.                         throw;
  3007.                    
  3008.                     // This is highly unexpected but if happens would result into Aborted exception with caught one as an inner exception
  3009.                     httpResult = HttpProcessingResult.Continue;
  3010.                     E = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), unexpectedException, WebExceptionStatus.RequestCanceled, _HttpResponse);
  3011.                 }
  3012.                 finally {
  3013.                     if (httpResult == HttpProcessingResult.Continue) {
  3014.                         CancelTimer();
  3015.                        
  3016.                         if (!(E is WebException) && !(E is SecurityException)) {
  3017.                             if (_HttpResponse == null) {
  3018.                                 E = new WebException(E.Message, E);
  3019.                             }
  3020.                             else {
  3021.                                 E = new WebException(SR.GetString(SR.net_servererror, NetRes.GetWebStatusCodeString(ResponseStatusCode, _HttpResponse.StatusDescription)), E, WebExceptionStatus.ProtocolError, _HttpResponse);
  3022.                             }
  3023.                         }
  3024.                        
  3025.                         LazyAsyncResult writeAResult;
  3026.                         LazyAsyncResult readAResult = null;
  3027.                        
  3028.                         // Async Abort may happen at any time including when the request is being cleared
  3029.                         // and resubmitted hence using checked response.
  3030.                         HttpWebResponse chkResponse = _HttpResponse;
  3031.                        
  3032.                         lock (this) {
  3033.                             writeAResult = _WriteAResult;
  3034.                            
  3035.                             if (_ReadAResult == null) {
  3036.                                 _ReadAResult = new LazyAsyncResult(null, null, null, E);
  3037.                                 //never throws
  3038.                             }
  3039.                             else {
  3040.                                 readAResult = _ReadAResult;
  3041.                             }
  3042.                         }
  3043.                        
  3044.                         try {
  3045.                             FinishRequest(chkResponse, E);
  3046.                             //never throws
  3047.                             try {
  3048.                                 if (writeAResult != null) {
  3049.                                     writeAResult.InvokeCallback(E);
  3050.                                 }
  3051.                             }
  3052.                             finally {
  3053.                                 if (readAResult != null) {
  3054.                                     #if DEBUG
  3055.                                     callbackInvoked = true;
  3056.                                     #endif
  3057.                                     readAResult.InvokeCallback(E);
  3058.                                 }
  3059.                             }
  3060.                         }
  3061.                         finally {
  3062.                             chkResponse = _ReadAResult.Result as HttpWebResponse;
  3063.                            
  3064.                             // If the response was already set that exception closes it.
  3065.                             if (chkResponse != null) {
  3066.                                 chkResponse.Abort();
  3067.                                 //never throws
  3068.                             }
  3069.                            
  3070.                             if (CacheProtocol != null) {
  3071.                                 CacheProtocol.Abort();
  3072.                                 //never throws
  3073.                             }
  3074.                         }
  3075.                     }
  3076.                     #if DEBUG
  3077.                     else {
  3078.                         callbackInvoked = true;
  3079.                     }
  3080.                     #endif
  3081.                 }
  3082.                 GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", httpResult.ToString());
  3083.                 #if DEBUG
  3084.             }
  3085.             catch (Exception exception) {
  3086.                 t_LastStressException = exception;
  3087.                
  3088.                 if (!NclUtilities.IsFatal(exception)) {
  3089.                     GlobalLog.Assert(callbackInvoked, "HttpWebRequest#{0}::SetResponse|{1}", ValidationHelper.HashString(this), exception.Message);
  3090.                 }
  3091.                 throw;
  3092.             }
  3093.             #endif
  3094.         }
  3095.        
  3096.         #if DEBUG
  3097.         [ThreadStatic()]
  3098.         private static Exception t_LastStressException;
  3099.         private object m_AbortDelegateUsed;
  3100.         #endif
  3101.        
  3102.        
  3103. /*++
  3104.             BeginSubmitRequest: Begins Submit off a request to the network.
  3105.             This is called when we need to transmit an Async Request, but
  3106.             this function only servers to activate the submit, and does not
  3107.             actually block
  3108.             Called when we want to submit a request to the network. We do several
  3109.             things here - look for a proxy, find the service point, etc. In the
  3110.             end we call the service point to get access (via a stream) to the
  3111.             underlying connection, then serialize our headers onto that connection.
  3112.             The actual submission request to the service point is async, so we
  3113.             submit the request and then return, to allow the async to run its course.
  3114.             Input:
  3115.                 forceFind - insures that always get a new ServicePoint,
  3116.                     needed on redirects, or where the ServicePoint may have changed
  3117.             Returns: Nothing
  3118.         --*/       
  3119.        
  3120.         private void BeginSubmitRequest()
  3121.         {
  3122.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginSubmitRequest");
  3123.             GlobalLog.ThreadContract(ThreadKinds.User, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginSubmitRequest");
  3124.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginSubmitRequest() Method:" + Method + " Address:" + Address);
  3125.            
  3126.             SubmitRequest(FindServicePoint(false));
  3127.            
  3128.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginSubmitRequest");
  3129.         }
  3130.        
  3131.         private void SubmitRequest(ServicePoint servicePoint)
  3132.         {
  3133.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest");
  3134.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest");
  3135.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest() HaveResponse:" + HaveResponse + " Saw100Continue:" + Saw100Continue);
  3136.            
  3137.             if (!Async) {
  3138.                 _ConnectionAResult = new LazyAsyncResult(this, null, null);
  3139.                 _ConnectionReaderAResult = new LazyAsyncResult(this, null, null);
  3140.                 OpenWriteSideResponseWindow();
  3141.             }
  3142.            
  3143.             if (_Timer == null && !Async) {
  3144.                 _Timer = TimerQueue.CreateTimer(s_TimeoutCallback, this);
  3145.             }
  3146.            
  3147.             try {
  3148.                
  3149.                 if (_SubmitWriteStream != null && _SubmitWriteStream.IsPostStream) {
  3150.                     // _OldSubmitWriteStream is the stream that holds real user data
  3151.                     // In no case it can be overwritten.
  3152.                     // For multiple resubmits the ContentLength was set already, so no need call it again.
  3153.                     // on first resubmission the real user data hasn't been saved, so _OldSubmitWriteStream is null
  3154.                     GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest() (resubmit) firstResubmission:" + (_OldSubmitWriteStream == null) + " NtlmKeepAlive:" + NtlmKeepAlive);
  3155.                     if (_OldSubmitWriteStream == null) {
  3156.                         // save the real user data.
  3157.                         GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest() (resubmit) save the real user data _OldSubmitWriteStream#" + ValidationHelper.HashString(_OldSubmitWriteStream));
  3158.                         _OldSubmitWriteStream = _SubmitWriteStream;
  3159.                     }
  3160.                     // make sure we reformat the headers before resubmitting
  3161.                     _WriteBuffer = null;
  3162.                 }
  3163.                
  3164.                 m_Retry = false;
  3165.                
  3166.                 // If pre-authentication is requested call the AuthenticationManager
  3167.                 // and add authorization header if there is response
  3168.                 if (PreAuthenticate) {
  3169.                     if (UsesProxySemantics && _Proxy != null && _Proxy.Credentials != null)
  3170.                         ProxyAuthenticationState.PreAuthIfNeeded(this, _Proxy.Credentials);
  3171.                     if (Credentials != null)
  3172.                         ServerAuthenticationState.PreAuthIfNeeded(this, Credentials);
  3173.                 }
  3174.                
  3175.                 if (WriteBuffer == null) {
  3176.                     UpdateHeaders();
  3177.                 }
  3178.                
  3179.                 if (CheckCacheRetrieveBeforeSubmit()) {
  3180.                     // We are done and internal Response processing is kicked in
  3181.                     GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest CACHED RESPONSE");
  3182.                     return;
  3183.                 }
  3184.                
  3185.                 // At this point we are going to send a live request
  3186.                 // _AbortDelegate is set on submission process.
  3187.                 servicePoint.SubmitRequest(this, GetConnectionGroupLine());
  3188.             }
  3189.             finally {
  3190.                 if (!Async)
  3191.                     CheckWriteSideResponseProcessing();
  3192.             }
  3193.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest");
  3194.         }
  3195.        
  3196.        
  3197.         //
  3198.         // This method may be invoked as part of the request submission but
  3199.         // before the response is received
  3200.         // Return:
  3201.         // - True = response is ready
  3202.         // - False = Proceed with the request submission
  3203.         private bool CheckCacheRetrieveBeforeSubmit()
  3204.         {
  3205.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckCacheRetrieveBeforeSubmit");
  3206.            
  3207.             if (CacheProtocol == null) {
  3208.                 return false;
  3209.             }
  3210.            
  3211.             try {
  3212.                 Uri cacheUri = _Uri;
  3213.                 if (cacheUri.Fragment.Length != 0)
  3214.                     cacheUri = new Uri(cacheUri.GetParts(UriComponents.AbsoluteUri & ~UriComponents.Fragment, UriFormat.SafeUnescaped));
  3215.                
  3216.                 CacheProtocol.GetRetrieveStatus(cacheUri, this);
  3217.                
  3218.                 if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) {
  3219.                     throw CacheProtocol.ProtocolException;
  3220.                 }
  3221.                
  3222.                 if (CacheProtocol.ProtocolStatus != CacheValidationStatus.ReturnCachedResponse) {
  3223.                     return false;
  3224.                 }
  3225.                
  3226.                 if (HttpWriteMode != HttpWriteMode.None) {
  3227.                     throw new NotSupportedException(SR.GetString(SR.net_cache_not_supported_body));
  3228.                 }
  3229.                
  3230.                 // If we take it from cache, we have to kick in response processing
  3231.                 // The _CacheStream is good to return as the response stream.
  3232.                 HttpRequestCacheValidator ctx = (HttpRequestCacheValidator)CacheProtocol.Validator;
  3233.                 CoreResponseData responseData = new CoreResponseData();
  3234.                 responseData.m_IsVersionHttp11 = ctx.CacheHttpVersion.Equals(HttpVersion.Version11);
  3235.                 responseData.m_StatusCode = ctx.CacheStatusCode;
  3236.                 responseData.m_StatusDescription = ctx.CacheStatusDescription;
  3237.                 responseData.m_ResponseHeaders = ctx.CacheHeaders;
  3238.                 responseData.m_ContentLength = CacheProtocol.ResponseStreamLength;
  3239.                 responseData.m_ConnectStream = CacheProtocol.ResponseStream;
  3240.                 _HttpResponse = new HttpWebResponse(_Uri, CurrentMethod, responseData, _MediaType, UsesProxySemantics, AutomaticDecompression);
  3241.                 _HttpResponse.InternalSetFromCache = true;
  3242.                 _HttpResponse.InternalSetIsCacheFresh = (ctx.CacheFreshnessStatus != CacheFreshnessStatus.Stale);
  3243.                 ProcessResponse();
  3244.                 return true;
  3245.             }
  3246.             catch (Exception exception) {
  3247.                 Abort(exception, AbortState.Public);
  3248.                 throw;
  3249.             }
  3250.         }
  3251.        
  3252.         //
  3253.         // This method has to be invoked as part of the wire response processing.
  3254.         // The wire response can be replaced on return
  3255.         //
  3256.         // ATTN: If the method returns false, the response is invalid and should be retried
  3257.         //
  3258.         private bool CheckCacheRetrieveOnResponse()
  3259.         {
  3260.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckCacheRetrieveOnResponse");
  3261.            
  3262.             if (CacheProtocol == null) {
  3263.                 return true;
  3264.             }
  3265.            
  3266.             if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) {
  3267.                 throw CacheProtocol.ProtocolException;
  3268.             }
  3269.            
  3270.             Stream oldResponseStream = _HttpResponse.ResponseStream;
  3271.            
  3272.             CacheProtocol.GetRevalidateStatus(_HttpResponse, _HttpResponse.ResponseStream);
  3273.            
  3274.             if (CacheProtocol.ProtocolStatus == CacheValidationStatus.RetryResponseFromServer) {
  3275.                 // Try to resubmit or fail
  3276.                 return false;
  3277.             }
  3278.            
  3279.             if (CacheProtocol.ProtocolStatus != CacheValidationStatus.ReturnCachedResponse && CacheProtocol.ProtocolStatus != CacheValidationStatus.CombineCachedAndServerResponse) {
  3280.                 // Take current response
  3281.                 return true;
  3282.             }
  3283.            
  3284.             if (HttpWriteMode != HttpWriteMode.None) {
  3285.                 // This should never happen in real life
  3286.                 throw new NotSupportedException(SR.GetString(SR.net_cache_not_supported_body));
  3287.             }
  3288.            
  3289.             CoreResponseData responseData = new CoreResponseData();
  3290.             HttpRequestCacheValidator ctx = (HttpRequestCacheValidator)CacheProtocol.Validator;
  3291.             // If we take it from cache, we have to replace the live response if any
  3292.             responseData.m_IsVersionHttp11 = ctx.CacheHttpVersion.Equals(HttpVersion.Version11);
  3293.             responseData.m_StatusCode = ctx.CacheStatusCode;
  3294.             responseData.m_StatusDescription = ctx.CacheStatusDescription;
  3295.            
  3296.             responseData.m_ResponseHeaders = CacheProtocol.ProtocolStatus == CacheValidationStatus.CombineCachedAndServerResponse ? new WebHeaderCollection(ctx.CacheHeaders) : ctx.CacheHeaders;
  3297.            
  3298.             responseData.m_ContentLength = CacheProtocol.ResponseStreamLength;
  3299.             responseData.m_ConnectStream = CacheProtocol.ResponseStream;
  3300.            
  3301.             _HttpResponse = new HttpWebResponse(_Uri, CurrentMethod, responseData, _MediaType, UsesProxySemantics, AutomaticDecompression);
  3302.            
  3303.             if (CacheProtocol.ProtocolStatus == CacheValidationStatus.ReturnCachedResponse) {
  3304.                 _HttpResponse.InternalSetFromCache = true;
  3305.                 _HttpResponse.InternalSetIsCacheFresh = CacheProtocol.IsCacheFresh;
  3306.                
  3307.                 // can only dispose the response stream when not combining the streams
  3308.                 // Note the response itself may still be needed for cache update call.
  3309.                 if (oldResponseStream != null) {
  3310.                     try {
  3311.                         oldResponseStream.Close();
  3312.                     }
  3313.                     catch {
  3314.                     }
  3315.                 }
  3316.             }
  3317.             return true;
  3318.         }
  3319.        
  3320.         //
  3321.         // This will decide on cache update and construct the effective response
  3322.         //
  3323.         // Possible CacheStatus on Input:
  3324.         // - Bypass = exit from the method, now
  3325.         // - FromCache = Take from cache, do not update the headers (see Bypass))
  3326.         // - Proceed = Take the cached response, ask for cache Context update
  3327.         // - NoCache = Take the live response, ask for cache update
  3328.         //
  3329.         private void CheckCacheUpdateOnResponse()
  3330.         {
  3331.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckCacheUpdateOnResponse");
  3332.            
  3333.             if (CacheProtocol == null) {
  3334.                 return;
  3335.             }
  3336.            
  3337.             if (CacheProtocol.GetUpdateStatus(_HttpResponse, _HttpResponse.ResponseStream) == CacheValidationStatus.UpdateResponseInformation) {
  3338.                 _HttpResponse.ResponseStream = CacheProtocol.ResponseStream;
  3339.             }
  3340.             else if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail)
  3341.                 throw CacheProtocol.ProtocolException;
  3342.         }
  3343.        
  3344. /*++
  3345.         EndSubmitRequest: End Submit off a request
  3346.         This function is invoked by a connection ready callback and continues the request by submitting its headers.
  3347.         --*/       
  3348.         private void EndSubmitRequest()
  3349.         {
  3350.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndSubmitRequest");
  3351.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndSubmitRequest");
  3352.            
  3353.             try {
  3354.                
  3355.                 //
  3356.                 // check to see if we need to buffer the headers and send them at
  3357.                 // a later time, when we know content length
  3358.                 //
  3359.                 if (HttpWriteMode == HttpWriteMode.Buffer) {
  3360.                     InvokeGetRequestStreamCallback();
  3361.                     GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndSubmitRequest", "InvokeGetRequestStreamCallback(HttpWriteMode==HttpWriteMode.Buffer)");
  3362.                     return;
  3363.                 }
  3364.                
  3365.                 // gather header bytes and write them to the stream
  3366.                 if (WriteBuffer == null) {
  3367.                     long result = SwitchToContentLength();
  3368.                     SerializeHeaders();
  3369.                     PostSwitchToContentLength(result);
  3370.                 }
  3371.                
  3372.                 GlobalLog.Assert(WriteBuffer != null && WriteBuffer[0] < 128 && WriteBuffer[0] != 0, "HttpWebRequest#{0}::EndSubmitRequest()|Invalid WriteBuffer generated.", ValidationHelper.HashString(this));
  3373.                
  3374.                 _SubmitWriteStream.WriteHeaders(Async);
  3375.             }
  3376.             catch {
  3377.                 // We depend on this to unblock possible response processing in case of unexpected failure
  3378.                 ConnectStream chkStream = _SubmitWriteStream;
  3379.                 if (chkStream != null)
  3380.                     chkStream.CallDone();
  3381.                
  3382.                 throw;
  3383.             }
  3384.             finally {
  3385.                 if (!Async)
  3386.                     CheckWriteSideResponseProcessing();
  3387.             }
  3388.            
  3389.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndSubmitRequest");
  3390.         }
  3391.        
  3392.        
  3393. /*++
  3394.             EndWriteHeaders: End write of headers
  3395.             This Typically called by a callback that wishes to proceed
  3396.             with the finalization of writing headers
  3397.             Input: Nothing.
  3398.             Returns: bool - true if success, false if we need to go pending
  3399.         --*/       
  3400.         internal bool EndWriteHeaders(bool async)
  3401.         {
  3402.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders async:" + async.ToString());
  3403.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders");
  3404.            
  3405.             try {
  3406.                 //
  3407.                 // if sending data and we sent a 100-continue to a 1.1 or better
  3408.                 // server then synchronize with the 100-continue intermediate
  3409.                 // response (or a final failure response)
  3410.                 //
  3411.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders() ContentLength:" + ContentLength + " HttpWriteMode:" + HttpWriteMode + " _ServicePoint.Understands100Continue:" + _ServicePoint.Understands100Continue + " ExpectContinue:" + ExpectContinue);
  3412.                 if ((ContentLength > 0 || HttpWriteMode == HttpWriteMode.Chunked) && ExpectContinue && _ServicePoint.Understands100Continue) {
  3413.                     if (async ? m_ContinueGate.StartTrigger(true) : m_ContinueGate.Trigger(true)) {
  3414.                         if (async) {
  3415.                             try {
  3416.                                 // If we haven't already received the continue, set a timer.
  3417.                                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders() starting timer for 100Continue, timeout:" + DefaultContinueTimeout.ToString());
  3418.                                 GlobalLog.Assert(m_ContinueTimer == null, "HttpWebRequest#{0}::EndWriteHeaders()|Timer already set.", ValidationHelper.HashString(this));
  3419.                                 m_ContinueTimer = s_ContinueTimerQueue.CreateTimer(s_ContinueTimeoutCallback, this);
  3420.                             }
  3421.                             finally {
  3422.                                 m_ContinueGate.FinishTrigger();
  3423.                             }
  3424.                            
  3425.                             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders", false);
  3426.                             return false;
  3427.                         }
  3428.                         else {
  3429.                             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders() calling PollAndRead()");
  3430.                             // On the Sync Path, we need to poll the Connection to see if there is any Data
  3431.                             _SubmitWriteStream.PollAndRead(UserRetrievedWriteStream);
  3432.                             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders", true);
  3433.                             return true;
  3434.                         }
  3435.                     }
  3436.                 }
  3437.                
  3438.                 // No continue expected or it was already received. Move forward.
  3439.                 EndWriteHeaders_Part2();
  3440.             }
  3441.             catch {
  3442.                 // We depend on this to unblock possible response processing in case of unexpected failure
  3443.                 ConnectStream chkStream = _SubmitWriteStream;
  3444.                 if (chkStream != null)
  3445.                     chkStream.CallDone();
  3446.                
  3447.                 throw;
  3448.             }
  3449.            
  3450.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders", true);
  3451.             return true;
  3452.         }
  3453.        
  3454.         // This can never call into user code or block, because it's called by the TimerThread.
  3455.         private static void ContinueTimeoutCallback(TimerThread.Timer timer, int timeNoticed, object context)
  3456.         {
  3457.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(context) + "::ContinueTimeoutCallback");
  3458.             GlobalLog.ThreadContract(ThreadKinds.Unknown, ThreadKinds.SafeSources | ThreadKinds.Timer, "HttpWebRequest#" + ValidationHelper.HashString(context) + "::ContinueTimeoutCallback");
  3459.            
  3460.             HttpWebRequest thisHttpWebRequest = (HttpWebRequest)context;
  3461.            
  3462.             if (thisHttpWebRequest.HttpWriteMode == HttpWriteMode.None) {
  3463.                 GlobalLog.Assert("HttpWebRequest#" + ValidationHelper.HashString(thisHttpWebRequest) + "::CompleteContinueGate()", "Not a POST type request, must not come here.");
  3464.                 return;
  3465.             }
  3466.            
  3467.             // Complete the 100 Continue gate. If this completes it, clean up the timer.
  3468.             if (thisHttpWebRequest.CompleteContinueGate()) {
  3469.                 GlobalLog.Assert(thisHttpWebRequest.m_ContinueTimer == timer, "HttpWebRequest#{0}::ContinueTimeoutCallback|Timers don't match.", ValidationHelper.HashString(thisHttpWebRequest));
  3470.                 thisHttpWebRequest.m_ContinueTimer = null;
  3471.             }
  3472.            
  3473.             // Always call this. Otherwise the timer should have been successfully cancelled.
  3474.             //
  3475.             // We have to put it on a threadpool thread since it may call user code. This is not
  3476.             // a critical path for perf.
  3477.             ThreadPool.UnsafeQueueUserWorkItem(s_EndWriteHeaders_Part2Callback, thisHttpWebRequest);
  3478.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(thisHttpWebRequest) + "::ContinueTimeoutCallback");
  3479.         }
  3480.        
  3481.         //
  3482.         private bool CompleteContinueGate()
  3483.         {
  3484.             return m_ContinueGate.Complete();
  3485.         }
  3486.         private static void EndWriteHeaders_Part2Wrapper(object state)
  3487.         {
  3488.             #if DEBUG
  3489.             GlobalLog.SetThreadSource(ThreadKinds.Worker);
  3490.             using (GlobalLog.SetThreadKind(ThreadKinds.System)) {
  3491.                 #endif
  3492.                 GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(state) + "::EndWriteHeaders_Part2Wrapper");
  3493.                 ((HttpWebRequest)state).EndWriteHeaders_Part2();
  3494.                 GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(state) + "::EndWriteHeaders_Part2Wrapper");
  3495.                 #if DEBUG
  3496.             }
  3497.             #endif
  3498.         }
  3499.        
  3500.         internal void EndWriteHeaders_Part2()
  3501.         {
  3502.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2");
  3503.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2");
  3504.            
  3505.             try {
  3506.                 ConnectStream submitWriteStream = _SubmitWriteStream;
  3507.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2() ConnectStream#" + ValidationHelper.HashString(submitWriteStream) + " HttpWriteMode:" + HttpWriteMode + " HaveResponse:" + HaveResponse);
  3508.                 if (HttpWriteMode != HttpWriteMode.None) {
  3509.                     m_BodyStarted = true;
  3510.                    
  3511.                     GlobalLog.Assert(submitWriteStream != null, "HttpWebRequest#{0}::EndWriteHeaders_Part2()|submitWriteStream == null", ValidationHelper.HashString(this));
  3512.                     //
  3513.                     // We always need to buffer because some servers send
  3514.                     // 100 Continue even when they mean to redirect,
  3515.                     // so we waste the cycles with buffering
  3516.                     //
  3517.                     GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2() AllowWriteStreamBuffering:" + AllowWriteStreamBuffering);
  3518.                     if (AllowWriteStreamBuffering) {
  3519.                         GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2() BufferOnly:" + submitWriteStream.BufferOnly + " _OldSubmitWriteStream#" + ValidationHelper.HashString(_OldSubmitWriteStream) + " submitWriteStream#" + ValidationHelper.HashString(submitWriteStream));
  3520.                         if (submitWriteStream.BufferOnly) {
  3521.                             //
  3522.                             // if the ConnectStream was buffering the headers then
  3523.                             // there will not be an OldSubmitWriteStream. set it
  3524.                             // now to the newly created one.
  3525.                             //
  3526.                             _OldSubmitWriteStream = submitWriteStream;
  3527.                         }
  3528.                         if (_OldSubmitWriteStream != null) {
  3529.                             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2() _OldSubmitWriteStream#" + ValidationHelper.HashString(_OldSubmitWriteStream) + " NtlmKeepAlive:" + NtlmKeepAlive);
  3530.                             #if DEBUG
  3531.                             using (GlobalLog.SetThreadKind(ThreadKinds.Sync)) {
  3532.                                 #endif
  3533.                                 submitWriteStream.ResubmitWrite(_OldSubmitWriteStream, (NtlmKeepAlive && ContentLength == 0));
  3534.                                 #if DEBUG
  3535.                             }
  3536.                             #endif
  3537.                             submitWriteStream.CloseInternal(true);
  3538.                         }
  3539.                     }
  3540.                 }
  3541.                 else {
  3542.                     // if (HttpWriteMode == HttpWriteMode.None) {
  3543.                     if (submitWriteStream != null) {
  3544.                         // close stream so the headers get sent
  3545.                         submitWriteStream.CloseInternal(true);
  3546.                         // disable write stream
  3547.                         submitWriteStream = null;
  3548.                     }
  3549.                     _OldSubmitWriteStream = null;
  3550.                 }
  3551.                
  3552.                 // callback processing - notify our caller that we're done
  3553.                 InvokeGetRequestStreamCallback();
  3554.             }
  3555.             catch {
  3556.                 // We depend on this to unblock possible response processing in case of unexpected failure
  3557.                 ConnectStream chkStream = _SubmitWriteStream;
  3558.                 if (chkStream != null)
  3559.                     chkStream.CallDone();
  3560.                
  3561.                 //
  3562.                 // Here we don't expect any exceptions and if got some from the user code then propagate it up.
  3563.                 //
  3564.                 throw;
  3565.             }
  3566.            
  3567.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2");
  3568.         }
  3569.        
  3570. /*++
  3571.         Routine Description:
  3572.             Assembles the status line for an HTTP request
  3573.             specifically for CONNECT style verbs, that create a pipe
  3574.         Arguments:
  3575.             headersSize - size of the Header string that we send after
  3576.                 this request line
  3577.         Return Value:
  3578.             int - number of bytes written out
  3579.         --*/       
  3580.         private int GenerateConnectRequestLine(int headersSize)
  3581.         {
  3582.             int offset = 0;
  3583.             string host = ConnectHostAndPort;
  3584.            
  3585.             //
  3586.             // Handle Connect Case, i.e. "CONNECT hostname.domain.edu:999"
  3587.             //
  3588.            
  3589.             int writeBufferLength = CurrentMethod.Name.Length + host.Length + RequestLineConstantSize + headersSize;
  3590.            
  3591.             _WriteBuffer = new byte[writeBufferLength];
  3592.             offset = Encoding.ASCII.GetBytes(CurrentMethod.Name, 0, CurrentMethod.Name.Length, WriteBuffer, 0);
  3593.             WriteBuffer[offset++] = (byte)' ';
  3594.             offset += Encoding.ASCII.GetBytes(host, 0, host.Length, WriteBuffer, offset);
  3595.             WriteBuffer[offset++] = (byte)' ';
  3596.             return offset;
  3597.         }
  3598.        
  3599.         internal string ConnectHostAndPort {
  3600.             get {
  3601.                 if (!IsTunnelRequest) {
  3602.                     return _Uri.GetParts(UriComponents.HostAndPort, UriFormat.UriEscaped);
  3603.                 }
  3604.                 else {
  3605.                     return _OriginUri.GetParts(UriComponents.HostAndPort, UriFormat.UriEscaped);
  3606.                 }
  3607.             }
  3608.         }
  3609.        
  3610. /*++
  3611.         Routine Description:
  3612.             Assembles the status line for an HTTP request
  3613.             specifically to a proxy...
  3614.         Arguments:
  3615.             headersSize - size of the Header string that we send after
  3616.                 this request line
  3617.         Return Value:
  3618.             int - number of bytes written out
  3619.         --*/       
  3620.         private int GenerateProxyRequestLine(int headersSize)
  3621.         {
  3622.             int offset = 0;
  3623.            
  3624.             //
  3625.             string requestUrl;
  3626.            
  3627.             if ((object)_Uri.Scheme == (object)Uri.UriSchemeFtp) {
  3628.                 string userInfo = _Uri.GetParts(UriComponents.UserInfo | UriComponents.KeepDelimiter, UriFormat.UriEscaped);
  3629.                 if (userInfo != "") {
  3630.                     requestUrl = _Uri.GetParts(UriComponents.HttpRequestUrl | UriComponents.UserInfo, UriFormat.UriEscaped);
  3631.                 }
  3632.                 else {
  3633.                     string username = null;
  3634.                     string password = null;
  3635.                     NetworkCredential networkCreds = Credentials.GetCredential(_Uri, "basic");
  3636.                     if (networkCreds != null && (object)networkCreds != (object)FtpWebRequest.DefaultNetworkCredential) {
  3637.                         username = networkCreds.InternalGetDomainUserName();
  3638.                         password = networkCreds.InternalGetPassword();
  3639.                         password = (password == null) ? string.Empty : password;
  3640.                     }
  3641.                     if (username != null) {
  3642.                         string scheme = _Uri.GetParts(UriComponents.Scheme | UriComponents.KeepDelimiter, UriFormat.UriEscaped);
  3643.                         string urlMinusScheme = _Uri.GetParts(UriComponents.HttpRequestUrl & ~UriComponents.Scheme, UriFormat.UriEscaped);
  3644.                        
  3645.                         // For FTP proxy we don't escape the username and password strings
  3646.                         // Since some servers don't seem to support it
  3647.                         // Only escape the absolute minimum that is required for
  3648.                         // a valid Uri which is (: \ / ? # %)
  3649.                         username = username.Replace(":", "%3A");
  3650.                         password = password.Replace(":", "%3A");
  3651.                         username = username.Replace("\\", "%5C");
  3652.                         password = password.Replace("\\", "%5C");
  3653.                         username = username.Replace("/", "%2F");
  3654.                         password = password.Replace("/", "%2F");
  3655.                         username = username.Replace("?", "%3F");
  3656.                         password = password.Replace("?", "%3F");
  3657.                         username = username.Replace("#", "%23");
  3658.                         password = password.Replace("#", "%23");
  3659.                         username = username.Replace("%", "%25");
  3660.                         password = password.Replace("%", "%25");
  3661.                         username = username.Replace("@", "%40");
  3662.                         password = password.Replace("@", "%40");
  3663.                         requestUrl = scheme + username + ":" + password + "@" + urlMinusScheme;
  3664.                         requestUrl = new Uri(requestUrl).AbsoluteUri;
  3665.                     }
  3666.                     else {
  3667.                         requestUrl = _Uri.GetParts(UriComponents.HttpRequestUrl, UriFormat.UriEscaped);
  3668.                     }
  3669.                 }
  3670.             }
  3671.             else {
  3672.                 requestUrl = _Uri.GetParts(UriComponents.HttpRequestUrl, UriFormat.UriEscaped);
  3673.             }
  3674.            
  3675.             int writeBufferLength = CurrentMethod.Name.Length + requestUrl.Length + RequestLineConstantSize + headersSize;
  3676.            
  3677.             _WriteBuffer = new byte[writeBufferLength];
  3678.             offset = Encoding.ASCII.GetBytes(CurrentMethod.Name, 0, CurrentMethod.Name.Length, WriteBuffer, 0);
  3679.             WriteBuffer[offset++] = (byte)' ';
  3680.             offset += Encoding.ASCII.GetBytes(requestUrl, 0, requestUrl.Length, WriteBuffer, offset);
  3681.             WriteBuffer[offset++] = (byte)' ';
  3682.             return offset;
  3683.         }
  3684.        
  3685. /*++
  3686.         Routine Description:
  3687.             Assembles the status/request line for the request.
  3688.         Arguments:
  3689.             headersSize - size of the Header string that we send after
  3690.                 this request line
  3691.         Return Value:
  3692.             int - number of bytes written
  3693.         --*/       
  3694.         private int GenerateRequestLine(int headersSize)
  3695.         {
  3696.             int offset = 0;
  3697.             string pathAndQuery = _Uri.PathAndQuery;
  3698.            
  3699.             int writeBufferLength = CurrentMethod.Name.Length + pathAndQuery.Length + RequestLineConstantSize + headersSize;
  3700.            
  3701.             _WriteBuffer = new byte[writeBufferLength];
  3702.             offset = Encoding.ASCII.GetBytes(CurrentMethod.Name, 0, CurrentMethod.Name.Length, WriteBuffer, 0);
  3703.             WriteBuffer[offset++] = (byte)' ';
  3704.             offset += Encoding.ASCII.GetBytes(pathAndQuery, 0, pathAndQuery.Length, WriteBuffer, offset);
  3705.             WriteBuffer[offset++] = (byte)' ';
  3706.             return offset;
  3707.         }
  3708.        
  3709. /*++
  3710.         Routine Description:
  3711.             Assembles the data/headers for an HTTP request
  3712.             into a buffer
  3713.         Arguments:
  3714.             none.
  3715.         Return Value:
  3716.             none.
  3717.         --*/       
  3718.         internal void UpdateHeaders()
  3719.         {
  3720.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::UpdateHeaders");
  3721.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::UpdateHeaders");
  3722.            
  3723.             // Set HostName Header
  3724.             _HttpRequestHeaders.ChangeInternal(HttpKnownHeaderNames.Host, (_Uri.IsDefaultPort ? _Uri.Host : ConnectHostAndPort));
  3725.             // about to create the headers we're going to send. Check if any
  3726.             // modules want to inspect or modify them
  3727.             if (_CookieContainer != null) {
  3728.                 CookieModule.OnSendingHeaders(this);
  3729.             }
  3730.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::UpdateHeaders");
  3731.         }
  3732.        
  3733.         //
  3734.         // The method is called right before sending headers to the wire
  3735.         // The result is updated internal _WriteBuffer
  3736.         //
  3737.         internal void SerializeHeaders()
  3738.         {
  3739.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::UpdateHeaders");
  3740.            
  3741.             //
  3742.             // If we have content-length, use it, if we don't check for chunked
  3743.             // sending mode, otherwise, if -1, then see to closing the connection.
  3744.             // There's one extra case in which the user didn't set the ContentLength and is
  3745.             // not chunking either. In this case we buffer the data, but to the time of that
  3746.             // method call the content length is already known.
  3747.             //
  3748.             GlobalLog.Assert(HttpWriteMode != HttpWriteMode.Unknown, "HttpWebRequest#{0}::SerializeHeaders()|HttpWriteMode:{1}", ValidationHelper.HashString(this), HttpWriteMode);
  3749.             if (HttpWriteMode != HttpWriteMode.None) {
  3750.                 if (HttpWriteMode == HttpWriteMode.Chunked) {
  3751.                     GlobalLog.Assert(!CurrentMethod.ContentBodyNotAllowed, "HttpWebRequest#{0}::SerializeHeaders()|!ContentBodyNotAllowed CurrentMethod:{1} HttpWriteMode:{2} ContentLength:{3}", ValidationHelper.HashString(this), CurrentMethod, HttpWriteMode, ContentLength);
  3752.                     _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.TransferEncoding, ChunkedHeader);
  3753.                 }
  3754.                 else if (ContentLength >= 0) {
  3755.                     GlobalLog.Assert(HttpWriteMode == HttpWriteMode.ContentLength, "HttpWebRequest#{0}::SerializeHeaders()|HttpWriteMode:{1}", ValidationHelper.HashString(this), HttpWriteMode);
  3756.                     GlobalLog.Assert(!CurrentMethod.ContentBodyNotAllowed, "HttpWebRequest#{0}::SerializeHeaders()|!ContentBodyNotAllowed CurrentMethod:{1} HttpWriteMode:{2} ContentLength:{3}", ValidationHelper.HashString(this), CurrentMethod, HttpWriteMode, ContentLength);
  3757.                     _HttpRequestHeaders.ChangeInternal(HttpKnownHeaderNames.ContentLength, _ContentLength.ToString(NumberFormatInfo.InvariantInfo));
  3758.                 }
  3759.                 ExpectContinue = ExpectContinue && !IsVersionHttp10 && ServicePoint.Expect100Continue;
  3760.                 if ((ContentLength > 0 || HttpWriteMode == HttpWriteMode.Chunked) && ExpectContinue) {
  3761.                     _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.Expect, ContinueHeader);
  3762.                 }
  3763.             }
  3764.            
  3765.             if ((AutomaticDecompression & DecompressionMethods.GZip) != 0) {
  3766.                
  3767.                 if ((AutomaticDecompression & DecompressionMethods.Deflate) != 0) {
  3768.                     _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.AcceptEncoding, GZipHeader + ", " + DeflateHeader);
  3769.                 }
  3770.                 else {
  3771.                     _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.AcceptEncoding, GZipHeader);
  3772.                 }
  3773.             }
  3774.             else if ((AutomaticDecompression & DecompressionMethods.Deflate) != 0) {
  3775.                 _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.AcceptEncoding, DeflateHeader);
  3776.             }
  3777.            
  3778.             //
  3779.             // Behavior from Wininet, on Uris with Proxies, send Proxy-Connection: instead
  3780.             // of Connection:
  3781.             //
  3782.             string connectionString = HttpKnownHeaderNames.Connection;
  3783.             if (UsesProxySemantics) {
  3784.                 _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Connection);
  3785.                 connectionString = HttpKnownHeaderNames.ProxyConnection;
  3786.                 if (!ValidationHelper.IsBlankString(Connection)) {
  3787.                     _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.ProxyConnection, _HttpRequestHeaders[HttpKnownHeaderNames.Connection]);
  3788.                 }
  3789.             }
  3790.             else {
  3791.                 _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.ProxyConnection);
  3792.             }
  3793.            
  3794.             if (KeepAlive || NtlmKeepAlive) {
  3795.                 GlobalLog.Assert(_ServicePoint != null, "HttpWebRequest#{0}::SerializeHeaders()|_ServicePoint == null", ValidationHelper.HashString(this));
  3796.                 if (IsVersionHttp10 || ServicePoint.HttpBehaviour <= HttpBehaviour.HTTP10) {
  3797.                     _HttpRequestHeaders.AddInternal((UsesProxySemantics ? HttpKnownHeaderNames.ProxyConnection : HttpKnownHeaderNames.Connection), "Keep-Alive");
  3798.                 }
  3799.             }
  3800.             else if (!IsVersionHttp10) {
  3801.                 _HttpRequestHeaders.AddInternal(connectionString, "Close");
  3802.             }
  3803.            
  3804.            
  3805.             //
  3806.             // Now create our headers by calling ToString, and then
  3807.             // create a HTTP Request Line to go with it.
  3808.             //
  3809.            
  3810.             int offset;
  3811.             string requestHeadersString = _HttpRequestHeaders.ToString();
  3812.             int requestHeadersSize = WebHeaderCollection.HeaderEncoding.GetByteCount(requestHeadersString);
  3813.            
  3814.             // NOTE: Perhaps we should cache this on this-object in the future?
  3815.             if (CurrentMethod.ConnectRequest) {
  3816.                 // for connect verbs we need to specially handle it.
  3817.                 offset = GenerateConnectRequestLine(requestHeadersSize);
  3818.             }
  3819.             else if (UsesProxySemantics) {
  3820.                 // depending on whether, we have a proxy, generate a proxy or normal request
  3821.                 offset = GenerateProxyRequestLine(requestHeadersSize);
  3822.             }
  3823.             else {
  3824.                 // default case for normal HTTP requests
  3825.                 offset = GenerateRequestLine(requestHeadersSize);
  3826.             }
  3827.            
  3828.             Buffer.BlockCopy(HttpBytes, 0, WriteBuffer, offset, HttpBytes.Length);
  3829.             offset += HttpBytes.Length;
  3830.            
  3831.             WriteBuffer[offset++] = (byte)'1';
  3832.             WriteBuffer[offset++] = (byte)'.';
  3833.             WriteBuffer[offset++] = IsVersionHttp10 ? (byte)'0' : (byte)'1';
  3834.             WriteBuffer[offset++] = (byte)'\r';
  3835.             WriteBuffer[offset++] = (byte)'\n';
  3836.             if (Logging.On)
  3837.                 Logging.PrintInfo(Logging.Web, this, "Request: " + Encoding.ASCII.GetString(WriteBuffer, 0, offset));
  3838.             //
  3839.             // Serialze the headers out to the byte Buffer,
  3840.             // by converting them to bytes from UNICODE
  3841.             //
  3842.             WebHeaderCollection.HeaderEncoding.GetBytes(requestHeadersString, 0, requestHeadersString.Length, WriteBuffer, offset);
  3843.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SerializeHeaders(), bytesCount = " + offset.ToString());
  3844.         }
  3845.        
  3846.        
  3847.         //
  3848.         // PERF:
  3849.         // removed some double initializations.
  3850.         // perf went from:
  3851.         // clocks per instruction CPI: 9,098.72 to 1,301.14
  3852.         // %app exclusive time: 2.92 to 0.43
  3853.         //
  3854.         /// <devdoc>
  3855.         /// <para>
  3856.         /// Basic Constructor for HTTP Protocol Class, Initializes to basic header state.
  3857.         /// </para>
  3858.         /// </devdoc>
  3859.         internal HttpWebRequest(Uri uri, ServicePoint servicePoint)
  3860.         {
  3861.             if (Logging.On)
  3862.                 Logging.Enter(Logging.Web, this, "HttpWebRequest", uri);
  3863.            
  3864.             (new WebPermission(NetworkAccess.Connect, uri)).Demand();
  3865.            
  3866.             // OOPS, This ctor can also be called with FTP scheme but then it should only allowed if going through the proxy
  3867.             // Something to think about...
  3868.             //if ((object)uri.Scheme != (object)Uri.UriSchemeHttp && (object)uri.Scheme != (object)Uri.UriSchemeHttps)
  3869.             //throw new ArgumentOutOfRangeException("uri");
  3870.            
  3871.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::.ctor(" + uri.ToString() + ")");
  3872.             //
  3873.             // internal constructor, HttpWebRequest cannot be created directly
  3874.             // but only through WebRequest.Create() method
  3875.             // set defaults
  3876.             //
  3877.             _HttpRequestHeaders = new WebHeaderCollection(WebHeaderCollectionType.HttpWebRequest);
  3878.             _Proxy = WebRequest.InternalDefaultWebProxy;
  3879.             _HttpWriteMode = HttpWriteMode.Unknown;
  3880.             _MaximumAllowedRedirections = 50;
  3881.             _Timeout = WebRequest.DefaultTimeout;
  3882.             _TimerQueue = WebRequest.DefaultTimerQueue;
  3883.             _ReadWriteTimeout = DefaultReadWriteTimeout;
  3884.             _MaximumResponseHeadersLength = DefaultMaximumResponseHeadersLength;
  3885.             _ContentLength = -1;
  3886.             _OriginVerb = KnownHttpVerb.Get;
  3887.             _OriginUri = uri;
  3888.             _Uri = _OriginUri;
  3889.             _ServicePoint = servicePoint;
  3890.             _RequestIsAsync = TriState.Unspecified;
  3891.            
  3892.             SetupCacheProtocol(_OriginUri);
  3893.            
  3894.            
  3895.             if (Logging.On)
  3896.                 Logging.Exit(Logging.Web, this, "HttpWebRequest", null);
  3897.         }
  3898.        
  3899.         internal HttpWebRequest(Uri proxyUri, Uri requestUri, HttpWebRequest orginalRequest) : this(proxyUri, null)
  3900.         {
  3901.            
  3902.             GlobalLog.Enter("HttpWebRequest::HttpWebRequest", "proxyUri=" + proxyUri + ", requestUri=" + requestUri);
  3903.            
  3904.             _OriginVerb = KnownHttpVerb.Parse("CONNECT");
  3905.            
  3906.             //
  3907.             // CONNECT requests cannot be pipelined
  3908.             //
  3909.            
  3910.             Pipelined = false;
  3911.            
  3912.             //
  3913.             // each CONNECT request has a unique connection group name to avoid
  3914.             // non-CONNECT requests being made over the same connection
  3915.             //
  3916.            
  3917.             _OriginUri = requestUri;
  3918.             IsTunnelRequest = true;
  3919.            
  3920.             _ConnectionGroupName = ServicePointManager.SpecialConnectGroupName + "(" + UniqueGroupId + ")";
  3921.             m_InternalConnectionGroup = true;
  3922.            
  3923.             //
  3924.             // the CONNECT request must respond to a 407 as if it were a 401.
  3925.             // So we set up the server authentication state as if for a proxy
  3926.             //
  3927.             ServerAuthenticationState = new AuthenticationState(true);
  3928.            
  3929.             // CONNECT request is not suitable for caching
  3930.             CacheProtocol = null;
  3931.            
  3932.             GlobalLog.Leave("HttpWebRequest::HttpWebRequest");
  3933.         }
  3934.        
  3935.         /// <devdoc>
  3936.         /// <para>ISerializable constructor</para>
  3937.         /// </devdoc>
  3938.         [Obsolete("Serialization is obsoleted for this type. http://go.microsoft.com/fwlink/?linkid=14202")]
  3939.         [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
  3940. /*private*/        protected HttpWebRequest(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext)
  3941.         {
  3942.             #if DEBUG
  3943.             using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
  3944.                 #endif
  3945.                 ExceptionHelper.WebPermissionUnrestricted.Demand();
  3946.                 if (Logging.On)
  3947.                     Logging.Enter(Logging.Web, this, "HttpWebRequest", serializationInfo);
  3948.                
  3949.                 _HttpRequestHeaders = (WebHeaderCollection)serializationInfo.GetValue("_HttpRequestHeaders", typeof(WebHeaderCollection));
  3950.                 _Proxy = (IWebProxy)serializationInfo.GetValue("_Proxy", typeof(IWebProxy));
  3951.                 KeepAlive = serializationInfo.GetBoolean("_KeepAlive");
  3952.                 Pipelined = serializationInfo.GetBoolean("_Pipelined");
  3953.                 AllowAutoRedirect = serializationInfo.GetBoolean("_AllowAutoRedirect");
  3954.                 AllowWriteStreamBuffering = serializationInfo.GetBoolean("_AllowWriteStreamBuffering");
  3955.                 HttpWriteMode = (HttpWriteMode)serializationInfo.GetInt32("_HttpWriteMode");
  3956.                 _MaximumAllowedRedirections = serializationInfo.GetInt32("_MaximumAllowedRedirections");
  3957.                 _AutoRedirects = serializationInfo.GetInt32("_AutoRedirects");
  3958.                 _Timeout = serializationInfo.GetInt32("_Timeout");
  3959.                 try {
  3960.                     _ReadWriteTimeout = serializationInfo.GetInt32("_ReadWriteTimeout");
  3961.                 }
  3962.                 catch {
  3963.                     _ReadWriteTimeout = DefaultReadWriteTimeout;
  3964.                 }
  3965.                 try {
  3966.                     _MaximumResponseHeadersLength = serializationInfo.GetInt32("_MaximumResponseHeadersLength");
  3967.                 }
  3968.                 catch {
  3969.                     _MaximumResponseHeadersLength = DefaultMaximumResponseHeadersLength;
  3970.                 }
  3971.                 _ContentLength = serializationInfo.GetInt64("_ContentLength");
  3972.                 _MediaType = serializationInfo.GetString("_MediaType");
  3973.                 _OriginVerb = KnownHttpVerb.Parse(serializationInfo.GetString("_OriginVerb"));
  3974.                 _ConnectionGroupName = serializationInfo.GetString("_ConnectionGroupName");
  3975.                 ProtocolVersion = (Version)serializationInfo.GetValue("_Version", typeof(Version));
  3976.                 _OriginUri = (Uri)serializationInfo.GetValue("_OriginUri", typeof(Uri));
  3977.                
  3978.                 SetupCacheProtocol(_OriginUri);
  3979.                 if (Logging.On)
  3980.                     Logging.Exit(Logging.Web, this, "HttpWebRequest", null);
  3981.                 #if DEBUG
  3982.             }
  3983.             #endif
  3984.         }
  3985.        
  3986.         /// <devdoc>
  3987.         /// <para>ISerializable method</para>
  3988.         /// </devdoc>
  3989.         [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter, SerializationFormatter = true)]
  3990.         void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
  3991.         {
  3992.             #if DEBUG
  3993.             using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
  3994.                 #endif
  3995.                 GetObjectData(serializationInfo, streamingContext);
  3996.                 #if DEBUG
  3997.             }
  3998.             #endif
  3999.         }
  4000.        
  4001.         //
  4002.         // FxCop: Need this in addition to the above in order to allow derived classes to access the base implementation.
  4003.         //
  4004.         [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
  4005.         protected override void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
  4006.         {
  4007.             #if DEBUG
  4008.             using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
  4009.                 #endif
  4010.                 //
  4011.                 // for now disregard streamingContext.
  4012.                 // just Add all the members we need to deserialize to construct
  4013.                 // the object at deserialization time
  4014.                 //
  4015.                 // the following runtime types already support serialization:
  4016.                 // Boolean, Char, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, DateTime
  4017.                 // for the others we need to provide our own serialization
  4018.                 //
  4019.                 serializationInfo.AddValue("_HttpRequestHeaders", _HttpRequestHeaders, typeof(WebHeaderCollection));
  4020.                 serializationInfo.AddValue("_Proxy", _Proxy, typeof(IWebProxy));
  4021.                 serializationInfo.AddValue("_KeepAlive", KeepAlive);
  4022.                 serializationInfo.AddValue("_Pipelined", Pipelined);
  4023.                 serializationInfo.AddValue("_AllowAutoRedirect", AllowAutoRedirect);
  4024.                 serializationInfo.AddValue("_AllowWriteStreamBuffering", AllowWriteStreamBuffering);
  4025.                 serializationInfo.AddValue("_HttpWriteMode", HttpWriteMode);
  4026.                 serializationInfo.AddValue("_MaximumAllowedRedirections", _MaximumAllowedRedirections);
  4027.                 serializationInfo.AddValue("_AutoRedirects", _AutoRedirects);
  4028.                 serializationInfo.AddValue("_Timeout", _Timeout);
  4029.                 serializationInfo.AddValue("_ReadWriteTimeout", _ReadWriteTimeout);
  4030.                 serializationInfo.AddValue("_MaximumResponseHeadersLength", _MaximumResponseHeadersLength);
  4031.                 serializationInfo.AddValue("_ContentLength", ContentLength);
  4032.                 serializationInfo.AddValue("_MediaType", _MediaType);
  4033.                 serializationInfo.AddValue("_OriginVerb", _OriginVerb);
  4034.                 serializationInfo.AddValue("_ConnectionGroupName", _ConnectionGroupName);
  4035.                 serializationInfo.AddValue("_Version", ProtocolVersion, typeof(Version));
  4036.                 serializationInfo.AddValue("_OriginUri", _OriginUri, typeof(Uri));
  4037.                 base.GetObjectData(serializationInfo, streamingContext);
  4038.                 #if DEBUG
  4039.             }
  4040.             #endif
  4041.         }
  4042.        
  4043.         /// <devdoc>
  4044.         /// <para>Used by ServicePoint code to find the right connection Group</para>
  4045.         /// </devdoc>
  4046.         static internal StringBuilder GenerateConnectionGroup(string connectionGroupName, bool unsafeConnectionGroup, bool isInternalGroup)
  4047.         {
  4048.             StringBuilder connectionLine = new StringBuilder(connectionGroupName);
  4049.            
  4050.             connectionLine.Append(unsafeConnectionGroup ? "U>" : "S>");
  4051.            
  4052.             if (isInternalGroup) {
  4053.                 connectionLine.Append("I>");
  4054.             }
  4055.            
  4056.             return connectionLine;
  4057.         }
  4058.        
  4059.        
  4060.         /// <devdoc>
  4061.         /// <para>Generates a string that
  4062.         /// allows a Connection to remain unique for a given NTLM auth
  4063.         /// user, this is needed to prevent multiple users from
  4064.         /// using the same sockets after they are authenticated.</para>
  4065.         /// </devdoc>
  4066.         internal string GetConnectionGroupLine()
  4067.         {
  4068.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetConnectionGroupLine");
  4069.             StringBuilder connectionLine = GenerateConnectionGroup(_ConnectionGroupName, UnsafeAuthenticatedConnectionSharing, m_InternalConnectionGroup);
  4070.            
  4071.            
  4072.             //
  4073.            
  4074.             if ((_Uri.Scheme == Uri.UriSchemeHttps) || IsTunnelRequest) {
  4075.                 if (UsesProxy) {
  4076.                     connectionLine.Append(ConnectHostAndPort);
  4077.                     connectionLine.Append("$");
  4078.                 }
  4079.             }
  4080.             if (ProxyAuthenticationState.UniqueGroupId != null) {
  4081.                 connectionLine.Append(ProxyAuthenticationState.UniqueGroupId);
  4082.             }
  4083.             else if (ServerAuthenticationState.UniqueGroupId != null) {
  4084.                 connectionLine.Append(ServerAuthenticationState.UniqueGroupId);
  4085.             }
  4086.            
  4087.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetConnectionGroupLine", connectionLine.ToString());
  4088.             return connectionLine.ToString();
  4089.         }
  4090.        
  4091.        
  4092.         /// <devdoc>
  4093.         /// <para>CheckResubmitForAuth - Determines if a HTTP request needs to be
  4094.         /// resubmitted due to HTTP authenication
  4095.         ///
  4096.         /// true - if we should reattempt submitting the request
  4097.         /// false - if the request is complete
  4098.         /// </para>
  4099.         /// </devdoc>
  4100.         private bool CheckResubmitForAuth()
  4101.         {
  4102.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmitForAuth");
  4103.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmitForAuth");
  4104.            
  4105.            
  4106.             bool result = false;
  4107.             bool authenticated = false;
  4108.             bool skip = false;
  4109.             if (UsesProxySemantics && _Proxy != null && _Proxy.Credentials != null) {
  4110.                 try {
  4111.                     result |= ProxyAuthenticationState.AttemptAuthenticate(this, _Proxy.Credentials);
  4112.                 }
  4113.                 catch (Win32Exception) {
  4114.                     if (!m_Extra401Retry) {
  4115.                         throw;
  4116.                     }
  4117.                     skip = true;
  4118.                 }
  4119.                 authenticated = true;
  4120.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmitForAuth() ProxyAuthenticationState.AttemptAuthenticate() returns result:" + result.ToString());
  4121.             }
  4122.             if (Credentials != null && !skip) {
  4123.                 try {
  4124.                     result |= ServerAuthenticationState.AttemptAuthenticate(this, Credentials);
  4125.                 }
  4126.                 catch (Win32Exception) {
  4127.                     if (!m_Extra401Retry) {
  4128.                         throw;
  4129.                     }
  4130.                     result = false;
  4131.                 }
  4132.                 authenticated = true;
  4133.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmitForAuth() ServerAuthenticationState.AttemptAuthenticate() returns result:" + result.ToString());
  4134.             }
  4135.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmitForAuth", result);
  4136.            
  4137.             if (!result && authenticated && m_Extra401Retry) {
  4138.                 ClearAuthenticatedConnectionResources();
  4139.                 m_Extra401Retry = false;
  4140.                 result = true;
  4141.             }
  4142.            
  4143.             return result;
  4144.         }
  4145.        
  4146.         /// <devdoc>
  4147.         /// <para>Determines whether we need to resubmit the request due to the cache settings
  4148.         /// here it is imperitive that this is not recalled when we already are receiving a cached
  4149.         /// response</para>
  4150.         /// </devdoc>
  4151.         private bool CheckResubmitForCache(ref Exception e)
  4152.         {
  4153.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmitForCache");
  4154.            
  4155.             // Here, we can go into retrying the request
  4156.             if (!CheckCacheRetrieveOnResponse()) {
  4157.                
  4158.                 // NB: We don't have a flag that would control a generic retries
  4159.                 // So far we used _AllowAutoRedirect when doing Auth resubmits so the cache intiated retries are put into same bucket
  4160.                 if (AllowAutoRedirect) {
  4161.                     // Resubmit the request
  4162.                     if (Logging.On)
  4163.                         Logging.PrintWarning(Logging.Web, this, "", SR.GetString(SR.net_log_cache_validation_failed_resubmit));
  4164.                     return true;
  4165.                 }
  4166.                
  4167.                 //fail terribly
  4168.                 if (Logging.On)
  4169.                     Logging.PrintError(Logging.Web, this, "", SR.GetString(SR.net_log_cache_refused_server_response));
  4170.                 e = new InvalidOperationException(SR.GetString(SR.net_cache_not_accept_response));
  4171.                 return false;
  4172.             }
  4173.            
  4174.             // This may change _HttpResponse memeber based on the CacheProtocol feedback.
  4175.             CheckCacheUpdateOnResponse();
  4176.             return false;
  4177.         }
  4178.        
  4179.         /// <devdoc>
  4180.         /// <para>Determines if a HTTP request needs to be
  4181.         /// resubmitted to a server point, this is called in Response
  4182.         /// Parsing to handle cases such as server Redirects and Authentications</para>
  4183.         ///
  4184.         /// true - if we should reattempt submitting the request
  4185.         /// false - if the request is complete
  4186.         /// </devdoc>
  4187.         private bool CheckResubmit(ref Exception e)
  4188.         {
  4189.             GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit");
  4190.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit");
  4191.            
  4192.             bool authResubmit = false;
  4193.            
  4194.             // 401
  4195.             // 407
  4196.             if (ResponseStatusCode == HttpStatusCode.Unauthorized || ResponseStatusCode == HttpStatusCode.ProxyAuthenticationRequired) {
  4197.                 try {
  4198.                     //
  4199.                     // Check for Authentication
  4200.                     //
  4201.                     if (!(authResubmit = CheckResubmitForAuth())) {
  4202.                         e = new WebException(SR.GetString(SR.net_servererror, NetRes.GetWebStatusCodeString(ResponseStatusCode, _HttpResponse.StatusDescription)), null, WebExceptionStatus.ProtocolError, _HttpResponse);
  4203.                         GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
  4204.                         return false;
  4205.                     }
  4206.                 }
  4207.                 catch (System.ComponentModel.Win32Exception w32Exception) {
  4208.                     throw new WebException(SR.GetString(SR.net_servererror, NetRes.GetWebStatusCodeString(ResponseStatusCode, _HttpResponse.StatusDescription)), w32Exception, WebExceptionStatus.ProtocolError, _HttpResponse);
  4209.                    
  4210.                 }
  4211.             }
  4212.             else {
  4213.                 if (ServerAuthenticationState != null && ServerAuthenticationState.Authorization != null) {
  4214.                     HttpWebResponse response = _HttpResponse;
  4215.                     if (response != null) {
  4216.                         response.InternalSetIsMutuallyAuthenticated = ServerAuthenticationState.Authorization.MutuallyAuthenticated;
  4217.                     }
  4218.                 }
  4219.                
  4220.                 // This is a workaround for resubmitting a failed chunked POST throw the proxy that does not support chunked POST
  4221.                 if (ResponseStatusCode == HttpStatusCode.BadRequest && this.SendChunked && this.ServicePoint.InternalProxyServicePoint) {
  4222.                     ClearAuthenticatedConnectionResources();
  4223.                     return true;
  4224.                 }
  4225.                
  4226.                
  4227.                 //
  4228.                 // Check for Redirection
  4229.                 //
  4230.                 // Table View:
  4231.                 // Method 301 302 303 307
  4232.                 // * * * GET *
  4233.                 // POST GET GET GET POST
  4234.                 //
  4235.                 // Put another way:
  4236.                 // 301 & 302 - All methods are redirected to the same method but POST. POST is redirected to a GET.
  4237.                 // 303 - All methods are redirected to GET
  4238.                 // 307 - All methods are redirected to the same method.
  4239.                 //
  4240.                 // 300
  4241.                 // 301
  4242.                 // 302
  4243.                 // 303
  4244.                 // 307
  4245.                 else if (AllowAutoRedirect && (ResponseStatusCode == HttpStatusCode.Ambiguous || ResponseStatusCode == HttpStatusCode.Moved || ResponseStatusCode == HttpStatusCode.Redirect || ResponseStatusCode == HttpStatusCode.RedirectMethod || ResponseStatusCode == HttpStatusCode.RedirectKeepVerb)) {
  4246.                    
  4247.                     _AutoRedirects++;
  4248.                    
  4249.                     if (_AutoRedirects > _MaximumAllowedRedirections) {
  4250.                        
  4251.                         e = new WebException(SR.GetString(SR.net_tooManyRedirections), null, WebExceptionStatus.ProtocolError, _HttpResponse);
  4252.                         GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
  4253.                         return false;
  4254.                     }
  4255.                    
  4256.                     string location = _HttpResponse.Headers.Location;
  4257.                     if (location == null) {
  4258.                         e = new WebException(SR.GetString(SR.net_servererror, NetRes.GetWebStatusCodeString(ResponseStatusCode, _HttpResponse.StatusDescription)), null, WebExceptionStatus.ProtocolError, _HttpResponse);
  4259.                         GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
  4260.                         return false;
  4261.                     }
  4262.                     GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit() Location:" + location);
  4263.                     Uri newUri;
  4264.                     try {
  4265.                         newUri = new Uri(_Uri, location);
  4266.                     }
  4267.                     catch (UriFormatException exception) {
  4268.                         e = new WebException(SR.GetString(SR.net_resubmitprotofailed), exception, WebExceptionStatus.ProtocolError, _HttpResponse);
  4269.                         GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
  4270.                         return false;
  4271.                     }
  4272.                     if (newUri.Scheme != Uri.UriSchemeHttp && newUri.Scheme != Uri.UriSchemeHttps) {
  4273.                         e = new WebException(SR.GetString(SR.net_resubmitprotofailed), null, WebExceptionStatus.ProtocolError, _HttpResponse);
  4274.                         GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
  4275.                         return false;
  4276.                     }
  4277.                     try {
  4278.                         // Check for permissions against redirect Uri
  4279.                         ExecutionContext x = null;
  4280.                         CodeAccessPermission permission = (new WebPermission(NetworkAccess.Connect, newUri));
  4281.                         if (x == null) {
  4282.                             permission.Demand();
  4283.                         }
  4284.                         else {
  4285.                             ExecutionContext.Run(x, NclUtilities.ContextRelativeDemandCallback, permission);
  4286.                         }
  4287.                     }
  4288.                     catch (SecurityException exception) {
  4289.                         e = new SecurityException(SR.GetString(SR.net_redirect_perm), new WebException(SR.GetString(SR.net_resubmitcanceled), exception, WebExceptionStatus.ProtocolError, _HttpResponse));
  4290.                        
  4291.                         GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
  4292.                         return false;
  4293.                     }
  4294.                    
  4295.                     _Uri = newUri;
  4296.                    
  4297.                     bool disableUpload = false;
  4298.                     if (ResponseStatusCode > MaxOkStatus) {
  4299.                         if (Logging.On)
  4300.                             Logging.PrintWarning(Logging.Web, this, "", SR.GetString(SR.net_log_server_response_error_code, ((int)ResponseStatusCode).ToString(NumberFormatInfo.InvariantInfo)));
  4301.                     }
  4302.                    
  4303.                     switch (ResponseStatusCode) {
  4304.                         case HttpStatusCode.Moved:
  4305.                         case HttpStatusCode.Redirect:
  4306.                             if (CurrentMethod.Equals(KnownHttpVerb.Post)) {
  4307.                                 disableUpload = true;
  4308.                             }
  4309.                             break;
  4310.                         case HttpStatusCode.RedirectKeepVerb:
  4311.                             break;
  4312.                         default:
  4313.                             disableUpload = true;
  4314.                             break;
  4315.                     }
  4316.                    
  4317.                     // set new Method
  4318.                     if (disableUpload) {
  4319.                         GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit() disabling upload HttpWriteMode:" + HttpWriteMode + " SubmitWriteStream#" + ValidationHelper.HashString(_SubmitWriteStream));
  4320.                         GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit() changing Verb from " + CurrentMethod + " to " + KnownHttpVerb.Get);
  4321.                         CurrentMethod = KnownHttpVerb.Get;
  4322.                         ExpectContinue = false;
  4323.                         HttpWriteMode = HttpWriteMode.None;
  4324.                     }
  4325.                    
  4326.                     //
  4327.                     // make sure we're not sending over credential information to an evil redirection
  4328.                     // URI. this will set our credentials to null unless the user is using DefaultCredentials
  4329.                     // or a CredentialCache, in which case he is responsible for binding the credentials to
  4330.                     // the proper Uri and AuthenticationScheme.
  4331.                     //
  4332.                    
  4333.                     Credentials = null;
  4334.                    
  4335.                     //
  4336.                     // do the necessary cleanup on the Headers involved in the
  4337.                     // Authentication handshake.
  4338.                     //
  4339.                     ProxyAuthenticationState.ClearAuthReq(this);
  4340.                     ServerAuthenticationState.ClearAuthReq(this);
  4341.                    
  4342.                     //strip referer if coming from an https site
  4343.                     if (_OriginUri.Scheme == Uri.UriSchemeHttps) {
  4344.                         _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Referer);
  4345.                     }
  4346.                    
  4347.                     // resubmit
  4348.                     GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit() CurrentMethod=" + CurrentMethod);
  4349.                 }
  4350.                 // > 399 = fatal
  4351.                 else if (ResponseStatusCode > MaxRedirectionStatus) {
  4352.                     e = new WebException(SR.GetString(SR.net_servererror, NetRes.GetWebStatusCodeString(ResponseStatusCode, _HttpResponse.StatusDescription)), null, WebExceptionStatus.ProtocolError, _HttpResponse);
  4353.                     GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
  4354.                     return false;
  4355.                 }
  4356.                 //some of 3XX and AllowAutoRedirect==true will result into an exceptional respone
  4357.                 else if (AllowAutoRedirect && ResponseStatusCode > MaxOkStatus) {
  4358.                     e = new WebException(SR.GetString(SR.net_servererror, NetRes.GetWebStatusCodeString(ResponseStatusCode, _HttpResponse.StatusDescription)), null, WebExceptionStatus.ProtocolError, _HttpResponse);
  4359.                     GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
  4360.                     return false;
  4361.                 }
  4362.                 // SUCCESS Status is <= 299 or (<=399 && AllowAutoRedirect==false) will result into a normal (non exceptional) response
  4363.                 else {
  4364.                     GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
  4365.                     return false;
  4366.                 }
  4367.             }
  4368.            
  4369.             GlobalLog.Assert(HttpWriteMode != HttpWriteMode.Unknown, "HttpWebRequest#{0}::CheckResubmit()|HttpWriteMode:{1}", ValidationHelper.HashString(this), HttpWriteMode);
  4370.             if (HttpWriteMode != HttpWriteMode.None && !AllowWriteStreamBuffering && (HttpWriteMode != HttpWriteMode.ContentLength || ContentLength != 0)) {
  4371.                 e = new WebException(SR.GetString(SR.net_need_writebuffering), null, WebExceptionStatus.ProtocolError, _HttpResponse);
  4372.                 GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
  4373.                 return false;
  4374.             }
  4375.            
  4376.             if (!authResubmit) {
  4377.                 ClearAuthenticatedConnectionResources();
  4378.             }
  4379.            
  4380.             if (Logging.On)
  4381.                 Logging.PrintWarning(Logging.Web, this, "", SR.GetString(SR.net_log_resubmitting_request));
  4382.             GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "true");
  4383.             return true;
  4384.         }
  4385.        
  4386. /*++
  4387.         Routine Description:
  4388.             ClearRequestForResubmit - prepares object for resubmission and recall
  4389.                 of submit request, for redirects, authentication, and other uses
  4390.                 This is needed to prevent duplicate headers being added, and other
  4391.                 such things.
  4392.         Arguments:
  4393.             None.
  4394.         Return Value:
  4395.             None.
  4396.         --*/       
  4397.         private void ClearRequestForResubmit()
  4398.         {
  4399.             GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::ClearRequestForResubmit");
  4400.            
  4401.             _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Host);
  4402.             _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Connection);
  4403.             _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.ProxyConnection);
  4404.             _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.ContentLength);
  4405.             _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.TransferEncoding);
  4406.             _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Expect);
  4407.            
  4408.             if (_HttpResponse != null && _HttpResponse.ResponseStream != null) {
  4409.                 //
  4410.                 // We just drain the response data, and throw them away since we're redirecting or authenticating.
  4411.                 //
  4412.                 GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ClearRequestForResubmit() draining ResponseStream");
  4413.                 if (!_HttpResponse.KeepAlive) {
  4414.                     ConnectStream liveStream = _HttpResponse.ResponseStream as ConnectStream;
  4415.                     if (liveStream != null) {
  4416.                         // The response stream may be closed at any time by the server.
  4417.                         // At this point we don't want to drain such a ConnectStream.
  4418.                         liveStream.ErrorResponseNotify(false);
  4419.                     }
  4420.                 }
  4421.                 ICloseEx icloseEx = _HttpResponse.ResponseStream as ICloseEx;
  4422.                 if (icloseEx != null) {
  4423.                     icloseEx.CloseEx(CloseExState.Silent);
  4424.                 }
  4425.                 else {
  4426.                     _HttpResponse.ResponseStream.Close();
  4427.                 }
  4428.             }
  4429.            
  4430.             _AbortDelegate = null;
  4431.            
  4432.             if (_SubmitWriteStream != null) {
  4433.                 //
  4434.                 // We're uploading and need to resubmit for Authentication or Redirect.
  4435.                 // if the response wants to keep alive the connection we shouldn't be closing
  4436.                 // it (this would also brake connection-oriented authentication schemes such as NTLM).
  4437.                 // so we need to flush all the data to the wire.
  4438.                 // if the server is closing the connection, instead, we can just close our side as well.
  4439.                 if ((_HttpResponse != null && _HttpResponse.KeepAlive) || _SubmitWriteStream.IgnoreSocketErrors) {
  4440.                     //
  4441.                     // the server wants to keep the connection alive.
  4442.                     // if we're uploading data, we need to make sure that we upload all
  4443.                     // of it before we start resubmitting.
  4444.                     // give the stream to the user if he didn't get it yet.
  4445.                     // if the user has set ContentLength to a big number, then we might be able
  4446.                     // to just decide to close the connection, but we need to be careful to NTLM.
  4447.                     //
  4448.                     GlobalLog.Assert(HttpWriteMode != HttpWriteMode.Unknown, "HttpWebRequest#{0}::ClearRequestForResubmit()|HttpWriteMode:{1}", ValidationHelper.HashString(this), HttpWriteMode);
  4449.                     if (HasEntityBody) {
  4450.                         //
  4451.                         // we're uploading
  4452.                         //
  4453.                         GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ClearRequestForResubmit() _WriteAResult:" + ValidationHelper.ToString(_WriteAResult));
  4454.                        
  4455.                         //
  4456.                         // the user didn't get the stream yet, give it to him
  4457.                         //
  4458.                         GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ClearRequestForResubmit() calling SetRequestContinue()");
  4459.                         SetRequestContinue();
  4460.                        
  4461.                         // We should only close the stream if we're not giving it back to the app.
  4462.                         if (!Async && UserRetrievedWriteStream)
  4463.                             _SubmitWriteStream.CallDone();
  4464.                     }
  4465.                 }
  4466.                
  4467.                 if ((Async || UserRetrievedWriteStream) && _OldSubmitWriteStream != null && _OldSubmitWriteStream != _SubmitWriteStream) {
  4468.                     GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ClearRequestForResubmit() closing RequestStream");
  4469.                     _SubmitWriteStream.CloseInternal(true);
  4470.                 }
  4471.             }
  4472.            
  4473.             m_ContinueGate.Reset();
  4474.             _RerequestCount += 1;
  4475.            
  4476.             m_BodyStarted = false;
  4477.             HeadersCompleted = false;
  4478.             _WriteBuffer = null;
  4479.             m_Extra401Retry = false;
  4480.            
  4481.             _HttpResponse = null;
  4482.            
  4483.             if (!Aborted && Async)
  4484.                 _CoreResponse = null;
  4485.         }
  4486.        
  4487.         //
  4488.         // Oprionally:
  4489.         // 1) copies off the response stream
  4490.         // 2) closes SubmitStream
  4491.         // 3) updates ServicePoint 100-Continue expectation for future requests
  4492.         //
  4493.         // Should never throw
  4494.         //
  4495.         private void FinishRequest(HttpWebResponse response, Exception errorException)
  4496.         {
  4497.            
  4498.             GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::FinishRequest()");
  4499.            
  4500.             // otherwise it's too late
  4501.             if (!_ReadAResult.InternalPeekCompleted && m_Aborted != AbortState.Public) {
  4502.                 if (response != null && errorException != null) {
  4503.                     // if this is a protocol exception copy off stream, don't just close it
  4504.                     GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckFinalStatus() - status" + (int)ResponseStatusCode);
  4505.                     response.ResponseStream = MakeMemoryStream(response.ResponseStream);
  4506.                     // Never throws
  4507.                 }
  4508.             }
  4509.            
  4510.             if (errorException != null && _SubmitWriteStream != null && !_SubmitWriteStream.IsClosed) {
  4511.                 _SubmitWriteStream.ErrorResponseNotify(false);
  4512.             }
  4513.            
  4514.             //
  4515.             // turn off expectation of 100 continue (we'll keep sending an
  4516.             // "Expect: 100-continue" header to a 1.1 server though)
  4517.             //
  4518.             if (errorException == null && _HttpResponse != null && (_HttpWriteMode == HttpWriteMode.Chunked || _ContentLength > 0) && ExpectContinue && !Saw100Continue && _ServicePoint.Understands100Continue && !IsTunnelRequest && ResponseStatusCode <= MaxOkStatus) {
  4519.                 _ServicePoint.Understands100Continue = false;
  4520.             }
  4521.         }
  4522.        
  4523.         //
  4524.         // Never throws
  4525.         //
  4526.         private Stream MakeMemoryStream(Stream stream)
  4527.         {
  4528.             // GlobalLog.ThreadContract(ThreadKinds.Sync, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::MakeMemoryStream");
  4529.            
  4530.             if (stream == null || stream is SyncMemoryStream)
  4531.                 return stream;
  4532.            
  4533.             SyncMemoryStream memoryStream = new SyncMemoryStream(0);
  4534.             // buffered Stream to save off data
  4535.             try {
  4536.                 //
  4537.                 // Now drain the Stream
  4538.                 //
  4539.                 if (stream.CanRead) {
  4540.                     byte[] buffer = new byte[1024];
  4541.                     int bytesTransferred = 0;
  4542.                    
  4543.                     int maxBytesToBuffer = (HttpWebRequest.DefaultMaximumErrorResponseLength == -1) ? buffer.Length : HttpWebRequest.DefaultMaximumErrorResponseLength * 1024;
  4544.                     while ((bytesTransferred = stream.Read(buffer, 0, Math.Min(buffer.Length, maxBytesToBuffer))) > 0) {
  4545.                         memoryStream.Write(buffer, 0, bytesTransferred);
  4546.                         if (HttpWebRequest.DefaultMaximumErrorResponseLength != -1)
  4547.                             maxBytesToBuffer -= bytesTransferred;
  4548.                     }
  4549.                 }
  4550.                 memoryStream.Position = 0;
  4551.             }
  4552.             catch {
  4553.             }
  4554.             finally {
  4555.                 try {
  4556.                     ICloseEx icloseEx = stream as ICloseEx;
  4557.                     if (icloseEx != null) {
  4558.                         icloseEx.CloseEx(CloseExState.Silent);
  4559.                     }
  4560.                     else {
  4561.                         stream.Close();
  4562.                     }
  4563.                 }
  4564.                 catch {
  4565.                 }
  4566.             }
  4567.             return memoryStream;
  4568.         }
  4569.        
  4570.         /// <devdoc>
  4571.         /// <para>
  4572.         /// Adds a range header to the request for a specified range.
  4573.         /// </para>
  4574.         /// </devdoc>
  4575.         public void AddRange(int from, int to)
  4576.         {
  4577.             AddRange("bytes", from, to);
  4578.         }
  4579.        
  4580.        
  4581.         /// <devdoc>
  4582.         /// <para>
  4583.         /// Adds a range header to a request for a specific
  4584.         /// range from the beginning or end
  4585.         /// of the requested data.
  4586.         /// To add the range from the end pass negative value
  4587.         /// To add the range from the some offset to the end pass positive value
  4588.         /// </para>
  4589.         /// </devdoc>
  4590.         public void AddRange(int range)
  4591.         {
  4592.             AddRange("bytes", range);
  4593.         }
  4594.        
  4595.         public void AddRange(string rangeSpecifier, int from, int to)
  4596.         {
  4597.            
  4598.             //
  4599.             // Do some range checking before assembling the header
  4600.             //
  4601.            
  4602.             if (rangeSpecifier == null) {
  4603.                 throw new ArgumentNullException("rangeSpecifier");
  4604.             }
  4605.             if ((from < 0) || (to < 0)) {
  4606.                 throw new ArgumentOutOfRangeException(SR.GetString(SR.net_rangetoosmall));
  4607.             }
  4608.             if (from > to) {
  4609.                 throw new ArgumentOutOfRangeException(SR.GetString(SR.net_fromto));
  4610.             }
  4611.             if (!WebHeaderCollection.IsValidToken(rangeSpecifier)) {
  4612.                 throw new ArgumentException(SR.GetString(SR.net_nottoken), "rangeSpecifier");
  4613.             }
  4614.             if (!AddRange(rangeSpecifier, from.ToString(NumberFormatInfo.InvariantInfo), to.ToString(NumberFormatInfo.InvariantInfo))) {
  4615.                 throw new InvalidOperationException(SR.GetString(SR.net_rangetype));
  4616.             }
  4617.         }
  4618.        
  4619.         public void AddRange(string rangeSpecifier, int range)
  4620.         {
  4621.             if (rangeSpecifier == null) {
  4622.                 throw new ArgumentNullException("rangeSpecifier");
  4623.             }
  4624.             if (!WebHeaderCollection.IsValidToken(rangeSpecifier)) {
  4625.                 throw new ArgumentException(SR.GetString(SR.net_nottoken), "rangeSpecifier");
  4626.             }
  4627.             if (!AddRange(rangeSpecifier, range.ToString(NumberFormatInfo.InvariantInfo), (range >= 0) ? "" : null)) {
  4628.                 throw new InvalidOperationException(SR.GetString(SR.net_rangetype));
  4629.             }
  4630.         }
  4631.        
  4632.         //
  4633.         // bool AddRange(rangeSpecifier, from, to)
  4634.         //
  4635.         // Add or extend a range header. Various range types can be specified
  4636.         // via rangeSpecifier, but only one type of Range request will be made
  4637.         // e.g. a byte-range request, or a row-range request. Range types
  4638.         // cannot be mixed
  4639.         //
  4640.         private bool AddRange(string rangeSpecifier, string from, string to)
  4641.         {
  4642.            
  4643.             string curRange = _HttpRequestHeaders[HttpKnownHeaderNames.Range];
  4644.            
  4645.             if ((curRange == null) || (curRange.Length == 0)) {
  4646.                 curRange = rangeSpecifier + "=";
  4647.             }
  4648.             else {
  4649.                 if (String.Compare(curRange.Substring(0, curRange.IndexOf('=')), rangeSpecifier, StringComparison.OrdinalIgnoreCase) != 0) {
  4650.                     return false;
  4651.                 }
  4652.                 curRange = string.Empty;
  4653.             }
  4654.             curRange += from.ToString();
  4655.             if (to != null) {
  4656.                 curRange += "-" + to;
  4657.             }
  4658.             _HttpRequestHeaders.SetAddVerified(HttpKnownHeaderNames.Range, curRange);
  4659.             return true;
  4660.         }
  4661.        
  4662.         private static string UniqueGroupId {
  4663.             get { return (Interlocked.Increment(ref s_UniqueGroupId)).ToString(NumberFormatInfo.InvariantInfo); }
  4664.         }
  4665.        
  4666.        
  4667.     }
  4668. }

Developer Fusion