Imported Upstream version 5.0.0.42

Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-04-10 11:41:01 +00:00
parent 1190d13a04
commit 6bdd276d05
19939 changed files with 3099680 additions and 93811 deletions

View File

@@ -0,0 +1,78 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.22816.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{BB2D2F6C-0445-43D4-84A9-DF5B4931FA19}") = "System.Net.Http.WinHttpHandler.Unit.Tests", "tests\UnitTests\System.Net.Http.WinHttpHandler.Unit.Tests.csproj", "{A2ECDEDB-12B7-402C-9230-152B7601179F}"
ProjectSection(ProjectDependencies) = postProject
{} = {}
EndProjectSection
EndProject
Project("{BB2D2F6C-0445-43D4-84A9-DF5B4931FA19}") = "System.Net.Http.WinHttpHandler.Functional.Tests", "tests\FunctionalTests\System.Net.Http.WinHttpHandler.Functional.Tests.csproj", "{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}"
ProjectSection(ProjectDependencies) = postProject
{} = {}
EndProjectSection
EndProject
Project("{BB2D2F6C-0445-43D4-84A9-DF5B4931FA19}") = "System.Net.Http.WinHttpHandler.Functional.Tests", "tests\FunctionalTests\System.Net.Http.WinHttpHandler.Functional.Tests.csproj", "{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}"
ProjectSection(ProjectDependencies) = postProject
{F75E3008-0562-42DF-BE72-C1384F12157E} = {F75E3008-0562-42DF-BE72-C1384F12157E}
EndProjectSection
EndProject
Project("{BB2D2F6C-0445-43D4-84A9-DF5B4931FA19}") = "System.Net.Http.WinHttpHandler.Unit.Tests", "tests\UnitTests\System.Net.Http.WinHttpHandler.Unit.Tests.csproj", "{A2ECDEDB-12B7-402C-9230-152B7601179F}"
ProjectSection(ProjectDependencies) = postProject
{F75E3008-0562-42DF-BE72-C1384F12157E} = {F75E3008-0562-42DF-BE72-C1384F12157E}
EndProjectSection
EndProject
Project("{BB2D2F6C-0445-43D4-84A9-DF5B4931FA19}") = "System.Net.Http.WinHttpHandler", "src\System.Net.Http.WinHttpHandler.csproj", "{F75E3008-0562-42DF-BE72-C1384F12157E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
DebugNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU = DebugNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU
ReleaseNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU = ReleaseNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU
DebugNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU = DebugNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU
ReleaseNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU = ReleaseNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU
DebugNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU = DebugNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU
ReleaseNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU = ReleaseNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}.DebugNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Debug|Any CPU
{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}.DebugNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Debug|Any CPU
{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}.ReleaseNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Release|Any CPU
{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}.ReleaseNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Release|Any CPU
{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}.DebugNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Debug|Any CPU
{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}.DebugNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Debug|Any CPU
{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}.ReleaseNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Release|Any CPU
{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}.ReleaseNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Release|Any CPU
{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}.DebugNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Debug|Any CPU
{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}.DebugNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Debug|Any CPU
{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}.ReleaseNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Release|Any CPU
{17D5CC82-F72C-4DD2-B6DB-DE7FB2F19C34}.ReleaseNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Release|Any CPU
{A2ECDEDB-12B7-402C-9230-152B7601179F}.DebugNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Debug|Any CPU
{A2ECDEDB-12B7-402C-9230-152B7601179F}.DebugNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Debug|Any CPU
{A2ECDEDB-12B7-402C-9230-152B7601179F}.ReleaseNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Release|Any CPU
{A2ECDEDB-12B7-402C-9230-152B7601179F}.ReleaseNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Release|Any CPU
{A2ECDEDB-12B7-402C-9230-152B7601179F}.DebugNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Debug|Any CPU
{A2ECDEDB-12B7-402C-9230-152B7601179F}.DebugNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Debug|Any CPU
{A2ECDEDB-12B7-402C-9230-152B7601179F}.ReleaseNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Release|Any CPU
{A2ECDEDB-12B7-402C-9230-152B7601179F}.ReleaseNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Release|Any CPU
{A2ECDEDB-12B7-402C-9230-152B7601179F}.DebugNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Debug|Any CPU
{A2ECDEDB-12B7-402C-9230-152B7601179F}.DebugNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Debug|Any CPU
{A2ECDEDB-12B7-402C-9230-152B7601179F}.ReleaseNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Release|Any CPU
{A2ECDEDB-12B7-402C-9230-152B7601179F}.ReleaseNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Release|Any CPU
{F75E3008-0562-42DF-BE72-C1384F12157E}.DebugNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Debug|Any CPU
{F75E3008-0562-42DF-BE72-C1384F12157E}.DebugNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Debug|Any CPU
{F75E3008-0562-42DF-BE72-C1384F12157E}.ReleaseNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Windows_NT-Release|Any CPU
{F75E3008-0562-42DF-BE72-C1384F12157E}.ReleaseNETCoreAppnetstandard1.3-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Windows_NT-Release|Any CPU
{F75E3008-0562-42DF-BE72-C1384F12157E}.DebugNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Unix-Debug|Any CPU
{F75E3008-0562-42DF-BE72-C1384F12157E}.DebugNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Unix-Debug|Any CPU
{F75E3008-0562-42DF-BE72-C1384F12157E}.ReleaseNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = netstandard1.3-Unix-Release|Any CPU
{F75E3008-0562-42DF-BE72-C1384F12157E}.ReleaseNETCoreAppnetstandard1.3-Unixnetstandard1.3-Windows_NT|AnyCPU.Build.0 = netstandard1.3-Unix-Release|Any CPU
{F75E3008-0562-42DF-BE72-C1384F12157E}.DebugNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = net46-Windows_NT-Debug|Any CPU
{F75E3008-0562-42DF-BE72-C1384F12157E}.DebugNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.Build.0 = net46-Windows_NT-Debug|Any CPU
{F75E3008-0562-42DF-BE72-C1384F12157E}.ReleaseNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.ActiveCfg = net46-Windows_NT-Release|Any CPU
{F75E3008-0562-42DF-BE72-C1384F12157E}.ReleaseNETCoreAppnet46-Windows_NTnetstandard1.3-Windows_NT|AnyCPU.Build.0 = net46-Windows_NT-Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\dir.props" />
<PropertyGroup>
<AssemblyVersion>4.0.2.0</AssemblyVersion>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<Project Include="System.Net.Http.WinHttpHandler.pkgproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" />
</Project>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Net.Http.WinHttpHandler.csproj">
<SupportedFramework>net46;netcoreapp1.0</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Net.Http.WinHttpHandler.builds" />
<NotSupportedOnTargetFramework Include="netcore50">
<PackageTargetRuntime>win</PackageTargetRuntime>
</NotSupportedOnTargetFramework>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
netstandard;
</BuildConfigurations>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,52 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// ------------------------------------------------------------------------------
// Changes to this file must follow the http://aka.ms/api-review process.
// ------------------------------------------------------------------------------
namespace System.Net.Http
{
public enum CookieUsePolicy
{
IgnoreCookies = 0,
UseInternalCookieStoreOnly = 1,
UseSpecifiedCookieContainer = 2,
}
public enum WindowsProxyUsePolicy
{
DoNotUseProxy = 0,
UseCustomProxy = 3,
UseWinHttpProxy = 1,
UseWinInetProxy = 2,
}
public partial class WinHttpHandler : System.Net.Http.HttpMessageHandler
{
public WinHttpHandler() { }
public System.Net.DecompressionMethods AutomaticDecompression { get { throw null; } set { } }
public bool AutomaticRedirection { get { throw null; } set { } }
public bool CheckCertificateRevocationList { get { throw null; } set { } }
public System.Net.Http.ClientCertificateOption ClientCertificateOption { get { throw null; } set { } }
public System.Security.Cryptography.X509Certificates.X509Certificate2Collection ClientCertificates { get { throw null; } }
public System.Net.CookieContainer CookieContainer { get { throw null; } set { } }
public System.Net.Http.CookieUsePolicy CookieUsePolicy { get { throw null; } set { } }
public System.Net.ICredentials DefaultProxyCredentials { get { throw null; } set { } }
public int MaxAutomaticRedirections { get { throw null; } set { } }
public int MaxConnectionsPerServer { get { throw null; } set { } }
public int MaxResponseDrainSize { get { throw null; } set { } }
public int MaxResponseHeadersLength { get { throw null; } set { } }
public bool PreAuthenticate { get { throw null; } set { } }
public System.Collections.Generic.IDictionary<string, object> Properties { get { throw null; } }
public System.Net.IWebProxy Proxy { get { throw null; } set { } }
public System.TimeSpan ReceiveDataTimeout { get { throw null; } set { } }
public System.TimeSpan ReceiveHeadersTimeout { get { throw null; } set { } }
public System.TimeSpan SendTimeout { get { throw null; } set { } }
public System.Func<System.Net.Http.HttpRequestMessage, System.Security.Cryptography.X509Certificates.X509Certificate2, System.Security.Cryptography.X509Certificates.X509Chain, System.Net.Security.SslPolicyErrors, bool> ServerCertificateValidationCallback { get { throw null; } set { } }
public System.Net.ICredentials ServerCredentials { get { throw null; } set { } }
public System.Security.Authentication.SslProtocols SslProtocols { get { throw null; } set { } }
public System.Net.Http.WindowsProxyUsePolicy WindowsProxyUsePolicy { get { throw null; } set { } }
protected override void Dispose(bool disposing) { }
protected override System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { throw null; }
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System.Net.Http.WinHttpHandler.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
netstandard1.3-Windows_NT;
netstandard1.3-Unix;
netstandard-Windows_NT;
netstandard-Unix;
net46-Windows_NT;
</BuildConfigurations>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="net_securityprotocolnotsupported" xml:space="preserve">
<value>The requested security protocol is not supported.</value>
</data>
<data name="net_http_invalid_cookiecontainer" xml:space="preserve">
<value>When using CookieUsePolicy.UseSpecifiedCookieContainer, the CookieContainer property must not be null.</value>
</data>
<data name="net_http_invalid_proxyusepolicy" xml:space="preserve">
<value>When using a non-null Proxy, the WindowsProxyUsePolicy property must be set to WindowsProxyUsePolicy.UseCustomProxy.</value>
</data>
<data name="net_http_invalid_proxy" xml:space="preserve">
<value>When using WindowsProxyUsePolicy.UseCustomProxy, the Proxy property must not be null.</value>
</data>
<data name="net_http_content_buffersize_limit" xml:space="preserve">
<value>Buffering more than {0} bytes is not supported.</value>
</data>
<data name="net_http_handler_norequest" xml:space="preserve">
<value>A request message must be provided. It cannot be null.</value>
</data>
<data name="net_http_operation_started" xml:space="preserve">
<value>This instance has already started one or more requests. Properties can only be modified before sending the first request.</value>
</data>
<data name="net_http_client_execution_error" xml:space="preserve">
<value>An error occurred while sending the request.</value>
</data>
<data name="net_http_io_read" xml:space="preserve">
<value>The read operation failed, see inner exception.</value>
</data>
<data name="net_http_io_read_incomplete" xml:space="preserve">
<value>Unable to read data from the transport connection. The connection was closed before all data could be read. Expected {0} bytes, read {1} bytes.</value>
</data>
<data name="net_http_io_write" xml:space="preserve">
<value>The write operation failed, see inner exception.</value>
</data>
<data name="net_http_chunked_not_allowed_with_empty_content" xml:space="preserve">
<value>'Transfer-Encoding: chunked' header can not be used when content object is not specified.</value>
</data>
<data name="net_http_value_must_be_greater_than" xml:space="preserve">
<value>The specified value must be greater than {0}.</value>
</data>
<data name="net_http_username_empty_string" xml:space="preserve">
<value>The username for a credential object cannot be null or empty.</value>
</data>
<data name="net_http_no_concurrent_io_allowed" xml:space="preserve">
<value>The stream does not support concurrent I/O read or write operations.</value>
</data>
<data name="net_http_buffer_insufficient_length" xml:space="preserve">
<value>The buffer was not long enough.</value>
</data>
<data name="ArgumentOutOfRange_NeedPosNum" xml:space="preserve">
<value>Positive number required.</value>
</data>
<data name="NotSupported_UnreadableStream" xml:space="preserve">
<value>Stream does not support reading.</value>
</data>
<data name="NotSupported_UnwritableStream" xml:space="preserve">
<value>Stream does not support writing.</value>
</data>
<data name="ObjectDisposed_StreamClosed" xml:space="preserve">
<value>Can not access a closed Stream.</value>
</data>
<data name="net_http_content_stream_already_read" xml:space="preserve">
<value>The stream was already consumed. It cannot be read again.</value>
</data>
</root>

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F75E3008-0562-42DF-BE72-C1384F12157E}</ProjectGuid>
<OutputType>Library</OutputType>
<AssemblyName>System.Net.Http.WinHttpHandler</AssemblyName>
<GeneratePlatformNotSupportedAssembly Condition="'$(TargetsUnix)' == 'true'">true</GeneratePlatformNotSupportedAssembly>
</PropertyGroup>
<!-- Help VS understand available configurations -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard1.3-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard1.3-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard1.3-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard1.3-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='net46-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='net46-Windows_NT-Release|AnyCPU'" />
<Import Project="System.Net.Http.WinHttpHandler.msbuild" Condition="'$(TargetsWindows)' == 'true'" />
<ItemGroup Condition="'$(TargetGroup)' == 'net46'">
<!-- Need to compile it here since the NET46 target here is building against System.Runtime whereas the
the list of other files in System.Net.Http.WinHttpHandler.msbuild is also used by System.Net.Http
library and the NET46 target there uses framework assembly references instead. -->
<CompileItem Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeHandleZeroOrMinusOneIsInvalid.cs" />
<CompileItem Include="$(CommonPath)\System\Net\HttpStatusDescription.cs" />
</ItemGroup>
<!-- For source files to be shown within the visual tree in Solution Explorer, the items must be
included directly in the project file. We have the *.msbuild define the Compile items in a made
up item called CompileItem and then just include it here. -->
<ItemGroup Condition=" '$(TargetsWindows)' == 'true' ">
<Compile Include="@(CompileItem)" />
<Compile Include="$(CommonPath)\System\IO\StreamHelpers.CopyValidation.cs">
<Link>Common\System\IO\StreamHelpers.CopyValidation.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Net\HttpVersionInternal.cs">
<Link>Common\System\Net\HttpVersionInternal.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<Reference Include="System.Buffers" />
<Reference Include="System.Diagnostics.DiagnosticSource" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netstandard1.3'">
<Reference Include="Microsoft.Win32.Primitives" />
<Reference Include="System.Collections" />
<Reference Include="System.Collections.NonGeneric" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.IO" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Primitives" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
<Reference Include="System.Runtime.Handles" />
<Reference Include="System.Runtime.InteropServices" />
<Reference Include="System.Security.Cryptography.X509Certificates" />
<Reference Include="System.Text.Encoding" />
<Reference Include="System.Threading" />
<Reference Include="System.Threading.Tasks" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<CompileItem Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs" />
<CompileItem Include="$(CommonPath)\Interop\Windows\Crypt32\Interop.certificates_types.cs" />
<CompileItem Include="$(CommonPath)\Interop\Windows\Crypt32\Interop.certificates.cs" />
<CompileItem Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FormatMessage.cs" />
<CompileItem Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetModuleHandle.cs" />
<CompileItem Include="$(CommonPath)\Interop\Windows\Interop.HRESULT_FROM_WIN32.cs" />
<CompileItem Include="$(CommonPath)\Interop\Windows\winhttp\Interop.SafeWinHttpHandle.cs" />
<CompileItem Include="$(CommonPath)\Interop\Windows\winhttp\Interop.winhttp_types.cs" />
<CompileItem Include="$(CommonPath)\Interop\Windows\winhttp\Interop.winhttp.cs" />
<CompileItem Include="$(CommonPath)\System\CharArrayHelpers.cs" />
<CompileItem Include="$(CommonPath)\System\StringExtensions.cs" />
<CompileItem Include="$(CommonPath)\System\Diagnostics\ExceptionExtensions.cs" />
<CompileItem Include="$(CommonPath)\System\Net\HttpKnownHeaderNames.cs" />
<CompileItem Include="$(CommonPath)\System\Net\HttpKnownHeaderNames.TryGetHeaderName.cs" />
<CompileItem Include="$(CommonPath)\System\Net\UriScheme.cs" />
<CompileItem Include="$(CommonPath)\System\Net\SecurityProtocol.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Http\HttpHandlerDefaults.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Http\HttpHandlerDiagnosticListenerExtensions.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Http\HttpHandlerLoggingStrings.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Http\NoWriteNoSeekStreamContent.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Http\WinHttpException.cs" />
<CompileItem Include="$(CommonPath)\System\Threading\Tasks\RendezvousAwaitable.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpAuthHelper.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpCertificateHelper.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpChannelBinding.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpCookieContainerAdapter.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpHandler.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpRequestCallback.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpRequestState.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpRequestStream.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpResponseHeaderReader.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpResponseParser.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpResponseStream.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpTraceHelper.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpTransportContext.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinInetProxyHelper.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' != 'net46'">
<CompileItem Include="$(CommonPath)\System\Net\HttpStatusDescription.cs" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,387 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using SafeWinHttpHandle = Interop.WinHttp.SafeWinHttpHandle;
namespace System.Net.Http
{
internal class WinHttpAuthHelper
{
// TODO: Issue #2165. This looks messy but it is fast. Research a cleaner way
// to do this which keeps high performance lookup.
//
// Fast lookup table to convert WINHTTP_AUTH constants to strings.
// WINHTTP_AUTH_SCHEME_BASIC = 0x00000001;
// WINHTTP_AUTH_SCHEME_NTLM = 0x00000002;
// WINHTTP_AUTH_SCHEME_DIGEST = 0x00000008;
// WINHTTP_AUTH_SCHEME_NEGOTIATE = 0x00000010;
private static readonly string[] s_authSchemeStringMapping =
{
null,
"Basic",
"NTLM",
null,
null,
null,
null,
null,
"Digest",
null,
null,
null,
null,
null,
null,
null,
"Negotiate"
};
private static readonly uint[] s_authSchemePriorityOrder =
{
Interop.WinHttp.WINHTTP_AUTH_SCHEME_NEGOTIATE,
Interop.WinHttp.WINHTTP_AUTH_SCHEME_NTLM,
Interop.WinHttp.WINHTTP_AUTH_SCHEME_DIGEST,
Interop.WinHttp.WINHTTP_AUTH_SCHEME_BASIC
};
// TODO: Issue #2165. This current design uses a handler-wide lock to Add/Retrieve
// from the cache. Need to improve this for next iteration in order
// to boost performance and scalability.
private readonly CredentialCache _credentialCache = new CredentialCache();
private readonly object _credentialCacheLock = new object();
public void CheckResponseForAuthentication(
WinHttpRequestState state,
ref uint proxyAuthScheme,
ref uint serverAuthScheme)
{
uint supportedSchemes = 0;
uint firstSchemeIgnored = 0;
uint authTarget = 0;
Uri uri = state.RequestMessage.RequestUri;
state.RetryRequest = false;
// Check the status code and retry the request applying credentials if needed.
var statusCode = (HttpStatusCode)WinHttpResponseParser.GetResponseHeaderNumberInfo(
state.RequestHandle,
Interop.WinHttp.WINHTTP_QUERY_STATUS_CODE);
switch (statusCode)
{
case HttpStatusCode.Unauthorized:
if (state.ServerCredentials == null || state.LastStatusCode == HttpStatusCode.Unauthorized)
{
// Either we don't have server credentials or we already tried
// to set the credentials and it failed before.
// So we will let the 401 be the final status code returned.
break;
}
state.LastStatusCode = statusCode;
// Determine authorization scheme to use. We ignore the firstScheme
// parameter which is included in the supportedSchemes flags already.
// We pass the schemes to ChooseAuthScheme which will pick the scheme
// based on most secure scheme to least secure scheme ordering.
if (!Interop.WinHttp.WinHttpQueryAuthSchemes(
state.RequestHandle,
out supportedSchemes,
out firstSchemeIgnored,
out authTarget))
{
// WinHTTP returns an error for schemes it doesn't handle.
// So, we need to ignore the error and just let it stay at 401.
break;
}
// WinHTTP returns the proper authTarget based on the status code (401, 407).
// But we can validate with assert.
Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER);
serverAuthScheme = ChooseAuthScheme(supportedSchemes);
if (serverAuthScheme != 0)
{
if (SetWinHttpCredential(
state.RequestHandle,
state.ServerCredentials,
uri,
serverAuthScheme,
authTarget))
{
state.RetryRequest = true;
}
}
break;
case HttpStatusCode.ProxyAuthenticationRequired:
if (state.LastStatusCode == HttpStatusCode.ProxyAuthenticationRequired)
{
// We tried already to set the credentials.
break;
}
state.LastStatusCode = statusCode;
// If we don't have any proxy credentials to try, then we end up with 407.
ICredentials proxyCreds = state.Proxy == null ?
state.DefaultProxyCredentials :
state.Proxy.Credentials;
if (proxyCreds == null)
{
break;
}
// Determine authorization scheme to use. We ignore the firstScheme
// parameter which is included in the supportedSchemes flags already.
// We pass the schemes to ChooseAuthScheme which will pick the scheme
// based on most secure scheme to least secure scheme ordering.
if (!Interop.WinHttp.WinHttpQueryAuthSchemes(
state.RequestHandle,
out supportedSchemes,
out firstSchemeIgnored,
out authTarget))
{
// WinHTTP returns an error for schemes it doesn't handle.
// So, we need to ignore the error and just let it stay at 401.
break;
}
// WinHTTP returns the proper authTarget based on the status code (401, 407).
// But we can validate with assert.
Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY);
proxyAuthScheme = ChooseAuthScheme(supportedSchemes);
state.RetryRequest = true;
break;
default:
if (state.PreAuthenticate && serverAuthScheme != 0)
{
SaveServerCredentialsToCache(uri, serverAuthScheme, state.ServerCredentials);
}
break;
}
}
public void PreAuthenticateRequest(WinHttpRequestState state, uint proxyAuthScheme)
{
// Set proxy credentials if we have them.
// If a proxy authentication challenge was responded to, reset
// those credentials before each SendRequest, because the proxy
// may require re-authentication after responding to a 401 or
// to a redirect. If you don't, you can get into a
// 407-401-407-401- loop.
if (proxyAuthScheme != 0)
{
ICredentials proxyCredentials;
Uri proxyUri;
if (state.Proxy != null)
{
proxyCredentials = state.Proxy.Credentials;
proxyUri = state.Proxy.GetProxy(state.RequestMessage.RequestUri);
}
else
{
proxyCredentials = state.DefaultProxyCredentials;
proxyUri = state.RequestMessage.RequestUri;
}
SetWinHttpCredential(
state.RequestHandle,
proxyCredentials,
proxyUri,
proxyAuthScheme,
Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY);
}
// Apply pre-authentication headers for server authentication?
if (state.PreAuthenticate)
{
uint authScheme;
NetworkCredential serverCredentials;
if (GetServerCredentialsFromCache(
state.RequestMessage.RequestUri,
out authScheme,
out serverCredentials))
{
SetWinHttpCredential(
state.RequestHandle,
serverCredentials,
state.RequestMessage.RequestUri,
authScheme,
Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER);
state.LastStatusCode = HttpStatusCode.Unauthorized; // Remember we already set the creds.
}
// No cached credential to use at this time. The request will first go out with no
// 'Authorization' header. Later, if a 401 occurs, we will be able to cache the credential
// since we will then know the proper auth scheme to use.
//
// TODO: Issue #2165. Adding logging to highlight the 'cache miss'.
}
}
// TODO: Issue #2165. Consider refactoring cache logic in separate class and avoid out parameters.
public bool GetServerCredentialsFromCache(
Uri uri,
out uint serverAuthScheme,
out NetworkCredential serverCredentials)
{
serverAuthScheme = 0;
serverCredentials = null;
NetworkCredential cred = null;
lock (_credentialCacheLock)
{
foreach (uint authScheme in s_authSchemePriorityOrder)
{
cred = _credentialCache.GetCredential(uri, s_authSchemeStringMapping[authScheme]);
if (cred != null)
{
serverAuthScheme = authScheme;
serverCredentials = cred;
return true;
}
}
}
return false;
}
public void SaveServerCredentialsToCache(Uri uri, uint authScheme, ICredentials serverCredentials)
{
string authType = s_authSchemeStringMapping[authScheme];
Debug.Assert(!string.IsNullOrEmpty(authType));
NetworkCredential cred = serverCredentials.GetCredential(uri, authType);
if (cred != null)
{
lock (_credentialCacheLock)
{
try
{
_credentialCache.Add(uri, authType, cred);
}
catch (ArgumentException)
{
// The credential was already added.
}
}
}
}
public void ChangeDefaultCredentialsPolicy(
SafeWinHttpHandle requestHandle,
uint authTarget,
bool allowDefaultCredentials)
{
Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY ||
authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER);
uint optionData = allowDefaultCredentials ?
(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY ?
Interop.WinHttp.WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM :
Interop.WinHttp.WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW) :
Interop.WinHttp.WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH;
if (!Interop.WinHttp.WinHttpSetOption(
requestHandle,
Interop.WinHttp.WINHTTP_OPTION_AUTOLOGON_POLICY,
ref optionData))
{
WinHttpException.ThrowExceptionUsingLastError();
}
}
private bool SetWinHttpCredential(
SafeWinHttpHandle requestHandle,
ICredentials credentials,
Uri uri,
uint authScheme,
uint authTarget)
{
string userName;
string password;
Debug.Assert(credentials != null);
Debug.Assert(authScheme != 0);
Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY ||
authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER);
NetworkCredential networkCredential = credentials.GetCredential(uri, s_authSchemeStringMapping[authScheme]);
if (networkCredential == null)
{
return false;
}
if (networkCredential == CredentialCache.DefaultNetworkCredentials)
{
// Only Negotiate and NTLM can use default credentials. Otherwise,
// behave as-if there were no credentials.
if (authScheme == Interop.WinHttp.WINHTTP_AUTH_SCHEME_NEGOTIATE ||
authScheme == Interop.WinHttp.WINHTTP_AUTH_SCHEME_NTLM)
{
// Allow WinHTTP to transmit the default credentials.
ChangeDefaultCredentialsPolicy(requestHandle, authTarget, allowDefaultCredentials:true);
userName = null;
password = null;
}
else
{
return false;
}
}
else
{
userName = networkCredential.UserName;
password = networkCredential.Password;
string domain = networkCredential.Domain;
// WinHTTP does not support a blank username. So, we will throw an exception.
if (string.IsNullOrEmpty(userName))
{
throw new InvalidOperationException(SR.net_http_username_empty_string);
}
if (!string.IsNullOrEmpty(domain))
{
userName = domain + "\\" + userName;
}
}
if (!Interop.WinHttp.WinHttpSetCredentials(
requestHandle,
authTarget,
authScheme,
userName,
password,
IntPtr.Zero))
{
WinHttpException.ThrowExceptionUsingLastError();
}
return true;
}
private static uint ChooseAuthScheme(uint supportedSchemes)
{
foreach (uint authScheme in s_authSchemePriorityOrder)
{
if ((supportedSchemes & authScheme) != 0)
{
return authScheme;
}
}
return 0;
}
}
}

