Here is a test proving that route can be null (I'm using 3.11.0):
import org.junit.Test;
import okhttp3.Authenticator;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;
public class AuthenticatorTest {
@Test
public void routeCanBeNull() throws Exception {
Authenticator authenticator = new Authenticator() {
@Override
public Request authenticate(Route route, Response response) {
if (route == null) {
throw new NullPointerException("route is null");
}
return null;
}
};
OkHttpClient client = new OkHttpClient.Builder()
.authenticator(authenticator)
.build();
Request request = new Request.Builder()
.url("https://httpbin.org/status/401")
.build();
client.newCall(request).execute(); // route is not null
client.newCall(request).execute(); // route is null
}
}
I'm not sure if it is a correct behaviour. If it is actually correct I'll make a PR adding @Nullable to route.
Yep, please submit a PR. I've also hit this using another auth library, in my case also because Interceptor.Chain.connection is null, so an interceptor calling a Authenticator will never have a route.
Related to https://github.com/square/okhttp/issues/3809
I think we _could_ get a route if our internal APIs were a little better organized. The reason the HTTP bin one doesn’t have a route is because the response body is empty and we’ve gotten rid of things by the time we’re ready to authenticate.
My preference on this is to fix RetryAndFollowUpInterceptor, possibly with support from StreamAllocation, so that we have a route when we call into the Authenticator. That feels like a better fix than changing the type to be nullable.
It still makes it awkward if you want to reuse an Authenticator from an Interceptor for premptive auth. Making route non @Nullable means it always need to be a network interceptor. So I still think it's worth making route @Nullable
Good point!
It's less of a good point, because you can't use it prior to sending the first request, but you can use it when implementing a app level interceptor. I hit that this week with a JIRA server returning a 400 when an anonymous query request fails, and I'd like to reuse the authenticator.
@yschimke Is this still open? Can I work on this?
Sorry, the PR closed this out. Let me look for good PR candidates.
Is there already an estimate when this will be included in a new release?
We get this very reliable every second request 😉.
@hardysim in Kotlin you can just replace route: Route with route: Route?.
@technoir42 hmm, it seems to actually not work 😞
My implementation of Authenticator now has set route: Route? but I still get the error.
override fun authenticate(route: Route?, response: Response): Request? { [...] }
I'm not sure why because even if the interface does not mark the parameter as nullable, my implementation does and therefor this error should not exist?!
Logcat continues to show the same error with my class at the top of the stack (which I just set to Route?).
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.e.b.i.b, parameter route
at [my-class].authenticate(Unknown Source:2)
@hardysim you sure you've updated all Authenticator implementations?
Compare the decompiled bytecode with Route and Route?. In the latter case it should contain:
@Nullable
public Request authenticate(@Nullable Route route, @NotNull Response response) {
Intrinsics.checkParameterIsNotNull(response, "response");
Yep, my fault. It's in a library my project uses and I messed up the release / import of the new version.
TL;DR:
it works by setting Route?
@swankjesse @yschimke, Please I would like to know how I can reproduce this bug manually. A project I am working on includes an authenticator in the client set up, and this bug was encountered because of some intermittent failures from the server. I would like to know the kind of server response that could cause this to happen if I don't mark the route as @Nullable
Most helpful comment
@hardysim in Kotlin you can just replace
route: Routewithroute: Route?.