{"action":"created","comment":{"url":"https://api.github.com/repos/dotnet/corefx/pulls/comments/33274336","id":33274336,"diff_hunk":"@@ -0,0 +1,2164 @@\n+// Copyright (c) Microsoft. All rights reserved.\n+// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n+\n+using System;\n+using System.Collections.Generic;\n+using System.Diagnostics;\n+using System.Globalization;\n+using System.IO;\n+using System.IO.Compression;\n+using System.Net;\n+using System.Net.Http;\n+using System.Net.Security;\n+using System.Runtime.InteropServices;\n+using System.Security.Authentication;\n+using System.Security.Cryptography.X509Certificates;\n+using System.Security.Principal;\n+using System.Text;\n+using System.Threading;\n+using System.Threading.Tasks;\n+\n+using SafeInternetHandle = Interop.WinHttp.SafeInternetHandle;\n+\n+namespace System.Net.Http\n+{\n+#if HTTP_DLL\n+    internal enum WindowsProxyUsePolicy\n+#else\n+    public enum WindowsProxyUsePolicy\n+#endif\n+    {\n+        DoNotUseProxy = 0, // Don't use a proxy at all.\n+        UseWinHttpProxy = 1, // Use configuration as specified by \"netsh winhttp\" machine config command. Automatic detect not supported.\n+        UseWinInetProxy = 2, // WPAD protocol and PAC files supported.\n+        UseCustomProxy = 3 // Use the custom proxy specified in the Proxy property.\n+    }\n+\n+#if HTTP_DLL\n+    internal enum AutomaticRedirectionPolicy\n+#else\n+    public enum AutomaticRedirectionPolicy\n+#endif\n+    {\n+        Never = 0,\n+        DisallowHttpsToHttp = 1,\n+        Always = 2\n+    }\n+\n+#if HTTP_DLL\n+    internal enum CookieUsePolicy\n+#else\n+    public enum CookieUsePolicy\n+#endif\n+    {\n+        IgnoreCookies = 0,\n+        UseInternalCookieStoreOnly = 1,\n+        UseSpecifiedCookieContainer = 2\n+    }\n+\n+#if HTTP_DLL\n+    internal class WinHttpHandler : HttpMessageHandler\n+#else\n+    public class WinHttpHandler : HttpMessageHandler\n+#endif\n+    {\n+        private static Interop.WinHttp.WINHTTP_STATUS_CALLBACK s_staticCallback = \n+            new Interop.WinHttp.WINHTTP_STATUS_CALLBACK(WinHttpStatusCallback);\n+\n+        // TODO:  This looks messy but it is fast. Research a cleaner way\n+        // to do this which keeps high performance lookup.\n+        //\n+        // Fast lookup table to convert WINHTTP_AUTH constants to strings.\n+        // WINHTTP_AUTH_SCHEME_BASIC = 0x00000001;\n+        // WINHTTP_AUTH_SCHEME_DIGEST = 0x00000008;\n+        // WINHTTP_AUTH_SCHEME_NEGOTIATE = 0x00000010;\n+        private static readonly string[] s_authSchemeStringMapping =\n+        {\n+            null,\n+            \"Basic\",\n+            null,\n+            null,\n+            null,\n+            null,\n+            null,\n+            null,\n+            \"Digest\",\n+            null,\n+            null,\n+            null,\n+            null,\n+            null,\n+            null,\n+            null,\n+            \"Negotiate\"\n+        };\n+\n+        private static readonly uint[] s_authSchemePriorityOrder =\n+        {\n+            Interop.WinHttp.WINHTTP_AUTH_SCHEME_NEGOTIATE,\n+            Interop.WinHttp.WINHTTP_AUTH_SCHEME_DIGEST,\n+            Interop.WinHttp.WINHTTP_AUTH_SCHEME_BASIC\n+        };\n+\n+        #region Constants\n+        private const string ClientAuthenticationOID = \"1.3.6.1.5.5.7.3.2\";\n+        private const string UriSchemeHttps = \"https\";\n+        private const string HeaderNameContentLength = \"Content-Length\";\n+        private const string HeaderNameContentEncoding = \"Content-Encoding\";\n+        private const string HeaderNameCookie = \"Cookie\";\n+        private const string HeaderNameSetCookie = \"Set-Cookie\";\n+        private const string EncodingNameDeflate = \"deflate\";\n+        private const string EncodingNameGzip = \"gzip\";\n+        private const string EmptyCookieHeader = HeaderNameCookie + \":\";\n+        private static readonly string[] s_httpHeadersSeparator = { \"\\r\\n\" };\n+        private static readonly TimeSpan s_maxTimeout = TimeSpan.FromMilliseconds(int.MaxValue);\n+        private static readonly TimeSpan s_infiniteTimeout = Timeout.InfiniteTimeSpan;\n+        #endregion\n+\n+        #region Fields\n+        private object _lockObject = new object();\n+        private bool _doManualDecompressionCheck = false;\n+        private WinInetProxyHelper _proxyHelper = null;\n+        private AutomaticRedirectionPolicy _automaticRedirectionPolicy = AutomaticRedirectionPolicy.DisallowHttpsToHttp;\n+        private int _maxAutomaticRedirections = 50;\n+        private DecompressionMethods _automaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;\n+        private CookieUsePolicy _cookieUsePolicy = CookieUsePolicy.UseInternalCookieStoreOnly;\n+        private CookieContainer _cookieContainer = null;\n+\n+        // TODO: This current design uses a handler-wide lock to Add/Retrieve\n+        // from the cache.  Need to improve this for next iteration in order\n+        // to boost performance and scalability.\n+        private CredentialCache _credentialCache = new CredentialCache();\n+        private Object _credentialCacheLock = new object();\n+\n+        private SslProtocols _sslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;\n+        private Func<\n+            HttpRequestMessage,\n+            X509Certificate2,\n+            X509Chain,\n+            SslPolicyErrors,\n+            bool> _serverCertificateValidationCallback = null;\n+        private bool _checkCertificateRevocationList = false;\n+        private ClientCertificateOption _clientCertificateOption = ClientCertificateOption.Manual;\n+        private X509Certificate2Collection _clientCertificates = null; // Only create collection when required.\n+        private ICredentials _serverCredentials = null;\n+        private bool _preAuthenticate = false;\n+        private WindowsProxyUsePolicy _windowsProxyUsePolicy = WindowsProxyUsePolicy.UseWinHttpProxy;\n+        private ICredentials _defaultProxyCredentials = CredentialCache.DefaultCredentials;\n+        private IWebProxy _proxy = null;\n+        private int _maxConnectionsPerServer = int.MaxValue;\n+        private TimeSpan _connectTimeout = TimeSpan.FromSeconds(60);\n+        private TimeSpan _sendTimeout = TimeSpan.FromSeconds(30);\n+        private TimeSpan _receiveHeadersTimeout = TimeSpan.FromSeconds(30);\n+        private TimeSpan _receiveDataTimeout = TimeSpan.FromSeconds(30);\n+        private int _maxResponseHeadersLength = 64 * 1024;\n+        private int _maxResponseDrainSize = 64 * 1024;\n+        private volatile bool _operationStarted;\n+        private volatile bool _disposed;\n+        private SafeInternetHandle _sessionHandle;\n+        #endregion\n+\n+        public WinHttpHandler()\n+        {\n+        }\n+\n+        #region Properties\n+        public AutomaticRedirectionPolicy AutomaticRedirectionPolicy\n+        {\n+            get\n+            {\n+                return _automaticRedirectionPolicy;\n+            }\n+\n+            set\n+            {\n+                if (value != AutomaticRedirectionPolicy.Never\n+                    && value != AutomaticRedirectionPolicy.DisallowHttpsToHttp\n+                    && value != AutomaticRedirectionPolicy.Always)\n+                {\n+                    throw new ArgumentOutOfRangeException(\"value\");\n+                }\n+\n+                CheckDisposedOrStarted();\n+                _automaticRedirectionPolicy = value;\n+            }\n+        }\n+\n+        public int MaxAutomaticRedirections\n+        {\n+            get\n+            {\n+                return _maxAutomaticRedirections;\n+            }\n+\n+            set\n+            {\n+                if (value <= 0)\n+                {\n+                    throw new ArgumentOutOfRangeException(\n+                        \"value\",\n+                        value,\n+                        string.Format(SR.net_http_value_must_be_greater_than, 0));\n+                }\n+\n+                CheckDisposedOrStarted();\n+                _maxAutomaticRedirections = value;\n+            }\n+        }\n+\n+        public DecompressionMethods AutomaticDecompression\n+        {\n+            get\n+            {\n+                return _automaticDecompression;\n+            }\n+\n+            set\n+            {\n+                CheckDisposedOrStarted();\n+                _automaticDecompression = value;\n+            }\n+        }\n+\n+        public CookieUsePolicy CookieUsePolicy\n+        {\n+            get\n+            {\n+                return _cookieUsePolicy;\n+            }\n+\n+            set\n+            {\n+                if (value != CookieUsePolicy.IgnoreCookies\n+                    && value != CookieUsePolicy.UseInternalCookieStoreOnly\n+                    && value != CookieUsePolicy.UseSpecifiedCookieContainer)\n+                {\n+                    throw new ArgumentOutOfRangeException(\"value\");\n+                }\n+\n+                CheckDisposedOrStarted();\n+                _cookieUsePolicy = value;\n+            }\n+        }\n+\n+        public CookieContainer CookieContainer\n+        {\n+            get\n+            {\n+                return _cookieContainer;\n+            }\n+\n+            set\n+            {\n+                CheckDisposedOrStarted();\n+                _cookieContainer = value;\n+            }\n+        }\n+\n+        public SslProtocols SslProtocols\n+        {\n+            get\n+            {\n+                return _sslProtocols;\n+            }\n+\n+            set\n+            {\n+                CheckDisposedOrStarted();\n+\n+                SslProtocols allowedSslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;\n+                if (value == SslProtocols.None || (value & ~allowedSslProtocols) != 0)\n+                {\n+                    throw new ArgumentOutOfRangeException(\"value\");\n+                }\n+\n+                _sslProtocols = value;\n+            }\n+        }\n+\n+        public Func<\n+            HttpRequestMessage,\n+            X509Certificate2,\n+            X509Chain,\n+            SslPolicyErrors,\n+            bool> ServerCertificateValidationCallback\n+        {\n+            get\n+            {\n+                return _serverCertificateValidationCallback;\n+            }\n+\n+            set\n+            {\n+                CheckDisposedOrStarted();\n+\n+                _serverCertificateValidationCallback = value;\n+            }\n+        }\n+\n+        public bool CheckCertificateRevocationList\n+        {\n+            get\n+            {\n+                return _checkCertificateRevocationList;\n+            }\n+\n+            set\n+            {\n+                _checkCertificateRevocationList = value;\n+            }\n+        }\n+\n+        public ClientCertificateOption ClientCertificateOption\n+        {\n+            get\n+            {\n+                return _clientCertificateOption;\n+            }\n+\n+            set\n+            {\n+                if (value != ClientCertificateOption.Manual\n+                    && value != ClientCertificateOption.Automatic)\n+                {\n+                    throw new ArgumentOutOfRangeException(\"value\");\n+                }\n+\n+                CheckDisposedOrStarted();\n+                _clientCertificateOption = value;\n+            }\n+        }\n+\n+        public X509Certificate2Collection ClientCertificates\n+        {\n+            get\n+            {\n+                if (_clientCertificates == null)\n+                {\n+                    _clientCertificates = new X509Certificate2Collection();\n+                }\n+\n+                return _clientCertificates;\n+            }\n+        }\n+\n+        public bool PreAuthenticate\n+        {\n+            get\n+            {\n+                return _preAuthenticate;\n+            }\n+\n+            set\n+            {\n+                _preAuthenticate = value;\n+            }\n+        }\n+\n+        public ICredentials ServerCredentials\n+        {\n+            get\n+            {\n+                return _serverCredentials;\n+            }\n+\n+            set\n+            {\n+                _serverCredentials = value;\n+            }\n+        }\n+\n+        public WindowsProxyUsePolicy WindowsProxyUsePolicy\n+        {\n+            get\n+            {\n+                return _windowsProxyUsePolicy;\n+            }\n+\n+            set\n+            {\n+                if (value != WindowsProxyUsePolicy.DoNotUseProxy &&\n+                    value != WindowsProxyUsePolicy.UseWinHttpProxy &&\n+                    value != WindowsProxyUsePolicy.UseWinInetProxy &&\n+                    value != WindowsProxyUsePolicy.UseCustomProxy)\n+                {\n+                    throw new ArgumentOutOfRangeException(\"value\");\n+                }\n+\n+                CheckDisposedOrStarted();\n+                _windowsProxyUsePolicy = value;\n+            }\n+        }\n+\n+        public ICredentials DefaultProxyCredentials\n+        {\n+            get\n+            {\n+                return _defaultProxyCredentials;\n+            }\n+\n+            set\n+            {\n+                CheckDisposedOrStarted();\n+                _defaultProxyCredentials = value;\n+            }\n+        }\n+\n+        public IWebProxy Proxy\n+        {\n+            get\n+            {\n+                return _proxy;\n+            }\n+\n+            set\n+            {\n+                CheckDisposedOrStarted();\n+                _proxy = value;\n+            }\n+        }\n+\n+        public int MaxConnectionsPerServer\n+        {\n+            get\n+            {\n+                return _maxConnectionsPerServer;\n+            }\n+\n+            set\n+            {\n+                if (value < 1)\n+                {\n+                    // In WinHTTP, setting this to 0 results in it being reset to 2.\n+                    // So, we'll only allow settings above 0.\n+                    throw new ArgumentOutOfRangeException(\n+                        \"value\",\n+                        value,\n+                        string.Format(SR.net_http_value_must_be_greater_than, 0));\n+                }\n+\n+                CheckDisposedOrStarted();\n+                _maxConnectionsPerServer = value;\n+            }\n+        }\n+\n+        public TimeSpan ConnectTimeout\n+        {\n+            get\n+            {\n+                return _connectTimeout;\n+            }\n+\n+            set\n+            {\n+                if (value != s_infiniteTimeout && (value <= TimeSpan.Zero || value > s_maxTimeout))\n+                {\n+                    throw new ArgumentOutOfRangeException(\"value\");\n+                }\n+\n+                CheckDisposedOrStarted();\n+                _connectTimeout = value;\n+            }\n+        }\n+\n+        public TimeSpan SendTimeout\n+        {\n+            get\n+            {\n+                return _sendTimeout;\n+            }\n+\n+            set\n+            {\n+                if (value != s_infiniteTimeout && (value <= TimeSpan.Zero || value > s_maxTimeout))\n+                {\n+                    throw new ArgumentOutOfRangeException(\"value\");\n+                }\n+\n+                CheckDisposedOrStarted();\n+                _sendTimeout = value;\n+            }\n+        }\n+\n+        public TimeSpan ReceiveHeadersTimeout\n+        {\n+            get\n+            {\n+                return _receiveHeadersTimeout;\n+            }\n+\n+            set\n+            {\n+                if (value != s_infiniteTimeout && (value <= TimeSpan.Zero || value > s_maxTimeout))\n+                {\n+                    throw new ArgumentOutOfRangeException(\"value\");\n+                }\n+\n+                CheckDisposedOrStarted();\n+                _receiveHeadersTimeout = value;\n+            }\n+        }\n+\n+        public TimeSpan ReceiveDataTimeout\n+        {\n+            get\n+            {\n+                return _receiveDataTimeout;\n+            }\n+\n+            set\n+            {\n+                if (value != s_infiniteTimeout && (value <= TimeSpan.Zero || value > s_maxTimeout))\n+                {\n+                    throw new ArgumentOutOfRangeException(\"value\");\n+                }\n+\n+                CheckDisposedOrStarted();\n+                _receiveDataTimeout = value;\n+            }\n+        }\n+\n+        public int MaxResponseHeadersLength\n+        {\n+            get\n+            {\n+                return _maxResponseHeadersLength;\n+            }\n+\n+            set\n+            {\n+                if (value <= 0)\n+                {\n+                    throw new ArgumentOutOfRangeException(\n+                        \"value\",\n+                        value,\n+                        string.Format(SR.net_http_value_must_be_greater_than, 0));\n+                }\n+\n+                CheckDisposedOrStarted();\n+                _maxResponseHeadersLength = value;\n+            }\n+        }\n+\n+        public int MaxResponseDrainSize\n+        {\n+            get\n+            {\n+                return _maxResponseDrainSize;\n+            }\n+\n+            set\n+            {\n+                if (value <= 0)\n+                {\n+                    throw new ArgumentOutOfRangeException(\n+                        \"value\",\n+                        value,\n+                        string.Format(SR.net_http_value_must_be_greater_than, 0));\n+                }\n+\n+                CheckDisposedOrStarted();\n+                _maxResponseDrainSize = value;\n+            }\n+        }\n+        #endregion\n+\n+        protected override void Dispose(bool disposing)\n+        {\n+            if (disposing && !_disposed)\n+            {\n+                _disposed = true;\n+\n+                if (_sessionHandle != null)\n+                {\n+                    _sessionHandle.DangerousRelease();\n+                    SafeInternetHandle.DisposeAndClearHandle(ref _sessionHandle);\n+                }\n+            }\n+\n+            base.Dispose(disposing);\n+        }\n+\n+#if HTTP_DLL\n+        protected internal override Task<HttpResponseMessage> SendAsync(\n+            HttpRequestMessage request,\n+            CancellationToken cancellationToken)\n+#else\n+        protected override Task<HttpResponseMessage> SendAsync(\n+            HttpRequestMessage request,\n+            CancellationToken cancellationToken)\n+#endif\n+        {\n+            if (request == null)\n+            {\n+                throw new ArgumentNullException(\"request\", SR.net_http_handler_norequest);\n+            }\n+\n+            // Check for invalid combinations of properties.\n+            if (_proxy != null && _windowsProxyUsePolicy != WindowsProxyUsePolicy.UseCustomProxy)\n+            {\n+                throw new InvalidOperationException(SR.net_http_invalid_proxyusepolicy);\n+            }\n+\n+            if (_windowsProxyUsePolicy == WindowsProxyUsePolicy.UseCustomProxy && _proxy == null)\n+            {\n+                throw new InvalidOperationException(SR.net_http_invalid_proxy);\n+            }\n+\n+            if (_cookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer &&\n+                _cookieContainer == null)\n+            {\n+                throw new InvalidOperationException(SR.net_http_invalid_cookiecontainer);\n+            }\n+\n+            CheckDisposed();\n+\n+            SetOperationStarted();\n+\n+            TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>();\n+\n+            // Create RequestState object and save current values of handler settings.\n+            RequestState state = new RequestState();\n+            state.Tcs = tcs;\n+            state.CancellationToken = cancellationToken;\n+            state.RequestMessage = request;\n+            state.Handler = this;\n+            state.CheckCertificateRevocationList = _checkCertificateRevocationList;\n+            state.ServerCertificateValidationCallback = _serverCertificateValidationCallback;\n+            state.WindowsProxyUsePolicy = this.WindowsProxyUsePolicy;\n+            state.Proxy = this.Proxy;\n+            state.ServerCredentials = _serverCredentials;\n+\n+            try\n+            {\n+                Task.Factory.StartNew(StartRequest, state);\n+            }\n+            catch (Exception ex)\n+            {\n+                throw new HttpRequestException(\"SendAsync\", ex);\n+            }\n+\n+            return tcs.Task;\n+        }\n+\n+        private static uint ChooseAuthScheme(uint supportedSchemes)\n+        {\n+            foreach (uint authScheme in s_authSchemePriorityOrder)\n+            {\n+                if ((supportedSchemes & authScheme) != 0)\n+                {\n+                    return authScheme;\n+                }\n+            }\n+\n+            return 0;\n+        }\n+\n+        private static void WinHttpStatusCallback(\n+            IntPtr handle,\n+            IntPtr context,\n+            uint internetStatus,\n+            IntPtr statusInformation,\n+            uint statusInformationLength)\n+        {\n+            RequestState state;\n+\n+            // TODO: Use logging.\n+\n+            if (internetStatus != Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REDIRECT &&\n+                internetStatus != Interop.WinHttp.WINHTTP_CALLBACK_STATUS_SENDING_REQUEST)\n+            {\n+                return;\n+            }\n+\n+            // Get request state object.\n+            try\n+            {\n+                GCHandle gch = GCHandle.FromIntPtr(context);\n+                state = (RequestState)gch.Target;\n+            }\n+            catch (Exception)\n+            {\n+                // TODO: We should log this but an exception here is pretty rare and\n+                // is probably the result of a programming error.\n+\n+                // Closing the WinHTTP request handle will cancel the operation.\n+                Interop.WinHttp.WinHttpCloseHandle(handle);\n+\n+                return;\n+            }\n+\n+            if (internetStatus == Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REDIRECT)\n+            {\n+                try\n+                {\n+                    var redirectUriString = Marshal.PtrToStringUni(statusInformation);\n+                    var redirectUri = new Uri(redirectUriString);\n+\n+                    // If we're manually handling cookies, we need to reset them\n+                    // based on the new URI.\n+                    if (state.Handler._cookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer)\n+                    {\n+                        // Clear cookies.\n+                        if (!Interop.WinHttp.WinHttpAddRequestHeaders(\n+                            state.RequestHandle,\n+                            EmptyCookieHeader,\n+                            (uint)EmptyCookieHeader.Length,\n+                            Interop.WinHttp.WINHTTP_ADDREQ_FLAG_REPLACE))\n+                        {\n+                            var lastError = Marshal.GetLastWin32Error();\n+                            if (lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)\n+                            {\n+                                throw WinHttpException.CreateExceptionUsingError(lastError);\n+                            }\n+                        }\n+\n+                        // Re-add cookies. The GetCookieHeader() method will return the correct set of\n+                        // cookies based on the redirectUri.\n+                        string cookieHeader = GetCookieHeader(redirectUri, state.Handler._cookieContainer);\n+                        if (!string.IsNullOrEmpty(cookieHeader))\n+                        {\n+                            if (!Interop.WinHttp.WinHttpAddRequestHeaders(\n+                                state.RequestHandle,\n+                                cookieHeader,\n+                                (uint)cookieHeader.Length,\n+                                Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))\n+                            {\n+                                WinHttpException.ThrowExceptionUsingLastError();\n+                            }\n+                        }\n+                    }\n+\n+                    state.RequestMessage.RequestUri = redirectUri;\n+\n+                    // For security reasons, we drop the server credential if it is a \n+                    // NetworkCredential.  But we allow credentials in a CredentialCache\n+                    // since they are specifically tied to URI's.\n+                    if (!(state.ServerCredentials is CredentialCache))\n+                    {\n+                        state.ServerCredentials = null;\n+                    }\n+                }\n+                catch (Exception ex)\n+                {\n+                    Interop.WinHttp.WinHttpCloseHandle(handle);\n+                    state.SavedException = ex;\n+                }\n+            }\n+            else if (internetStatus == Interop.WinHttp.WINHTTP_CALLBACK_STATUS_SENDING_REQUEST)\n+            {\n+                if (state.RequestMessage.RequestUri.Scheme != UriSchemeHttps)\n+                {\n+                    // Not SSL/TLS.\n+                    return;\n+                }\n+\n+                // Grab the channel binding token (CBT) information from the request handle and put it into\n+                // the TransportContext object.\n+                try\n+                {\n+                    state.TransportContext.SetChannelBinding(state.RequestHandle);\n+                }\n+                catch (Exception ex)\n+                {\n+                    Interop.WinHttp.WinHttpCloseHandle(handle);\n+                    state.SavedException = ex;\n+\n+                    return;\n+                }\n+\n+                if (state.ServerCertificateValidationCallback != null)\n+                {\n+                    IntPtr data = IntPtr.Zero;\n+                    uint dataSize = (uint)IntPtr.Size;\n+\n+                    if (Interop.WinHttp.WinHttpQueryOption(\n+                        state.RequestHandle,\n+                        Interop.WinHttp.WINHTTP_OPTION_SERVER_CERT_CONTEXT,\n+                        ref data,\n+                        ref dataSize))\n+                    {\n+                        var serverCertificate = new X509Certificate2(data);\n+                        Interop.Crypt32.CertFreeCertificateContext(data);\n+\n+                        X509Chain chain = null;\n+                        SslPolicyErrors sslPolicyErrors;\n+\n+                        try\n+                        {\n+                            CertificateHelper.BuildChain(\n+                                serverCertificate,\n+                                state.RequestMessage.RequestUri.Host,\n+                                state.CheckCertificateRevocationList,\n+                                out chain,\n+                                out sslPolicyErrors);\n+\n+                            var result = state.ServerCertificateValidationCallback(\n+                                state.RequestMessage,\n+                                serverCertificate,\n+                                chain,\n+                                sslPolicyErrors);\n+                            if (!result)\n+                            {\n+                                Interop.WinHttp.WinHttpCloseHandle(handle);\n+                                state.SavedException = \n+                                    WinHttpException.CreateExceptionUsingError((int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE);\n+                            }\n+                        }\n+                        catch (Exception ex)\n+                        {\n+                            Interop.WinHttp.WinHttpCloseHandle(handle);\n+                            state.SavedException = ex;\n+                        }\n+                        finally\n+                        {\n+                            if (chain != null)\n+                            {\n+                                chain.Dispose();\n+                            }\n+                        }\n+                    }\n+                    else\n+                    {\n+                        var lastError = Marshal.GetLastWin32Error();\n+                        Interop.WinHttp.WinHttpCloseHandle(handle);\n+                        state.SavedException = WinHttpException.CreateExceptionUsingError(lastError);\n+                    }\n+                }\n+            }\n+        }\n+\n+        private static bool IsChunkedModeForSend(HttpRequestMessage requestMessage)\n+        {\n+            bool chunkedMode = requestMessage.Headers.TransferEncodingChunked.HasValue &&\n+                requestMessage.Headers.TransferEncodingChunked.Value;\n+\n+            HttpContent requestContent = requestMessage.Content;\n+            if (requestContent != null)\n+            {\n+                if (requestContent.Headers.ContentLength.HasValue)\n+                {\n+                    if (chunkedMode)\n+                    {\n+                        // Deal with conflict between 'Content-Length' vs. 'Transfer-Encoding: chunked' semantics.\n+                        // Current .NET Desktop HttpClientHandler allows both headers to be specified but ends up\n+                        // stripping out 'Content-Length' and using chunked semantics.  WinHttpHandler will maintain\n+                        // the same behavior.\n+                        requestContent.Headers.ContentLength = null;\n+                    }\n+                }\n+                else\n+                {\n+                    if (!chunkedMode)\n+                    {\n+                        // Neither 'Content-Length' nor 'Transfer-Encoding: chunked' semantics was given.\n+                        // Current .NET Desktop HttpClientHandler uses 'Content-Length' semantics and\n+                        // buffers the content as well in some cases.  But the WinHttpHandler can't access\n+                        // the protected internal TryComputeLength() method of the content.  So, it\n+                        // will use'Transfer-Encoding: chunked' semantics.\n+                        chunkedMode = true;\n+                        requestMessage.Headers.TransferEncodingChunked = true;\n+                    }\n+                }\n+            }\n+            else if (chunkedMode)\n+            {\n+                throw new InvalidOperationException(SR.net_http_chunked_not_allowed_with_empty_content);\n+            }\n+\n+            return chunkedMode;\n+        }\n+\n+        // TODO: Refactor to smaller files. Perhaps split cookie handling into separate class.\n+        private static string GetCookieHeader(Uri uri, CookieContainer cookies)\n+        {\n+            string cookieHeader = null;\n+\n+            Debug.Assert(cookies != null);\n+\n+            string cookieValues = cookies.GetCookieHeader(uri);\n+            if (!string.IsNullOrEmpty(cookieValues))\n+            {\n+                cookieHeader = string.Format(CultureInfo.InvariantCulture, \"{0}: {1}\", HeaderNameCookie, cookieValues);\n+            }\n+\n+            return cookieHeader;\n+        }\n+\n+        private static void AddRequestHeaders(\n+            SafeInternetHandle requestHandle,\n+            HttpRequestMessage requestMessage,\n+            CookieContainer cookies)\n+        {\n+            var requestHeadersBuffer = new StringBuilder();\n+\n+            // Manually add cookies.\n+            if (cookies != null)\n+            {\n+                string cookieHeader = GetCookieHeader(requestMessage.RequestUri, cookies);\n+                if (!string.IsNullOrEmpty(cookieHeader))\n+                {\n+                    requestHeadersBuffer.AppendLine(cookieHeader);\n+                }\n+            }\n+\n+            // Serialize general request headers.\n+            requestHeadersBuffer.AppendLine(requestMessage.Headers.ToString());\n+\n+            // Serialize entity-body (content) headers.\n+            if (requestMessage.Content != null)\n+            {\n+                // TODO: Content-Length header isn't getting correctly placed using ToString()\n+                // This is a bug in HttpContentHeaders that needs to be fixed.\n+                if (requestMessage.Content.Headers.ContentLength.HasValue)\n+                {\n+                    long contentLength = requestMessage.Content.Headers.ContentLength.Value;\n+                    requestMessage.Content.Headers.ContentLength = null;\n+                    requestMessage.Content.Headers.ContentLength = contentLength;\n+                }\n+\n+                requestHeadersBuffer.AppendLine(requestMessage.Content.Headers.ToString());\n+            }\n+\n+            // Add request headers to WinHTTP request handle.\n+            if (!Interop.WinHttp.WinHttpAddRequestHeaders(\n+                requestHandle,\n+                requestHeadersBuffer,\n+                (uint)requestHeadersBuffer.Length,\n+                Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))\n+            {\n+                WinHttpException.ThrowExceptionUsingLastError();\n+            }\n+        }\n+\n+        private void EnsureSessionHandleExists(RequestState state)\n+        {\n+            bool ignore = false;\n+\n+            if (_sessionHandle == null)\n+            {\n+                lock (_lockObject)\n+                {\n+                    if (_sessionHandle == null)\n+                    {\n+                        uint accessType;\n+\n+                        // If a custom proxy is specified and it is really the system web proxy\n+                        // (initial WebRequest.DefaultWebProxy) then we need to update the settings\n+                        // since that object is only a sentinel.\n+                        if (state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.UseCustomProxy)\n+                        {\n+                            Debug.Assert(state.Proxy != null);\n+                            try\n+                            {\n+                                state.Proxy.GetProxy(state.RequestMessage.RequestUri);\n+                            }\n+                            catch (PlatformNotSupportedException)\n+                            {\n+                                // This is the system web proxy.\n+                                state.WindowsProxyUsePolicy = WindowsProxyUsePolicy.UseWinInetProxy;\n+                                state.Proxy = null;\n+                            }\n+                        }\n+\n+                        if (state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.DoNotUseProxy ||\n+                            state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.UseCustomProxy)\n+                        {\n+                            // Either no proxy at all or a custom IWebProxy proxy is specified.\n+                            // For a custom IWebProxy, we'll need to calculate and set the proxy\n+                            // on a per request handle basis using the request Uri.  For now,\n+                            // we set the session handle to have no proxy.\n+                            accessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NO_PROXY;\n+                        }\n+                        else if (state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.UseWinHttpProxy)\n+                        {\n+                            // Use WinHTTP per-machine proxy settings which are set using the \"netsh winhttp\" command.\n+                            accessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;\n+                        }\n+                        else\n+                        {\n+                            // Use WinInet per-user proxy settings.\n+                            accessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY;\n+                        }\n+\n+                        _sessionHandle = Interop.WinHttp.WinHttpOpen(\n+                            IntPtr.Zero,\n+                            accessType,\n+                            Interop.WinHttp.WINHTTP_NO_PROXY_NAME,\n+                            Interop.WinHttp.WINHTTP_NO_PROXY_BYPASS,\n+                            0);\n+                        if (!_sessionHandle.IsInvalid)\n+                        {\n+                            _sessionHandle.DangerousAddRef(ref ignore);\n+\n+                            return;\n+                        }\n+\n+                        var lastError = Marshal.GetLastWin32Error();\n+                        if (lastError != Interop.WinHttp.ERROR_INVALID_PARAMETER)\n+                        {\n+                            throw new HttpRequestException(\n+                                SR.net_http_client_execution_error,\n+                                WinHttpException.CreateExceptionUsingError(lastError));\n+                        }\n+\n+                        // We must be running on a platform earlier than Win8.1/Win2K12R2 which doesn't support\n+                        // WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY.  So, we'll need to read the Wininet style proxy\n+                        // settings ourself using our WinInetProxyHelper object.\n+                        _proxyHelper = new WinInetProxyHelper();\n+                        _sessionHandle = Interop.WinHttp.WinHttpOpen(\n+                            IntPtr.Zero,\n+                            _proxyHelper.ManualSettingsOnly ? Interop.WinHttp.WINHTTP_ACCESS_TYPE_NAMED_PROXY : Interop.WinHttp.WINHTTP_ACCESS_TYPE_NO_PROXY,\n+                            _proxyHelper.ManualSettingsOnly ? _proxyHelper.Proxy : Interop.WinHttp.WINHTTP_NO_PROXY_NAME,\n+                            _proxyHelper.ManualSettingsOnly ? _proxyHelper.ProxyBypass : Interop.WinHttp.WINHTTP_NO_PROXY_BYPASS,\n+                            0);\n+                        if (_sessionHandle.IsInvalid)\n+                        {\n+                            throw new HttpRequestException(\n+                                SR.net_http_client_execution_error,\n+                                WinHttpException.CreateExceptionUsingLastError());\n+                        }\n+\n+                        _sessionHandle.DangerousAddRef(ref ignore);\n+                    }\n+                }\n+            }\n+        }\n+\n+        private bool GetServerCredentialsFromCache(\n+            Uri uri,\n+            out uint serverAuthScheme,\n+            out NetworkCredential serverCredentials)\n+        {\n+            serverAuthScheme = 0;\n+            serverCredentials = null;\n+\n+            NetworkCredential cred = null;\n+\n+            lock (_credentialCacheLock)\n+            {\n+                foreach (uint authScheme in s_authSchemePriorityOrder)\n+                {\n+                    cred = _credentialCache.GetCredential(uri, s_authSchemeStringMapping[authScheme]);\n+                    if (cred != null)\n+                    {\n+                        serverAuthScheme = authScheme;\n+                        serverCredentials = cred;\n+\n+                        return true;\n+                    }\n+                }\n+            }\n+\n+            return false;\n+        }\n+\n+        private void SaveServerCredentialsToCache(Uri uri, uint authScheme, ICredentials serverCredentials)\n+        {\n+            string authType = s_authSchemeStringMapping[authScheme];\n+            Debug.Assert(!string.IsNullOrEmpty(authType));\n+\n+            NetworkCredential cred = serverCredentials.GetCredential(uri, authType);\n+            if (cred != null)\n+            {\n+                lock (_credentialCacheLock)\n+                {\n+                    try\n+                    {\n+                        _credentialCache.Add(uri, authType, cred);\n+                    }\n+                    catch (ArgumentException)\n+                    {\n+                        // The credential was already added.\n+                    }\n+                }\n+            }\n+        }\n+\n+        private async void StartRequest(object obj)\n+        {\n+            RequestState state = obj as RequestState;","path":"src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs","position":1080,"original_position":1080,"commit_id":"1f3b12168a61f103f403041b1458f2427c52070e","original_commit_id":"1f3b12168a61f103f403041b1458f2427c52070e","user":{"login":"davidsh","id":7684835,"avatar_url":"https://avatars.githubusercontent.com/u/7684835?v=3","gravatar_id":"","url":"https://api.github.com/users/davidsh","html_url":"https://github.com/davidsh","followers_url":"https://api.github.com/users/davidsh/followers","following_url":"https://api.github.com/users/davidsh/following{/other_user}","gists_url":"https://api.github.com/users/davidsh/gists{/gist_id}","starred_url":"https://api.github.com/users/davidsh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davidsh/subscriptions","organizations_url":"https://api.github.com/users/davidsh/orgs","repos_url":"https://api.github.com/users/davidsh/repos","events_url":"https://api.github.com/users/davidsh/events{/privacy}","received_events_url":"https://api.github.com/users/davidsh/received_events","type":"User","site_admin":false},"body":"FIXED: Changed to (RequestState)obj","created_at":"2015-06-25T16:25:03Z","updated_at":"2015-06-25T16:25:03Z","html_url":"https://github.com/dotnet/corefx/pull/2149#discussion_r33274336","pull_request_url":"https://api.github.com/repos/dotnet/corefx/pulls/2149","_links":{"self":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/comments/33274336"},"html":{"href":"https://github.com/dotnet/corefx/pull/2149#discussion_r33274336"},"pull_request":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/2149"}}},"pull_request":{"url":"https://api.github.com/repos/dotnet/corefx/pulls/2149","id":38469142,"html_url":"https://github.com/dotnet/corefx/pull/2149","diff_url":"https://github.com/dotnet/corefx/pull/2149.diff","patch_url":"https://github.com/dotnet/corefx/pull/2149.patch","issue_url":"https://api.github.com/repos/dotnet/corefx/issues/2149","number":2149,"state":"open","locked":false,"title":"Initial open source WinHttpHandler","user":{"login":"davidsh","id":7684835,"avatar_url":"https://avatars.githubusercontent.com/u/7684835?v=3","gravatar_id":"","url":"https://api.github.com/users/davidsh","html_url":"https://github.com/davidsh","followers_url":"https://api.github.com/users/davidsh/followers","following_url":"https://api.github.com/users/davidsh/following{/other_user}","gists_url":"https://api.github.com/users/davidsh/gists{/gist_id}","starred_url":"https://api.github.com/users/davidsh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davidsh/subscriptions","organizations_url":"https://api.github.com/users/davidsh/orgs","repos_url":"https://api.github.com/users/davidsh/repos","events_url":"https://api.github.com/users/davidsh/events{/privacy}","received_events_url":"https://api.github.com/users/davidsh/received_events","type":"User","site_admin":false},"body":"This is the initial open sourcing of the System.Net.Http.WinHttpHandler package. This commit also includes a fully buildable System.Net.Http.dll binary as well as System.Net.Http.WinHttpHandler.dll binary.  Unit tests are included as well.  There is a skeleton file for beginning cross-platform work on System.Net.Http.","created_at":"2015-06-24T17:56:54Z","updated_at":"2015-06-25T16:25:03Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f7786ad794c1e91e12f860cd6b9634d5b957b3e5","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/dotnet/corefx/pulls/2149/commits","review_comments_url":"https://api.github.com/repos/dotnet/corefx/pulls/2149/comments","review_comment_url":"https://api.github.com/repos/dotnet/corefx/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dotnet/corefx/issues/2149/comments","statuses_url":"https://api.github.com/repos/dotnet/corefx/statuses/1f3b12168a61f103f403041b1458f2427c52070e","head":{"label":"davidsh:winhttphandler","ref":"winhttphandler","sha":"1f3b12168a61f103f403041b1458f2427c52070e","user":{"login":"davidsh","id":7684835,"avatar_url":"https://avatars.githubusercontent.com/u/7684835?v=3","gravatar_id":"","url":"https://api.github.com/users/davidsh","html_url":"https://github.com/davidsh","followers_url":"https://api.github.com/users/davidsh/followers","following_url":"https://api.github.com/users/davidsh/following{/other_user}","gists_url":"https://api.github.com/users/davidsh/gists{/gist_id}","starred_url":"https://api.github.com/users/davidsh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davidsh/subscriptions","organizations_url":"https://api.github.com/users/davidsh/orgs","repos_url":"https://api.github.com/users/davidsh/repos","events_url":"https://api.github.com/users/davidsh/events{/privacy}","received_events_url":"https://api.github.com/users/davidsh/received_events","type":"User","site_admin":false},"repo":{"id":31976766,"name":"corefx","full_name":"davidsh/corefx","owner":{"login":"davidsh","id":7684835,"avatar_url":"https://avatars.githubusercontent.com/u/7684835?v=3","gravatar_id":"","url":"https://api.github.com/users/davidsh","html_url":"https://github.com/davidsh","followers_url":"https://api.github.com/users/davidsh/followers","following_url":"https://api.github.com/users/davidsh/following{/other_user}","gists_url":"https://api.github.com/users/davidsh/gists{/gist_id}","starred_url":"https://api.github.com/users/davidsh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davidsh/subscriptions","organizations_url":"https://api.github.com/users/davidsh/orgs","repos_url":"https://api.github.com/users/davidsh/repos","events_url":"https://api.github.com/users/davidsh/events{/privacy}","received_events_url":"https://api.github.com/users/davidsh/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/davidsh/corefx","description":"This repo contains the .NET Core foundational libraries, called CoreFX. It includes classes for collections, file systems, console, XML, async and many others.","fork":true,"url":"https://api.github.com/repos/davidsh/corefx","forks_url":"https://api.github.com/repos/davidsh/corefx/forks","keys_url":"https://api.github.com/repos/davidsh/corefx/keys{/key_id}","collaborators_url":"https://api.github.com/repos/davidsh/corefx/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/davidsh/corefx/teams","hooks_url":"https://api.github.com/repos/davidsh/corefx/hooks","issue_events_url":"https://api.github.com/repos/davidsh/corefx/issues/events{/number}","events_url":"https://api.github.com/repos/davidsh/corefx/events","assignees_url":"https://api.github.com/repos/davidsh/corefx/assignees{/user}","branches_url":"https://api.github.com/repos/davidsh/corefx/branches{/branch}","tags_url":"https://api.github.com/repos/davidsh/corefx/tags","blobs_url":"https://api.github.com/repos/davidsh/corefx/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/davidsh/corefx/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/davidsh/corefx/git/refs{/sha}","trees_url":"https://api.github.com/repos/davidsh/corefx/git/trees{/sha}","statuses_url":"https://api.github.com/repos/davidsh/corefx/statuses/{sha}","languages_url":"https://api.github.com/repos/davidsh/corefx/languages","stargazers_url":"https://api.github.com/repos/davidsh/corefx/stargazers","contributors_url":"https://api.github.com/repos/davidsh/corefx/contributors","subscribers_url":"https://api.github.com/repos/davidsh/corefx/subscribers","subscription_url":"https://api.github.com/repos/davidsh/corefx/subscription","commits_url":"https://api.github.com/repos/davidsh/corefx/commits{/sha}","git_commits_url":"https://api.github.com/repos/davidsh/corefx/git/commits{/sha}","comments_url":"https://api.github.com/repos/davidsh/corefx/comments{/number}","issue_comment_url":"https://api.github.com/repos/davidsh/corefx/issues/comments{/number}","contents_url":"https://api.github.com/repos/davidsh/corefx/contents/{+path}","compare_url":"https://api.github.com/repos/davidsh/corefx/compare/{base}...{head}","merges_url":"https://api.github.com/repos/davidsh/corefx/merges","archive_url":"https://api.github.com/repos/davidsh/corefx/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/davidsh/corefx/downloads","issues_url":"https://api.github.com/repos/davidsh/corefx/issues{/number}","pulls_url":"https://api.github.com/repos/davidsh/corefx/pulls{/number}","milestones_url":"https://api.github.com/repos/davidsh/corefx/milestones{/number}","notifications_url":"https://api.github.com/repos/davidsh/corefx/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/davidsh/corefx/labels{/name}","releases_url":"https://api.github.com/repos/davidsh/corefx/releases{/id}","created_at":"2015-03-10T19:16:38Z","updated_at":"2015-05-06T21:44:49Z","pushed_at":"2015-06-24T17:54:18Z","git_url":"git://github.com/davidsh/corefx.git","ssh_url":"git@github.com:davidsh/corefx.git","clone_url":"https://github.com/davidsh/corefx.git","svn_url":"https://github.com/davidsh/corefx","homepage":"","size":22336,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"dotnet:master","ref":"master","sha":"39cbff972a11a01026b9d8b481d36742707bd691","user":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars.githubusercontent.com/u/9141961?v=3","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"repo":{"id":26295345,"name":"corefx","full_name":"dotnet/corefx","owner":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars.githubusercontent.com/u/9141961?v=3","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dotnet/corefx","description":"This repo contains the .NET Core foundational libraries, called CoreFX. It includes classes for collections, file systems, console, XML, async and many others.","fork":false,"url":"https://api.github.com/repos/dotnet/corefx","forks_url":"https://api.github.com/repos/dotnet/corefx/forks","keys_url":"https://api.github.com/repos/dotnet/corefx/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dotnet/corefx/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dotnet/corefx/teams","hooks_url":"https://api.github.com/repos/dotnet/corefx/hooks","issue_events_url":"https://api.github.com/repos/dotnet/corefx/issues/events{/number}","events_url":"https://api.github.com/repos/dotnet/corefx/events","assignees_url":"https://api.github.com/repos/dotnet/corefx/assignees{/user}","branches_url":"https://api.github.com/repos/dotnet/corefx/branches{/branch}","tags_url":"https://api.github.com/repos/dotnet/corefx/tags","blobs_url":"https://api.github.com/repos/dotnet/corefx/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dotnet/corefx/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dotnet/corefx/git/refs{/sha}","trees_url":"https://api.github.com/repos/dotnet/corefx/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dotnet/corefx/statuses/{sha}","languages_url":"https://api.github.com/repos/dotnet/corefx/languages","stargazers_url":"https://api.github.com/repos/dotnet/corefx/stargazers","contributors_url":"https://api.github.com/repos/dotnet/corefx/contributors","subscribers_url":"https://api.github.com/repos/dotnet/corefx/subscribers","subscription_url":"https://api.github.com/repos/dotnet/corefx/subscription","commits_url":"https://api.github.com/repos/dotnet/corefx/commits{/sha}","git_commits_url":"https://api.github.com/repos/dotnet/corefx/git/commits{/sha}","comments_url":"https://api.github.com/repos/dotnet/corefx/comments{/number}","issue_comment_url":"https://api.github.com/repos/dotnet/corefx/issues/comments{/number}","contents_url":"https://api.github.com/repos/dotnet/corefx/contents/{+path}","compare_url":"https://api.github.com/repos/dotnet/corefx/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dotnet/corefx/merges","archive_url":"https://api.github.com/repos/dotnet/corefx/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dotnet/corefx/downloads","issues_url":"https://api.github.com/repos/dotnet/corefx/issues{/number}","pulls_url":"https://api.github.com/repos/dotnet/corefx/pulls{/number}","milestones_url":"https://api.github.com/repos/dotnet/corefx/milestones{/number}","notifications_url":"https://api.github.com/repos/dotnet/corefx/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dotnet/corefx/labels{/name}","releases_url":"https://api.github.com/repos/dotnet/corefx/releases{/id}","created_at":"2014-11-06T23:42:48Z","updated_at":"2015-06-25T08:51:51Z","pushed_at":"2015-06-25T15:28:23Z","git_url":"git://github.com/dotnet/corefx.git","ssh_url":"git@github.com:dotnet/corefx.git","clone_url":"https://github.com/dotnet/corefx.git","svn_url":"https://github.com/dotnet/corefx","homepage":"http://dotnet.github.io/core/","size":49116,"stargazers_count":7960,"watchers_count":7960,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1632,"mirror_url":null,"open_issues_count":438,"forks":1632,"open_issues":438,"watchers":7960,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/2149"},"html":{"href":"https://github.com/dotnet/corefx/pull/2149"},"issue":{"href":"https://api.github.com/repos/dotnet/corefx/issues/2149"},"comments":{"href":"https://api.github.com/repos/dotnet/corefx/issues/2149/comments"},"review_comments":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/2149/comments"},"review_comment":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/2149/commits"},"statuses":{"href":"https://api.github.com/repos/dotnet/corefx/statuses/1f3b12168a61f103f403041b1458f2427c52070e"}}}}