View File

@@ -0,0 +1,126 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
namespace System.Net.Http
{
internal static class WinHttpCertificateHelper
{
private const string ClientAuthenticationOID = "1.3.6.1.5.5.7.3.2";
// TODO: Issue #2165. Merge with similar code used in System.Net.Security move to Common/src//System/Net.
public static void BuildChain(
X509Certificate2 certificate,
string hostName,
bool checkCertificateRevocationList,
out X509Chain chain,
out SslPolicyErrors sslPolicyErrors)
{
chain = null;
sslPolicyErrors = SslPolicyErrors.None;
// Build the chain.
chain = new X509Chain();
chain.ChainPolicy.RevocationMode =
checkCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
if (!chain.Build(certificate))
{
sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
}
// Verify the hostName matches the certificate.
unsafe
{
var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA();
cppStruct.cbSize = (uint)Marshal.SizeOf<Interop.Crypt32.CERT_CHAIN_POLICY_PARA>();
cppStruct.dwFlags = 0;
var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA();
eppStruct.cbSize = (uint)Marshal.SizeOf<Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA>();
eppStruct.dwAuthType = Interop.Crypt32.AuthType.AUTHTYPE_CLIENT;
cppStruct.pvExtraPolicyPara = &eppStruct;
fixed (char* namePtr = hostName)
{
eppStruct.pwszServerName = namePtr;
cppStruct.dwFlags =
Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL &
~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG;
var status = new Interop.Crypt32.CERT_CHAIN_POLICY_STATUS();
status.cbSize = (uint)Marshal.SizeOf<Interop.Crypt32.CERT_CHAIN_POLICY_STATUS>();
if (Interop.Crypt32.CertVerifyCertificateChainPolicy(
(IntPtr)Interop.Crypt32.CertChainPolicy.CERT_CHAIN_POLICY_SSL,
chain.SafeHandle,
ref cppStruct,
ref status))
{
if (status.dwError == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH)
{
sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
}
}
else
{
// Failure checking the policy. This is a rare error. We will assume the name check failed.
// TODO: Issue #2165. Log this error or perhaps throw an exception instead.
sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
}
}
}
}
public static X509Certificate2 GetEligibleClientCertificate()
{
// Get initial list of client certificates from the MY store.
X509Certificate2Collection candidateCerts;
using (var myStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
myStore.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
candidateCerts = myStore.Certificates;
}
return GetEligibleClientCertificate(candidateCerts);
}
// TODO: Issue #3891. Get the Trusted Issuers List from WinHTTP and use that to help narrow down
// the list of eligible client certificates.
public static X509Certificate2 GetEligibleClientCertificate(X509Certificate2Collection candidateCerts)
{
if (candidateCerts.Count == 0)
{
return null;
}
// Reduce the set of certificates to match the proper 'Client Authentication' criteria.
candidateCerts = candidateCerts.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, false);
candidateCerts = candidateCerts.Find(X509FindType.FindByApplicationPolicy, ClientAuthenticationOID, false);
// Build a new collection with certs that have a private key. Need to do this
// manually because there is no X509FindType to match this criteria.
var eligibleCerts = new X509Certificate2Collection();
foreach (X509Certificate2 cert in candidateCerts)
{
if (cert.HasPrivateKey)
{
eligibleCerts.Add(cert);
}
}
if (eligibleCerts.Count > 0)
{
return eligibleCerts[0];
}
else
{
return null;
}
}
}
}

