Skip to content

Commit

Permalink
Merge pull request #1006 from nfuller/TransparentGzipBasic
Browse files Browse the repository at this point in the history
Fix transparent gzip for basic auth.
  • Loading branch information
swankjesse committed Jul 30, 2014
2 parents 152b02c + 1a7e803 commit e8fee51
Show file tree
Hide file tree
Showing 7 changed files with 276 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public RecordedResponse assertHandshake() {
* response for the original request.
*/
public RecordedResponse redirectedBy() {
Response redirectedBy = response.redirectedBy();
Response redirectedBy = response.priorResponse();
assertNotNull(redirectedBy);
assertNull(redirectedBy.body());
return new RecordedResponse(redirectedBy.request(), redirectedBy, null, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,43 @@
import java.util.List;

public final class RecordingOkAuthenticator implements OkAuthenticator {
public final List<String> calls = new ArrayList<String>();
public final List<URL> urls = new ArrayList<URL>();
public final List<List<Challenge>> challengesList = new ArrayList<List<Challenge>>();
public final List<Proxy> proxies = new ArrayList<Proxy>();
public final Credential credential;

public RecordingOkAuthenticator(Credential credential) {
this.credential = credential;
}

public URL onlyUrl() {
if (urls.size() != 1) throw new IllegalStateException();
return urls.get(0);
}

public List<Challenge> onlyChallenge() {
if (challengesList.size() != 1) throw new IllegalStateException();
return challengesList.get(0);
}

public Proxy onlyProxy() {
if (proxies.size() != 1) throw new IllegalStateException();
return proxies.get(0);
}

@Override public Credential authenticate(Proxy proxy, URL url, List<Challenge> challenges)
throws IOException {
calls.add("authenticate"
+ " proxy=" + proxy.type()
+ " url=" + url
+ " challenges=" + challenges);
urls.add(url);
challengesList.add(challenges);
proxies.add(proxy);
return credential;
}

@Override public Credential authenticateProxy(Proxy proxy, URL url, List<Challenge> challenges)
throws IOException {
calls.add("authenticateProxy"
+ " proxy=" + proxy.type()
+ " url=" + url
+ " challenges=" + challenges);
urls.add(url);
challengesList.add(challenges);
proxies.add(proxy);
return credential;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import com.squareup.okhttp.ConnectionPool;
import com.squareup.okhttp.HttpResponseCache;
import com.squareup.okhttp.OkAuthenticator.Challenge;
import com.squareup.okhttp.OkAuthenticator.Credential;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.OkUrlFactory;
Expand Down Expand Up @@ -1644,6 +1645,39 @@ enum StreamingMode {
}
}

/** https://code.google.com/p/android/issues/detail?id=74026 */
@Test public void authenticateWithGetAndTransparentGzip() throws Exception {
MockResponse pleaseAuthenticate = new MockResponse().setResponseCode(401)
.addHeader("WWW-Authenticate: Basic realm=\"protected area\"")
.setBody("Please authenticate.");
// fail auth three times...
server.enqueue(pleaseAuthenticate);
server.enqueue(pleaseAuthenticate);
server.enqueue(pleaseAuthenticate);
// ...then succeed the fourth time
MockResponse successfulResponse = new MockResponse()
.addHeader("Content-Encoding", "gzip")
.setBody(gzip("Successful auth!".getBytes("UTF-8")));
server.enqueue(successfulResponse);
server.play();

Authenticator.setDefault(new RecordingAuthenticator());
connection = client.open(server.getUrl("/"));
assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));

// no authorization header for the first request...
RecordedRequest request = server.takeRequest();
assertContainsNoneMatching(request.getHeaders(), "Authorization: Basic .*");

// ...but the three requests that follow requests include an authorization header
for (int i = 0; i < 3; i++) {
request = server.takeRequest();
assertEquals("GET / HTTP/1.1", request.getRequestLine());
assertContains(request.getHeaders(),
"Authorization: Basic " + RecordingAuthenticator.BASE_64_CREDENTIALS);
}
}

/** https://github.com/square/okhttp/issues/342 */
@Test public void authenticateRealmUppercase() throws Exception {
server.enqueue(new MockResponse().setResponseCode(401)
Expand Down Expand Up @@ -2661,11 +2695,10 @@ private void reusedConnectionFailsWithPost(TransferKind transferKind, int reques
assertContains(server.takeRequest().getHeaders(),
"Authorization: " + credential.getHeaderValue());

assertEquals(1, authenticator.calls.size());
String call = authenticator.calls.get(0);
assertTrue(call, call.contains("proxy=DIRECT"));
assertTrue(call, call.contains("url=" + server.getUrl("/private")));
assertTrue(call, call.contains("challenges=[Basic realm=\"protected area\"]"));
assertEquals(Proxy.NO_PROXY, authenticator.onlyProxy());
URL url = authenticator.onlyUrl();
assertEquals("/private", url.getPath());
assertEquals(Arrays.asList(new Challenge("Basic", "protected area")), authenticator.onlyChallenge());
}

@Test public void npnSetsProtocolHeader_SPDY_3() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,18 @@ public final class CacheStrategy {
}
}

public final Request request;
public final Response response;
/** The request to send on the network, or null if this call doesn't use the network. */
public final Request networkRequest;

/** The cached response to return or validate; or null if this call doesn't use a cache. */
public final Response cacheResponse;

public final ResponseSource source;

private CacheStrategy(
Request request, Response response, ResponseSource source) {
this.request = request;
this.response = response;
Request networkRequest, Response cacheResponse, ResponseSource source) {
this.networkRequest = networkRequest;
this.cacheResponse = cacheResponse;
this.source = source;
}

Expand Down Expand Up @@ -165,12 +169,12 @@ public CacheStrategy get() {
if (candidate.source != ResponseSource.CACHE && request.cacheControl().onlyIfCached()) {
// We're forbidden from using the network, but the cache is insufficient.
Response noneResponse = new Response.Builder()
.request(candidate.request)
.request(candidate.networkRequest)
.statusLine(GATEWAY_TIMEOUT_STATUS_LINE)
.setResponseSource(ResponseSource.NONE)
.body(EMPTY_BODY)
.build();
return new CacheStrategy(candidate.request, noneResponse, ResponseSource.NONE);
return new CacheStrategy(null, noneResponse, ResponseSource.NONE);
}

return candidate;
Expand All @@ -180,19 +184,19 @@ public CacheStrategy get() {
private CacheStrategy getCandidate() {
// No cached response.
if (cacheResponse == null) {
return new CacheStrategy(request, cacheResponse, ResponseSource.NETWORK);
return new CacheStrategy(request, null, ResponseSource.NETWORK);
}

// Drop the cached response if it's missing a required handshake.
if (request.isHttps() && cacheResponse.handshake() == null) {
return new CacheStrategy(request, cacheResponse, ResponseSource.NETWORK);
return new CacheStrategy(request, null, ResponseSource.NETWORK);
}

// If this response shouldn't have been stored, it should never be used
// as a response source. This check should be redundant as long as the
// persistence store is well-behaved and the rules are constant.
if (!isCacheable(cacheResponse, request)) {
return new CacheStrategy(request, cacheResponse, ResponseSource.NETWORK);
return new CacheStrategy(request, null, ResponseSource.NETWORK);
}

CacheControl requestCaching = request.cacheControl();
Expand Down Expand Up @@ -228,7 +232,7 @@ private CacheStrategy getCandidate() {
if (ageMillis > oneDayMillis && isFreshnessLifetimeHeuristic()) {
builder.addHeader("Warning", "113 HttpURLConnection \"Heuristic expiration\"");
}
return new CacheStrategy(request, builder.build(), ResponseSource.CACHE);
return new CacheStrategy(null, builder.build(), ResponseSource.CACHE);
}

Request.Builder conditionalRequestBuilder = request.newBuilder();
Expand All @@ -244,10 +248,9 @@ private CacheStrategy getCandidate() {
}

Request conditionalRequest = conditionalRequestBuilder.build();
ResponseSource responseSource = hasConditions(conditionalRequest)
? ResponseSource.CONDITIONAL_CACHE
: ResponseSource.NETWORK;
return new CacheStrategy(conditionalRequest, cacheResponse, responseSource);
return hasConditions(conditionalRequest)
? new CacheStrategy(conditionalRequest, cacheResponse, ResponseSource.CONDITIONAL_CACHE)
: new CacheStrategy(conditionalRequest, null, ResponseSource.NETWORK);
}

/**
Expand Down
Loading

0 comments on commit e8fee51

Please sign in to comment.