Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ string EncodeUrl (Uri url)
if (redirectState.NewUrl == null)
throw new InvalidOperationException ("Request redirected but no new URI specified");
request.Method = redirectState.Method;
request.RequestUri = redirectState.NewUrl;
} catch (Java.Net.SocketTimeoutException ex) when (JNIEnv.ShouldWrapJavaException (ex)) {
throw new WebException (ex.Message, ex, WebExceptionStatus.Timeout, null);
} catch (Java.Net.UnknownServiceException ex) when (JNIEnv.ShouldWrapJavaException (ex)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public async Task ServerCertificateCustomValidationCallback_ApproveRequest ()
var handler = new AndroidMessageHandler {
ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => {
Assert.NotNull (request, "request");
Assert.AreEqual ("microsoft.com", request.RequestUri.Host);
Assert.AreEqual ("www.microsoft.com", request.RequestUri.Host);
Assert.NotNull (cert, "cert");
Assert.True (cert!.Subject.Contains ("microsoft.com"), $"Unexpected certificate subject {cert!.Subject}");
Assert.True (cert!.Subject.Contains ("www.microsoft.com"), $"Unexpected certificate subject {cert!.Subject}");
Assert.True (cert!.Issuer.Contains ("Microsoft"), $"Unexpected certificate issuer {cert!.Issuer}");
Assert.NotNull (chain, "chain");
Assert.AreEqual (SslPolicyErrors.None, errors);
Expand All @@ -40,7 +40,7 @@ public async Task ServerCertificateCustomValidationCallback_ApproveRequest ()
};

var client = new HttpClient (handler);
await client.GetStringAsync ("https://microsoft.com/");
await client.GetStringAsync ("https://www.microsoft.com/");

Assert.IsTrue (callbackHasBeenCalled, "custom validation callback hasn't been called");
}
Expand All @@ -58,7 +58,7 @@ public async Task ServerCertificateCustomValidationCallback_RejectRequest ()
};
var client = new HttpClient (handler);

await AssertRejectsRemoteCertificate (() => client.GetStringAsync ("https://microsoft.com/"));
await AssertRejectsRemoteCertificate (() => client.GetStringAsync ("https://www.microsoft.com/"));

Assert.IsTrue (callbackHasBeenCalled, "custom validation callback hasn't been called");
}
Expand Down Expand Up @@ -111,6 +111,25 @@ public async Task ServerCertificateCustomValidationCallback_IgnoresCertificateHo
Assert.AreEqual (SslPolicyErrors.RemoteCertificateNameMismatch, reportedErrors & SslPolicyErrors.RemoteCertificateNameMismatch);
}

[Test]
public async Task ServerCertificateCustomValidationCallback_Redirects ()
{
int callbackCounter = 0;

var handler = new AndroidMessageHandler {
ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => {
callbackCounter++;
return errors == SslPolicyErrors.None;
}
};

var client = new HttpClient (handler);
var result = await client.GetAsync ("https://httpbin.org/redirect-to?url=https://www.microsoft.com/");

Assert.AreEqual (2, callbackCounter);
Copy link
Contributor

Choose a reason for hiding this comment

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

@simonrozsival: why is this 2? Are there any docs around how many times ServerCertificateCustomValidationCallback will be invoked, other than "at least once"? Why is the callback being called twice? Is that a bug? Is that likely to change at any point in the future?

Or should it be 2: once for httpbin.org/redirect-to, and once again for www.microsoft.com, and it's called "once per redirect", i.e. if you "nested" redirects with https://httpbin.org/redirect-to?url=https://httpbin.org/redirect-to?url=…, callbackCounter should be the number of times we hit httpbin.org/redirect-to + 1?

Copy link
Member Author

Choose a reason for hiding this comment

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

The callback is called once for every sub-request that's made (the first request + all redirects). In this case, it's called once for httpbin.org/... and once for www.microsoft.com. So callbackCounter should equal to 1 + number of redirects. The SocketsHttpHandler behaves the same way.

Assert.IsTrue (result.IsSuccessStatusCode);
}

private async Task AssertRejectsRemoteCertificate (Func<Task> makeRequest)
{
// there is a difference between the exception that's thrown in the .NET build and the legacy Xamarin
Expand Down