runtime: [release/2.1] Expect100Continue with Windows auth and request body > 1024 bytes fails
In this code: https://github.com/dotnet/corefx/blob/7ee84596d92e178bce54c986df31ccc52479e772/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs#L534-L549
If the Expect100Continue header is set, and the response code is >= 300 and there’s a request body with known length greater than 1024 bytes, if the request body hasn’t begun to be sent yet, it sets _connectionClose
to true
. When using authentication, the challenge response comes with an HTTP status code of 401. As (401 >= 300)
evaluates to true, whenever using authentication with request body size > 1024 bytes, _connectionClose
will be set to true
. In this code: https://github.com/dotnet/corefx/blob/7ee84596d92e178bce54c986df31ccc52479e772/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs#L68-L75
If there was a valid authentication challenge and a response is available to send, a call is made to HttpConnection.DrainResponseAsync
. In that method: https://github.com/dotnet/corefx/blob/7ee84596d92e178bce54c986df31ccc52479e772/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs#L1528-L1531
If _connectionClose
is true, it throws and aborts the request.
This is breaking Windows authentication for WCF with requests which are larger than 1024.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 2
- Comments: 30 (27 by maintainers)
Commits related to this issue
- Don't close connection for responses to NT auth using Expect: 100-continue Port fix from PR #38744 (.NET Core 3.0) to release/2.1 LTS branch. Fixes #30760 — committed to davidsh/corefx by davidsh 5 years ago
- Don't close connection for responses to NT auth using 100continue Port fix from PR #38744 (.NET Core 3.0) to release/2.1 LTS branch. Fixes #30760 — committed to davidsh/corefx by davidsh 5 years ago
- Don't close connection for responses to NT auth using 100continue (#39341) Port fix from PR #38744 (.NET Core 3.0) to release/2.1 LTS branch. Fixes #30760 — committed to dotnet/corefx by davidsh 5 years ago
I’m a customer, new to this issue. I updated my application dependencies (core 2.2 and wcf 4.5.3) today and promptly crashed my application. I’m here to vote for prioritization. Any thoughts on a timeline to fix? Thanks.
Customer here, I would love to see this issue resolved. When starting a new project we shouldn’t have to check if every workaround is still required. This issue is still very much there and open for quite sometime now and needs to be resolved 😃
Fix for release/2.1 checked in with PR dotnet/corefx#39341
Fixed in master for .NET Core 3.0 with PR dotnet/corefx#38744
Re-opening for release/2.1 and release/2.2 consideration.
Disabling 100-Continue does avoid the issue but that’s not something a developer can do very easily. When 100-Continue support was added to HttpClient, I modified WCF to match the behavior we have on .NET Framework. We don’t have any API to change that behavior as on .NET Framework you can do this using ServicePointManager so WCF doesn’t have any API’s exposed to modify this behavior.
This is still blocking partner as our customers are continuing to have problems with this. Look at the issue in WCF where we are tracking this (dotnet/wcf#2923) to see how many people have problem.
On .NET Framework it does send the request twice on the authentication handshake so that behavior is acceptable to exist for fixing in 2.1+ (as 2.1 is a LTS so needs the functional break fixed there). I see my suggestion of the added optimization to remove the second send as being an improvement beyond what .NET Framework does so that’s fine to be in 3.0. I’m not looking to retroactively add features 😄 .
@geoffkizer, the current solution means that you can’t use use NTLM authentication with the Expect header. It simply can’t work as it abandons the request and throws an HttpRequestException at the caller. I ran some experiments and recorded what HttpWebRequest does on the .Net Framework so I’ll give a quick overview here.
Expect: 100-continue
headerWWW-Authenticate: NTLM
header (no blob)Content-Length: 0
header (no expect header because no request body).Expect: 100-continue
headerThis is the minimum that should be done. I believe that this can be optimized further. I suspect in step 3 the client could abandon the socket as there’s no state information about the authentication that has been transmitted yet. This is the general idea that the current code attempts to do. But the current implementation then throws an HttpRequestException at the caller and there’s no way to complete the request. Instead it should close the connection, not throw and create a new connection instead. Although the current limit of 1024 is too small as that is less than a single ethernet frame payload. Ideally the RTT would be queried from the OS and a heuristic used to work out which approach would be quicker but the System.Net.Socket abstraction is too far removed from the OS to query this information.
Additionally, when PreAuthenticate has been enabled and a credentials cache is used which only contains NTLM credentials, the first request can probably be skipped and can jump straight to step 4 as the server doesn’t provide any challenge data in the initial authentication challenge. That would avoid sending the request body completely until after the authentication is completed. There is a risk that some servers could initialize some state when replying with the empty NTLM challenge, but that’s easily tested and could be turned off by not using setting PreAuthenticate to true if some implementation failed with this optimization.
@mconnew, I’m not entirely sure what you want us to do in this scenario. When we get an early response with Expect: 100-continue, we either need to (a) finish sending the request body, so we can keep the connection alive, or (b) close the connection and stop sending the request body.
Removing label until this is ready for big shiproom.