Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Add support and tests for HTTP 308 Permanent Redirect#30398

Merged
rmkerr merged 5 commits intodotnet:masterfrom
rmkerr:http_308redirect_followed
Jul 10, 2018
Merged

Add support and tests for HTTP 308 Permanent Redirect#30398
rmkerr merged 5 commits intodotnet:masterfrom
rmkerr:http_308redirect_followed

Conversation

@rmkerr
Copy link
Contributor

@rmkerr rmkerr commented Jun 14, 2018

The HttpStatusCode enum was only recently updated to include HTTP status code 308, via PR #26727. With the platform handlers we support whatever cURL and WinHttp support, so 308 works even though the status code did not exist in the enum until recently. However in SocketsHttpHandler we only support the redirects that were in the enum when that code was written, which at the time did not include 308.

This PR adds support for 308 redirects to SocketsHttpHandler, and enables 308 redirects in our tests. It is not well documented when WinHttp and cURL added support for HTTP 308, so it is possible these tests will fail on older operating systems. If so I believe we should still take the change, but should add documentation on our support on older systems.

Fixes: #30389

@rmkerr rmkerr self-assigned this Jun 14, 2018
@rmkerr rmkerr requested review from a team and stephentoub June 14, 2018 17:50
@rmkerr
Copy link
Contributor Author

rmkerr commented Jun 14, 2018

@dotnet-bot test Outerloop Windows x64 Debug Build
@dotnet-bot test Outerloop Linux x64 Debug Build
@dotnet-bot test Outerloop NETFX x86 Debug Build
@dotnet-bot test Outerloop UWP CoreCLR x64 Debug Build


new object[] { 308, "GET", "GET" },
new object[] { 308, "POST", "POST" },
new object[] { 308, "HEAD", "HEAD" },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll be interested to see if this passes on NetfxHandler and CurlHandler.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And UapHandler, since:

if (response.StatusCode != HttpStatusCode.MultipleChoices &&
response.StatusCode != HttpStatusCode.MovedPermanently &&
response.StatusCode != HttpStatusCode.Redirect &&
response.StatusCode != HttpStatusCode.RedirectMethod &&
response.StatusCode != HttpStatusCode.RedirectKeepVerb)
{
break;
}

Copy link
Contributor Author

@rmkerr rmkerr Jun 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I think it's possible that it will also fail in WinHttpHandler on win7. If so though I think we should keep the change and disable the test on those platforms. I'll extend the fix to UAP though, since we can control the behavior there.

case HttpStatusCode.SeeOther:
case HttpStatusCode.TemporaryRedirect:
case HttpStatusCode.MultipleChoices:
case HttpStatusCode.PermanentRedirect:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about

private bool IsLastResponse(HttpWebRequest request, HttpStatusCode statusCode)
{
if (request.AllowAutoRedirect)
{
if (statusCode == HttpStatusCode.Ambiguous || // 300
statusCode == HttpStatusCode.Moved || // 301
statusCode == HttpStatusCode.Redirect || // 302
statusCode == HttpStatusCode.RedirectMethod || // 303
statusCode == HttpStatusCode.RedirectKeepVerb) // 307
{
return s_autoRedirectsAccessor(request) >= request.MaximumAutomaticRedirections;
}
}
return true;
}
?
cc: @vancem

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will probably need to be updated too. It looks like the test for MaxAutomaticRedirections only uses 302, so I'll add an additional test for that case.