View File

@@ -0,0 +1,79 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
using System.Security.Authentication.ExtendedProtection;
using System.Text;
using SafeWinHttpHandle = Interop.WinHttp.SafeWinHttpHandle;
namespace System.Net.Http
{
internal class WinHttpChannelBinding : ChannelBinding
{
private int _size = 0;
private string _cachedToString = null;
internal WinHttpChannelBinding(SafeWinHttpHandle requestHandle)
{
IntPtr data = IntPtr.Zero;
uint dataSize = 0;
if (!Interop.WinHttp.WinHttpQueryOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_SERVER_CBT, null, ref dataSize))
{
if (Marshal.GetLastWin32Error() == Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER)
{
data = Marshal.AllocHGlobal((int)dataSize);
if (Interop.WinHttp.WinHttpQueryOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_SERVER_CBT, data, ref dataSize))
{
SetHandle(data);
_size = (int)dataSize;
}
else
{
Marshal.FreeHGlobal(data);
}
}
}
}
public override bool IsInvalid
{
get
{
return _size == 0;
}
}
public override int Size
{
get
{
return _size;
}
}
public override string ToString()
{
if (_cachedToString == null && !IsInvalid)
{
var bytes = new byte[_size];
Marshal.Copy(this.handle, bytes, 0, _size);
_cachedToString = BitConverter.ToString(bytes).Replace('-', ' ');
}
return _cachedToString;
}
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(this.handle);
SetHandle(IntPtr.Zero);
_size = 0;
return true;
}
}
}

View File

@@ -0,0 +1,99 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using SafeWinHttpHandle = Interop.WinHttp.SafeWinHttpHandle;
namespace System.Net.Http
{
internal static class WinHttpCookieContainerAdapter
{
private const string CookieHeaderNameWithColon = "Cookie" + ":";
public static void AddResponseCookiesToContainer(WinHttpRequestState state)
{
HttpRequestMessage request = state.RequestMessage;
SafeWinHttpHandle requestHandle = state.RequestHandle;
CookieContainer cookieContainer = state.Handler.CookieContainer;
Debug.Assert(state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer);
Debug.Assert(cookieContainer != null);
// Get 'Set-Cookie' headers from response.
char[] buffer = null;
uint index = 0;
string cookieHeader;
WinHttpTraceHelper.Trace("WINHTTP_QUERY_SET_COOKIE");
while (WinHttpResponseParser.GetResponseHeader(
requestHandle, Interop.WinHttp.WINHTTP_QUERY_SET_COOKIE, ref buffer, ref index, out cookieHeader))
{
WinHttpTraceHelper.Trace(cookieHeader);
try
{
cookieContainer.SetCookies(request.RequestUri, cookieHeader);
WinHttpTraceHelper.Trace(cookieHeader);
}
catch (CookieException)
{
// We ignore malformed cookies in the response.
WinHttpTraceHelper.Trace("Ignoring invalid cookie: {0}", cookieHeader);
}
}
}
public static void ResetCookieRequestHeaders(WinHttpRequestState state, Uri redirectUri)
{
SafeWinHttpHandle requestHandle = state.RequestHandle;
Debug.Assert(state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer);
// Clear cookies.
if (!Interop.WinHttp.WinHttpAddRequestHeaders(
requestHandle,
CookieHeaderNameWithColon,
(uint)CookieHeaderNameWithColon.Length,
Interop.WinHttp.WINHTTP_ADDREQ_FLAG_REPLACE))
{
int lastError = Marshal.GetLastWin32Error();
if (lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
{
throw WinHttpException.CreateExceptionUsingError(lastError);
}
}
// Re-add cookies. The GetCookieHeader() method will return the correct set of
// cookies based on the redirectUri.
string cookieHeader = GetCookieHeader(redirectUri, state.Handler.CookieContainer);
if (!string.IsNullOrEmpty(cookieHeader))
{
if (!Interop.WinHttp.WinHttpAddRequestHeaders(
requestHandle,
cookieHeader,
(uint)cookieHeader.Length,
Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
{
WinHttpException.ThrowExceptionUsingLastError();
}
}
}
public static string GetCookieHeader(Uri uri, CookieContainer cookies)
{
string cookieHeader = null;
Debug.Assert(cookies != null);
string cookieValues = cookies.GetCookieHeader(uri);
if (!string.IsNullOrEmpty(cookieValues))
{
cookieHeader = CookieHeaderNameWithColon + " " + cookieValues;
}
return cookieHeader;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,396 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using SafeWinHttpHandle = Interop.WinHttp.SafeWinHttpHandle;
namespace System.Net.Http
{
/// <summary>
/// Static class containing the WinHttp global callback and associated routines.
/// </summary>
internal static class WinHttpRequestCallback
{
public static Interop.WinHttp.WINHTTP_STATUS_CALLBACK StaticCallbackDelegate =
new Interop.WinHttp.WINHTTP_STATUS_CALLBACK(WinHttpCallback);
public static void WinHttpCallback(
IntPtr handle,
IntPtr context,
uint internetStatus,
IntPtr statusInformation,
uint statusInformationLength)
{
WinHttpTraceHelper.TraceCallbackStatus("WinHttpCallback", handle, context, internetStatus);
if (Environment.HasShutdownStarted)
{
WinHttpTraceHelper.Trace("WinHttpCallback: Environment.HasShutdownStarted returned True");
return;
}
if (context == IntPtr.Zero)
{
return;
}
WinHttpRequestState state = WinHttpRequestState.FromIntPtr(context);
Debug.Assert(state != null, "WinHttpCallback must have a non-null state object");
RequestCallback(handle, state, internetStatus, statusInformation, statusInformationLength);
}
private static void RequestCallback(
IntPtr handle,
WinHttpRequestState state,
uint internetStatus,
IntPtr statusInformation,
uint statusInformationLength)
{
try
{
switch (internetStatus)
{
case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
OnRequestHandleClosing(state);
return;
case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
OnRequestSendRequestComplete(state);
return;
case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
Debug.Assert(statusInformationLength == Marshal.SizeOf<int>());
int bytesAvailable = Marshal.ReadInt32(statusInformation);
OnRequestDataAvailable(state, bytesAvailable);
return;
case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
OnRequestReadComplete(state, statusInformationLength);
return;
case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
OnRequestWriteComplete(state);
return;
case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
OnRequestReceiveResponseHeadersComplete(state);
return;
case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REDIRECT:
string redirectUriString = Marshal.PtrToStringUni(statusInformation);
var redirectUri = new Uri(redirectUriString);
OnRequestRedirect(state, redirectUri);
return;
case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
OnRequestSendingRequest(state);
return;
case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
Debug.Assert(
statusInformationLength == Marshal.SizeOf<Interop.WinHttp.WINHTTP_ASYNC_RESULT>(),
"RequestCallback: statusInformationLength=" + statusInformationLength +
" must be sizeof(WINHTTP_ASYNC_RESULT)=" + Marshal.SizeOf<Interop.WinHttp.WINHTTP_ASYNC_RESULT>());
var asyncResult = Marshal.PtrToStructure<Interop.WinHttp.WINHTTP_ASYNC_RESULT>(statusInformation);
OnRequestError(state, asyncResult);
return;
default:
return;
}
}
catch (Exception ex)
{
Interop.WinHttp.WinHttpCloseHandle(handle);
state.SavedException = ex;
}
}
private static void OnRequestHandleClosing(WinHttpRequestState state)
{
Debug.Assert(state != null, "OnRequestSendRequestComplete: state is null");
// This is the last notification callback that WinHTTP will send. Therefore, we can
// now explicitly dispose the state object which will free its corresponding GCHandle.
// This will then allow the state object to be garbage collected.
state.Dispose();
}
private static void OnRequestSendRequestComplete(WinHttpRequestState state)
{
Debug.Assert(state != null, "OnRequestSendRequestComplete: state is null");
Debug.Assert(state.LifecycleAwaitable != null, "OnRequestSendRequestComplete: LifecycleAwaitable is null");
state.LifecycleAwaitable.SetResult(1);
}
private static void OnRequestDataAvailable(WinHttpRequestState state, int bytesAvailable)
{
Debug.Assert(state != null, "OnRequestDataAvailable: state is null");
state.LifecycleAwaitable.SetResult(bytesAvailable);
}
private static void OnRequestReadComplete(WinHttpRequestState state, uint bytesRead)
{
Debug.Assert(state != null, "OnRequestReadComplete: state is null");
// If we read to the end of the stream and we're using 'Content-Length' semantics on the response body,
// then verify we read at least the number of bytes required.
if (bytesRead == 0
&& state.ExpectedBytesToRead.HasValue
&& state.CurrentBytesRead < state.ExpectedBytesToRead.Value)
{
state.LifecycleAwaitable.SetException(new IOException(string.Format(
SR.net_http_io_read_incomplete,
state.ExpectedBytesToRead.Value,
state.CurrentBytesRead)));
}
else
{
state.CurrentBytesRead += (long)bytesRead;
state.LifecycleAwaitable.SetResult((int)bytesRead);
}
}
private static void OnRequestWriteComplete(WinHttpRequestState state)
{
Debug.Assert(state != null, "OnRequestWriteComplete: state is null");
Debug.Assert(state.TcsInternalWriteDataToRequestStream != null, "TcsInternalWriteDataToRequestStream is null");
Debug.Assert(!state.TcsInternalWriteDataToRequestStream.Task.IsCompleted, "TcsInternalWriteDataToRequestStream.Task is completed");
state.TcsInternalWriteDataToRequestStream.TrySetResult(true);
}
private static void OnRequestReceiveResponseHeadersComplete(WinHttpRequestState state)
{
Debug.Assert(state != null, "OnRequestReceiveResponseHeadersComplete: state is null");
Debug.Assert(state.LifecycleAwaitable != null, "LifecycleAwaitable is null");
state.LifecycleAwaitable.SetResult(1);
}
private static void OnRequestRedirect(WinHttpRequestState state, Uri redirectUri)
{
Debug.Assert(state != null, "OnRequestRedirect: state is null");
Debug.Assert(redirectUri != null, "OnRequestRedirect: redirectUri is null");
// If we're manually handling cookies, we need to reset them based on the new URI.
if (state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer)
{
// Add any cookies that may have arrived with redirect response.
WinHttpCookieContainerAdapter.AddResponseCookiesToContainer(state);
// Reset cookie request headers based on redirectUri.
WinHttpCookieContainerAdapter.ResetCookieRequestHeaders(state, redirectUri);
}
state.RequestMessage.RequestUri = redirectUri;
// Redirection to a new uri may require a new connection through a potentially different proxy.
// If so, we will need to respond to additional 407 proxy auth demands and re-attach any
// proxy credentials. The ProcessResponse() method looks at the state.LastStatusCode
// before attaching proxy credentials and marking the HTTP request to be re-submitted.
// So we need to reset the LastStatusCode remembered. Otherwise, it will see additional 407
// responses as an indication that proxy auth failed and won't retry the HTTP request.
if (state.LastStatusCode == HttpStatusCode.ProxyAuthenticationRequired)
{
state.LastStatusCode = 0;
}
// For security reasons, we drop the server credential if it is a
// NetworkCredential. But we allow credentials in a CredentialCache
// since they are specifically tied to URI's.
if (!(state.ServerCredentials is CredentialCache))
{
state.ServerCredentials = null;
}
}
private static void OnRequestSendingRequest(WinHttpRequestState state)
{
Debug.Assert(state != null, "OnRequestSendingRequest: state is null");
Debug.Assert(state.RequestHandle != null, "OnRequestSendingRequest: state.RequestHandle is null");
if (state.RequestMessage.RequestUri.Scheme != UriScheme.Https)
{
// Not SSL/TLS.
return;
}
// Grab the channel binding token (CBT) information from the request handle and put it into
// the TransportContext object.
state.TransportContext.SetChannelBinding(state.RequestHandle);
if (state.ServerCertificateValidationCallback != null)
{
IntPtr certHandle = IntPtr.Zero;
uint certHandleSize = (uint)IntPtr.Size;
if (!Interop.WinHttp.WinHttpQueryOption(
state.RequestHandle,
Interop.WinHttp.WINHTTP_OPTION_SERVER_CERT_CONTEXT,
ref certHandle,
ref certHandleSize))
{
int lastError = Marshal.GetLastWin32Error();
WinHttpTraceHelper.Trace(
"OnRequestSendingRequest: Error getting WINHTTP_OPTION_SERVER_CERT_CONTEXT, {0}",
lastError);
if (lastError == Interop.WinHttp.ERROR_WINHTTP_INCORRECT_HANDLE_STATE)
{
// Not yet an SSL/TLS connection. This occurs while connecting thru a proxy where the
// CONNECT verb hasn't yet been processed due to the proxy requiring authentication.
// We need to ignore this notification. Another notification will be sent once the final
// connection thru the proxy is completed.
return;
}
throw WinHttpException.CreateExceptionUsingError(lastError);
}
// Create a managed wrapper around the certificate handle. Since this results in duplicating
// the handle, we will close the original handle after creating the wrapper.
var serverCertificate = new X509Certificate2(certHandle);
Interop.Crypt32.CertFreeCertificateContext(certHandle);
X509Chain chain = null;
SslPolicyErrors sslPolicyErrors;
try
{
WinHttpCertificateHelper.BuildChain(
serverCertificate,
state.RequestMessage.RequestUri.Host,
state.CheckCertificateRevocationList,
out chain,
out sslPolicyErrors);
bool result = state.ServerCertificateValidationCallback(
state.RequestMessage,
serverCertificate,
chain,
sslPolicyErrors);
if (!result)
{
throw WinHttpException.CreateExceptionUsingError(
(int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE);
}
}
finally
{
if (chain != null)
{
chain.Dispose();
}
serverCertificate.Dispose();
}
}
}
private static void OnRequestError(WinHttpRequestState state, Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult)
{
WinHttpTraceHelper.TraceAsyncError("OnRequestError", asyncResult);
Debug.Assert(state != null, "OnRequestError: state is null");
Exception innerException = WinHttpException.CreateExceptionUsingError((int)asyncResult.dwError);
switch ((uint)asyncResult.dwResult.ToInt32())
{
case Interop.WinHttp.API_SEND_REQUEST:
state.LifecycleAwaitable.SetException(innerException);
break;
case Interop.WinHttp.API_RECEIVE_RESPONSE:
if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_RESEND_REQUEST)
{
state.RetryRequest = true;
state.LifecycleAwaitable.SetResult(0);
}
else if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED)
{
// WinHttp will automatically drop any client SSL certificates that we
// have pre-set into the request handle including the NULL certificate
// (which means we have no certs to send). For security reasons, we don't
// allow the certificate to be re-applied. But we need to tell WinHttp
// explicitly that we don't have any certificate to send.
Debug.Assert(state.RequestHandle != null, "OnRequestError: state.RequestHandle is null");
WinHttpHandler.SetNoClientCertificate(state.RequestHandle);
state.RetryRequest = true;
state.LifecycleAwaitable.SetResult(0);
}
else if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED)
{
state.LifecycleAwaitable.SetCanceled(state.CancellationToken);
}
else
{
state.LifecycleAwaitable.SetException(innerException);
}
break;
case Interop.WinHttp.API_QUERY_DATA_AVAILABLE:
if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED)
{
// TODO: Issue #2165. We need to pass in the cancellation token from the
// user's ReadAsync() call into the TrySetCanceled().
Debug.WriteLine("RequestCallback: QUERY_DATA_AVAILABLE - ERROR_WINHTTP_OPERATION_CANCELLED");
state.LifecycleAwaitable.SetCanceled();
}
else
{
state.LifecycleAwaitable.SetException(
new IOException(SR.net_http_io_read, innerException));
}
break;
case Interop.WinHttp.API_READ_DATA:
if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED)
{
// TODO: Issue #2165. We need to pass in the cancellation token from the
// user's ReadAsync() call into the TrySetCanceled().
Debug.WriteLine("RequestCallback: API_READ_DATA - ERROR_WINHTTP_OPERATION_CANCELLED");
state.LifecycleAwaitable.SetCanceled();
}
else
{
state.LifecycleAwaitable.SetException(new IOException(SR.net_http_io_read, innerException));
}
break;
case Interop.WinHttp.API_WRITE_DATA:
if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED)
{
// TODO: Issue #2165. We need to pass in the cancellation token from the
// user's WriteAsync() call into the TrySetCanceled().
Debug.WriteLine("RequestCallback: API_WRITE_DATA - ERROR_WINHTTP_OPERATION_CANCELLED");
state.TcsInternalWriteDataToRequestStream.TrySetCanceled();
}
else
{
state.TcsInternalWriteDataToRequestStream.TrySetException(
new IOException(SR.net_http_io_write, innerException));
}
break;
default:
Debug.Fail(
"OnRequestError: Result (" + asyncResult.dwResult + ") is not expected.",
"Error code: " + asyncResult.dwError + " (" + innerException.Message + ")");
break;
}
}
}
}

View File

@@ -0,0 +1,229 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using SafeWinHttpHandle = Interop.WinHttp.SafeWinHttpHandle;
namespace System.Net.Http
{
internal sealed class WinHttpRequestState : IDisposable
{
#if DEBUG
private static int s_dbg_allocated = 0;
private static int s_dbg_pin = 0;
private static int s_dbg_clearSendRequestState = 0;
private static int s_dbg_callDispose = 0;
private static int s_dbg_operationHandleFree = 0;
private IntPtr s_dbg_requestHandle;
#endif
// A GCHandle for this operation object.
// This is owned by the callback and will be deallocated when the sessionHandle has been closed.
private GCHandle _operationHandle;
private WinHttpTransportContext _transportContext;
private volatile bool _disposed = false; // To detect redundant calls.
public WinHttpRequestState()
{
#if DEBUG
Interlocked.Increment(ref s_dbg_allocated);
#endif
}
public void Pin()
{
if (!_operationHandle.IsAllocated)
{
#if DEBUG
Interlocked.Increment(ref s_dbg_pin);
#endif
_operationHandle = GCHandle.Alloc(this);
}
}
public static WinHttpRequestState FromIntPtr(IntPtr gcHandle)
{
GCHandle stateHandle = GCHandle.FromIntPtr(gcHandle);
return (WinHttpRequestState)stateHandle.Target;
}
public IntPtr ToIntPtr()
{
return GCHandle.ToIntPtr(_operationHandle);
}
// TODO (Issue 2506): The current locking mechanism doesn't allow any two WinHttp functions executing at
// the same time for the same handle. Enhance locking to prevent only WinHttpCloseHandle being called
// during other API execution. E.g. using a Reader/Writer model or, even better, Interlocked functions.
// The lock object must be used during the execution of any WinHttp function to ensure no race conditions with
// calling WinHttpCloseHandle.
public object Lock => this;
public void ClearSendRequestState()
{
#if DEBUG
Interlocked.Increment(ref s_dbg_clearSendRequestState);
#endif
// Since WinHttpRequestState has a self-referenced strong GCHandle, we
// need to clear out object references to break cycles and prevent leaks.
Tcs = null;
TcsInternalWriteDataToRequestStream = null;
CancellationToken = default(CancellationToken);
RequestMessage = null;
Handler = null;
ServerCertificateValidationCallback = null;
TransportContext = null;
Proxy = null;
ServerCredentials = null;
DefaultProxyCredentials = null;
if (RequestHandle != null)
{
RequestHandle.Dispose();
RequestHandle = null;
}
}
public TaskCompletionSource<HttpResponseMessage> Tcs { get; set; }
public CancellationToken CancellationToken { get; set; }
public HttpRequestMessage RequestMessage { get; set; }
public WinHttpHandler Handler { get; set; }
SafeWinHttpHandle _requestHandle;
public SafeWinHttpHandle RequestHandle
{
get
{
return _requestHandle;
}
set
{
#if DEBUG
if (value != null)
{
s_dbg_requestHandle = value.DangerousGetHandle();
}
#endif
_requestHandle = value;
}
}
public Exception SavedException { get; set; }
public bool CheckCertificateRevocationList { get; set; }
public Func<
HttpRequestMessage,
X509Certificate2,
X509Chain,
SslPolicyErrors,
bool> ServerCertificateValidationCallback { get; set; }
public WinHttpTransportContext TransportContext
{
get { return _transportContext ?? (_transportContext = new WinHttpTransportContext()); }
set { _transportContext = value; }
}
public WindowsProxyUsePolicy WindowsProxyUsePolicy { get; set; }
public IWebProxy Proxy { get; set; }
public ICredentials ServerCredentials { get; set; }
public ICredentials DefaultProxyCredentials { get; set; }
public bool PreAuthenticate { get; set; }
public HttpStatusCode LastStatusCode { get; set; }
public bool RetryRequest { get; set; }
public RendezvousAwaitable<int> LifecycleAwaitable { get; set; } = new RendezvousAwaitable<int>();
public TaskCompletionSource<bool> TcsInternalWriteDataToRequestStream { get; set; }
public bool AsyncReadInProgress { get; set; }
// WinHttpResponseStream state.
public long? ExpectedBytesToRead { get; set; }
public long CurrentBytesRead { get; set; }
// TODO (Issue 2505): temporary pinned buffer caches of 1 item. Will be replaced by PinnableBufferCache.
private GCHandle _cachedReceivePinnedBuffer;
public void PinReceiveBuffer(byte[] buffer)
{
if (!_cachedReceivePinnedBuffer.IsAllocated || _cachedReceivePinnedBuffer.Target != buffer)
{
if (_cachedReceivePinnedBuffer.IsAllocated)
{
_cachedReceivePinnedBuffer.Free();
}
_cachedReceivePinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
}
}
#region IDisposable Members
private void Dispose(bool disposing)
{
#if DEBUG
Interlocked.Increment(ref s_dbg_callDispose);
#endif
if (WinHttpTraceHelper.IsTraceEnabled())
{
WinHttpTraceHelper.Trace(
"WinHttpRequestState.Dispose, GCHandle=0x{0:X}, disposed={1}, disposing={2}",
ToIntPtr(),
_disposed,
disposing);
}
// Since there is no finalizer and this class is sealed, the disposing parameter should be TRUE.
Debug.Assert(disposing, "WinHttpRequestState.Dispose() should have disposing=TRUE");
if (_disposed)
{
return;
}
_disposed = true;
if (_operationHandle.IsAllocated)
{
// This method only gets called when the WinHTTP request handle is fully closed and thus all
// async operations are done. So, it is safe at this point to unpin the buffers and release
// the strong GCHandle for this object.
if (_cachedReceivePinnedBuffer.IsAllocated)
{
_cachedReceivePinnedBuffer.Free();
_cachedReceivePinnedBuffer = default(GCHandle);
}
#if DEBUG
Interlocked.Increment(ref s_dbg_operationHandleFree);
#endif
_operationHandle.Free();
_operationHandle = default(GCHandle);
}
}
public void Dispose()
{
// No need to suppress finalization since the finalizer is not overridden and the class is sealed.
Dispose(true);
}
#endregion
}
}

View File

@@ -0,0 +1,254 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using SafeWinHttpHandle = Interop.WinHttp.SafeWinHttpHandle;
namespace System.Net.Http
{
internal class WinHttpRequestStream : Stream
{
private static byte[] s_crLfTerminator = new byte[] { 0x0d, 0x0a }; // "\r\n"
private static byte[] s_endChunk = new byte[] { 0x30, 0x0d, 0x0a, 0x0d, 0x0a }; // "0\r\n\r\n"
private volatile bool _disposed;
private WinHttpRequestState _state;
private bool _chunkedMode;
// TODO (Issue 2505): temporary pinned buffer caches of 1 item. Will be replaced by PinnableBufferCache.
private GCHandle _cachedSendPinnedBuffer;
internal WinHttpRequestStream(WinHttpRequestState state, bool chunkedMode)
{
_state = state;
_chunkedMode = chunkedMode;
}
public override bool CanRead
{
get
{
return false;
}
}
public override bool CanSeek
{
get
{
return false;
}
}
public override bool CanWrite
{
get
{
return !_disposed;
}
}
public override long Length
{
get
{
CheckDisposed();
throw new NotSupportedException();
}
}
public override long Position
{
get
{
CheckDisposed();
throw new NotSupportedException();
}
set
{
CheckDisposed();
throw new NotSupportedException();
}
}
public override void Flush()
{
// Nothing to do.
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
return cancellationToken.IsCancellationRequested ?
Task.FromCanceled(cancellationToken) :
Task.CompletedTask;
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
if (offset < 0)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
if (count > buffer.Length - offset)
{
throw new ArgumentException(SR.net_http_buffer_insufficient_length, nameof(buffer));
}
if (token.IsCancellationRequested)
{
var tcs = new TaskCompletionSource<int>();
tcs.TrySetCanceled(token);
return tcs.Task;
}
CheckDisposed();
if (_state.TcsInternalWriteDataToRequestStream != null &&
!_state.TcsInternalWriteDataToRequestStream.Task.IsCompleted)
{
throw new InvalidOperationException(SR.net_http_no_concurrent_io_allowed);
}
return InternalWriteAsync(buffer, offset, count, token);
}
public override void Write(byte[] buffer, int offset, int count)
{
WriteAsync(buffer, offset, count, CancellationToken.None).GetAwaiter().GetResult();
}
public override long Seek(long offset, SeekOrigin origin)
{
CheckDisposed();
throw new NotSupportedException();
}
public override void SetLength(long value)
{
CheckDisposed();
throw new NotSupportedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
CheckDisposed();
throw new NotSupportedException();
}
internal async Task EndUploadAsync(CancellationToken token)
{
if (_chunkedMode)
{
await InternalWriteDataAsync(s_endChunk, 0, s_endChunk.Length, token).ConfigureAwait(false);
}
}
protected override void Dispose(bool disposing)
{
if (!_disposed)
{
_disposed = true;
// TODO (Issue 2508): Pinned buffers must be released in the callback, when it is guaranteed no further
// operations will be made to the send/receive buffers.
if (_cachedSendPinnedBuffer.IsAllocated)
{
_cachedSendPinnedBuffer.Free();
}
}
base.Dispose(disposing);
}
private void CheckDisposed()
{
if (_disposed)
{
throw new ObjectDisposedException(this.GetType().FullName);
}
}
private Task InternalWriteAsync(byte[] buffer, int offset, int count, CancellationToken token)
{
return _chunkedMode ?
InternalWriteChunkedModeAsync(buffer, offset, count, token) :
InternalWriteDataAsync(buffer, offset, count, token);
}
private async Task InternalWriteChunkedModeAsync(byte[] buffer, int offset, int count, CancellationToken token)
{
// WinHTTP does not fully support chunked uploads. It simply allows one to omit the 'Content-Length' header
// and instead use the 'Transfer-Encoding: chunked' header. The caller is still required to encode the
// request body according to chunking rules.
Debug.Assert(_chunkedMode);
string chunkSizeString = String.Format("{0:x}\r\n", count);
byte[] chunkSize = Encoding.UTF8.GetBytes(chunkSizeString);
await InternalWriteDataAsync(chunkSize, 0, chunkSize.Length, token).ConfigureAwait(false);
await InternalWriteDataAsync(buffer, offset, count, token).ConfigureAwait(false);
await InternalWriteDataAsync(s_crLfTerminator, 0, s_crLfTerminator.Length, token).ConfigureAwait(false);
}
private Task<bool> InternalWriteDataAsync(byte[] buffer, int offset, int count, CancellationToken token)
{
Debug.Assert(count >= 0);
if (count == 0)
{
return Task.FromResult<bool>(true);
}
// TODO (Issue 2505): replace with PinnableBufferCache.
if (!_cachedSendPinnedBuffer.IsAllocated || _cachedSendPinnedBuffer.Target != buffer)
{
if (_cachedSendPinnedBuffer.IsAllocated)
{
_cachedSendPinnedBuffer.Free();
}
_cachedSendPinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
}
_state.TcsInternalWriteDataToRequestStream =
new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
lock (_state.Lock)
{
if (!Interop.WinHttp.WinHttpWriteData(
_state.RequestHandle,
Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset),
(uint)count,
IntPtr.Zero))
{
_state.TcsInternalWriteDataToRequestStream.TrySetException(
new IOException(SR.net_http_io_write, WinHttpException.CreateExceptionUsingLastError().InitializeStackTrace()));
}
}
// TODO: Issue #2165. Register callback on cancellation token to cancel WinHTTP operation.
return _state.TcsInternalWriteDataToRequestStream.Task;
}
}
}

View File

@@ -0,0 +1,161 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
namespace System.Net.Http
{
/// <summary>
/// Used to read header lines of an HTTP response, where each line is separated by "\r\n".
/// </summary>
internal struct WinHttpResponseHeaderReader
{
private const string Gzip = "gzip";
private const string Deflate = "deflate";
private readonly char[] _buffer;
private readonly int _length;
private int _position;
public WinHttpResponseHeaderReader(char[] buffer, int startIndex, int length)
{
CharArrayHelpers.DebugAssertArrayInputs(buffer, startIndex, length);
_buffer = buffer;
_position = startIndex;
_length = length;
}
/// <summary>
/// Reads a header line.
/// Empty header lines are skipped, as are malformed header lines that are missing a colon character.
/// </summary>
/// <returns>true if the next header was read successfully, or false if all characters have been read.</returns>
public bool ReadHeader(out string name, out string value)
{
int startIndex;
int length;
while (ReadLine(out startIndex, out length))
{
// Skip empty lines.
if (length == 0)
{
continue;
}
int colonIndex = Array.IndexOf(_buffer, ':', startIndex, length);
// Skip malformed header lines that are missing the colon character.
if (colonIndex == -1)
{
continue;
}
int nameLength = colonIndex - startIndex;
// If it's a known header name, use the known name instead of allocating a new string.
if (!HttpKnownHeaderNames.TryGetHeaderName(_buffer, startIndex, nameLength, out name))
{
name = new string(_buffer, startIndex, nameLength);
}
// Normalize header value by trimming white space.
int valueStartIndex = colonIndex + 1;
int valueLength = startIndex + length - colonIndex - 1;
CharArrayHelpers.Trim(_buffer, ref valueStartIndex, ref valueLength);
value = GetHeaderValue(name, _buffer, valueStartIndex, valueLength);
return true;
}
name = null;
value = null;
return false;
}
/// <summary>
/// Reads lines separated by "\r\n".
/// </summary>
/// <returns>true if the next line was read successfully, or false if all characters have been read.</returns>
public bool ReadLine()
{
int startIndex;
int length;
return ReadLine(out startIndex, out length);
}
/// <summary>
/// Reads lines separated by "\r\n".
/// </summary>
/// <param name="startIndex">The start of the line segment.</param>
/// <param name="length">The length of the line segment.</param>
/// <returns>true if the next line was read successfully, or false if all characters have been read.</returns>
private bool ReadLine(out int startIndex, out int length)
{
Debug.Assert(_buffer != null);
int i = _position;
while (i < _length)
{
char ch = _buffer[i];
if (ch == '\r')
{
int next = i + 1;
if (next < _length && _buffer[next] == '\n')
{
startIndex = _position;
length = i - _position;
_position = i + 2;
return true;
}
}
i++;
}
if (i > _position)
{
startIndex = _position;
length = i - _position;
_position = i;
return true;
}
startIndex = 0;
length = 0;
return false;
}
private static string GetHeaderValue(string name, char[] array, int startIndex, int length)
{
Debug.Assert(name != null);
CharArrayHelpers.DebugAssertArrayInputs(array, startIndex, length);
if (length == 0)
{
return string.Empty;
}
// If it's a known header value, use the known value instead of allocating a new string.
// Do a really quick reference equals check to see if name is the same object as
// HttpKnownHeaderNames.ContentEncoding, in which case the value is very likely to
// be either "gzip" or "deflate".
if (object.ReferenceEquals(name, HttpKnownHeaderNames.ContentEncoding))
{
if (CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase(Gzip, array, startIndex, length))
{
return Gzip;
}
else if (CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase(Deflate, array, startIndex, length))
{
return Deflate;
}
}
return new string(array, startIndex, length);
}
}
}

Some files were not shown because too many files have changed in this diff Show More