public async Task GetAsync_MaxAutomaticRedirectionsNServerHops_ThrowsIfTooMany(int maxHops, int hops)
{
if (IsWinHttpHandler && !PlatformDetection.IsWindows10Version1703OrGreater)
{
// Skip this test if using WinHttpHandler but on a release prior to Windows 10 Creators Update.
_output.WriteLine("Skipping test due to Windows 10 version prior to Version 1703.");
return;
}
else if (PlatformDetection.IsFullFramework)
{
// Skip this test if running on .NET Framework. Exceeding max redirections will not throw
// exception. Instead, it simply returns the 3xx response.
_output.WriteLine("Skipping test on .NET Framework due to behavior difference.");
return;
}
HttpClientHandler handler = CreateHttpClientHandler();
handler.MaxAutomaticRedirections = maxHops;
using (var client = new HttpClient(handler))
{
Task<HttpResponseMessage> t = client.GetAsync(Configuration.Http.RedirectUriForDestinationUri(
secure: false,
statusCode: 302,
destinationUri: Configuration.Http.RemoteEchoServer,
hops: hops));
if (hops <= maxHops)
{
using (HttpResponseMessage response = await t)
{
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(Configuration.Http.RemoteEchoServer, response.RequestMessage.RequestUri);
}
}
else
{
if (UseSocketsHttpHandler)
{
using (HttpResponseMessage response = await t)
{
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
}
}
else
{
await Assert.ThrowsAsync<HttpRequestException>(() => t);
}
}
}
}

Copy link
Contributor Author

@rmkerr rmkerr Jun 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stephentoub I added the new redirect code here, but it is causing build failures on netfx. I can use the integer 308 instead, or do you think I should take a different approach?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using "308" might still fail on NETFX since it might not be supported. You can try though using the integer. But if the test fails, then you'll need to skip that test case on NETFX.

Copy link
Contributor

@davidsh davidsh Jun 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidsh
Copy link
Contributor

davidsh commented Jun 14, 2018

@dotnet-bot Test Outerloop OSX x64 Debug Build

@rmkerr
Copy link
Contributor Author

rmkerr commented Jun 14, 2018

It looks like the redirect tests that are using the remote echo server are failing with a 500 error:

Message :
Assert.Equal() Failure
Expected: OK
Actual:   InternalServerError
Stack Trace :
   at System.Net.Http.Functional.Tests.HttpClientHandlerTest.GetAsync_AllowAutoRedirectTrue_RedirectFromHttpToHttp_StatusCodeOK(Int32 statusCode) in D:\j\workspace\windows-TGrou---db113413\src\System.Net.Http\tests\FunctionalTests\HttpClientHandlerTest.cs:line 979
--- End of stack trace from previous location where exception was thrown ---

I'm going to take a look at the remote echo server code to see if it is causing these failures.

}

[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "Not currently supported on UAP")]
[OuterLoop] // TODO: Issue #11345
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're trying to remove the obsoleted TODO 11345.

Instead this should be "[Outerloop("Use external server")]"

@davidsh
Copy link
Contributor

davidsh commented Jun 14, 2018

The remote echo server will need to updated:

                    if (statusCode < 300 || statusCode > 307)
                    {
                        context.Response.StatusCode = 500;
                        context.Response.StatusDescription = "Invalid redirect statuscode: " + statusCodeString;
                        return;
                    }

I will handle that.

And the source code for it in CoreFx is not actually up to date with the real deployed code. That is done from a different repo.

@rmkerr
Copy link
Contributor Author

rmkerr commented Jun 14, 2018

@davidsh Thanks for taking care of it. For future reference, where is that repo?

@davidsh
Copy link
Contributor

davidsh commented Jun 14, 2018

@davidsh Thanks for taking care of it. For future reference, where is that repo?

Let's discuss offline in team meeting. To update the service, it's more complex than just knowing where the repo is.

@davidsh
Copy link
Contributor

davidsh commented Jun 14, 2018

Updated corefx-net.cloudapp.net/redirect.ashx endpoint to support 308 status code:
image

@rmkerr
Copy link
Contributor Author

rmkerr commented Jun 14, 2018

Thanks! I'll rerun the tests.

@dotnet-bot test Outerloop Windows x64 Debug Build
@dotnet-bot test Outerloop Linux x64 Debug Build
@dotnet-bot test Outerloop NETFX x86 Debug Build
@dotnet-bot test Outerloop UWP CoreCLR x64 Debug Build
@dotnet-bot test Outerloop OSX x64 Debug Build

@rmkerr
Copy link
Contributor Author

rmkerr commented Jun 15, 2018

I think the test failures here are a combination of three issues:

  1. It looks like 308 redirects are not supported in WinHttp versions before Windows 10. This causes platform handler failures on win7 and win8. I'll just disable these on the PlatformHandler for anything older than win10.
  2. The remote echo server only uses the specified redirect status code on the first redirect. Subsequent redirects drop the status code, and always use 302:
    else
    {
    context.Response.Headers.Add(
    "Location",
    string.Format("/Redirect.ashx?uri={0}&hops={1}",
    redirectUri,
    hops - 1));
    }
    context.Response.StatusCode = statusCode;
    I'm not sure what the more realistic behavior is, but it does break the test I added. I can adjust the test if this is the desired behavior. @davidsh do you have any thoughts here?
  3. Failures on netfx due to the usage of the new status code that does not exist yet in .NET Framework. I'll adjust this to use the integer constant 308 instead, as seems to be standard for those tests.

@davidsh
Copy link
Contributor

davidsh commented Jun 15, 2018

I'm not sure what the more realistic behavior is, but it does break the test I added. I can adjust the test if this is the desired behavior. @davidsh do you have any thoughts here?

Having multiple hops was only about testing the "limits" we set for MaxAutomaticRedirection in the handlers. It wasn't about whether it was "realistic" behavior of clients, i.e. browsers.

I would rather we don't touch the current behavior of the redirect.ashx endpoint for this. And we should fix/remove the tests as needed. I don't think it is necessary to have multi-hop tests for all redirect status codes.

@rmkerr
Copy link
Contributor Author

rmkerr commented Jun 15, 2018

@davidsh Okay, in that case I'll just remove that test. We have a multi-hop test for 302 and single hop tests for all other status codes, so that should cover it.

Copy link
Contributor

@davidsh davidsh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. You'll also want to re-run all Outerloop tests again since you've revised the PR.

@rmkerr
Copy link
Contributor Author

rmkerr commented Jun 19, 2018

@dotnet-bot test Outerloop Windows x64 Debug Build
@dotnet-bot test Outerloop Linux x64 Debug Build
@dotnet-bot test Outerloop NETFX x86 Debug Build
@dotnet-bot test Outerloop UWP CoreCLR x64 Debug Build
@dotnet-bot test Outerloop OSX x64 Debug Build

@rmkerr
Copy link
Contributor Author

rmkerr commented Jul 9, 2018

Rerunning the tests since this has been inactive for almost a month. If the tests look good I'll go ahead and merge this.

@dotnet-bot test Outerloop Windows x64 Debug Build
@dotnet-bot test Outerloop Linux x64 Debug Build
@dotnet-bot test Outerloop NETFX x86 Debug Build
@dotnet-bot test Outerloop UWP CoreCLR x64 Debug Build
@dotnet-bot test Outerloop OSX x64 Debug Build

@rmkerr
Copy link
Contributor Author

rmkerr commented Jul 10, 2018

I'm going to go ahead and merge this change. The Linux Outerloop failure was in System.Drawing, and is unrelated. The OSX failure is a known flaky HTTP test that does not use redirection.

@rmkerr rmkerr merged commit 12e41ed into dotnet:master Jul 10, 2018
rmkerr added a commit to rmkerr/corefx that referenced this pull request Jul 10, 2018
This change adds support for 308 redirects to SocketsHttpHandler, and enables 308 redirects in our tests.

Fixes: #30389
rmkerr added a commit that referenced this pull request Jul 10, 2018
This change adds support for 308 redirects to SocketsHttpHandler, and enables 308 redirects in our tests.

Fixes: #30389
@karelz karelz added this to the 3.0 milestone Jul 19, 2018
macrogreg pushed a commit to open-telemetry/opentelemetry-dotnet-instrumentation that referenced this pull request Sep 24, 2020
…30398)

This change adds support for 308 redirects to SocketsHttpHandler, and enables 308 redirects in our tests.

Fixes: dotnet/corefx#30389


Commit migrated from dotnet/corefx@12e41ed
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
…30398)

This change adds support for 308 redirects to SocketsHttpHandler, and enables 308 redirects in our tests.

Fixes: dotnet/corefx#30389


Commit migrated from dotnet/corefx@12e41ed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

bug Product bug (most likely)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants