/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.squareup.okhttp.internal.huc; import com.squareup.okhttp.Connection; import com.squareup.okhttp.Handshake; import com.squareup.okhttp.Headers; import com.squareup.okhttp.HttpUrl; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Protocol; import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; import com.squareup.okhttp.Route; import com.squareup.okhttp.internal.Internal; import com.squareup.okhttp.internal.Platform; import com.squareup.okhttp.internal.Util; import com.squareup.okhttp.internal.Version; import com.squareup.okhttp.internal.http.HttpDate; import com.squareup.okhttp.internal.http.HttpEngine; import com.squareup.okhttp.internal.http.HttpMethod; import com.squareup.okhttp.internal.http.OkHeaders; import com.squareup.okhttp.internal.http.RequestException; import com.squareup.okhttp.internal.http.RetryableSink; import com.squareup.okhttp.internal.http.RouteException; import com.squareup.okhttp.internal.http.StatusLine; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpRetryException; import java.net.HttpURLConnection; import java.net.InetSocketAddress; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.Proxy; import java.net.SocketPermission; import java.net.URL; import java.net.UnknownHostException; import java.security.Permission; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import okio.BufferedSink; import okio.Sink; /** * This implementation uses HttpEngine to send requests and receive responses. * This class may use multiple HttpEngines to follow redirects, authentication * retries, etc. to retrieve the final response body. * *
Warning: This method may return false before attempting
* to connect and true afterwards.
*/
@Override public final boolean usingProxy() {
Proxy proxy = route != null
? route.getProxy()
: client.getProxy();
return proxy != null && proxy.type() != Proxy.Type.DIRECT;
}
@Override public String getResponseMessage() throws IOException {
return getResponse().getResponse().message();
}
@Override public final int getResponseCode() throws IOException {
return getResponse().getResponse().code();
}
@Override public final void setRequestProperty(String field, String newValue) {
if (connected) {
throw new IllegalStateException("Cannot set request property after connection is made");
}
if (field == null) {
throw new NullPointerException("field == null");
}
if (newValue == null) {
// Silently ignore null header values for backwards compatibility with older
// android versions as well as with other URLConnection implementations.
//
// Some implementations send a malformed HTTP header when faced with
// such requests, we respect the spec and ignore the header.
Platform.get().logW("Ignoring header " + field + " because its value was null.");
return;
}
// TODO: Deprecate use of X-Android-Transports header?
if ("X-Android-Transports".equals(field) || "X-Android-Protocols".equals(field)) {
setProtocols(newValue, false /* append */);
} else {
requestHeaders.set(field, newValue);
}
}
@Override public void setIfModifiedSince(long newValue) {
super.setIfModifiedSince(newValue);
if (ifModifiedSince != 0) {
requestHeaders.set("If-Modified-Since", HttpDate.format(new Date(ifModifiedSince)));
} else {
requestHeaders.removeAll("If-Modified-Since");
}
}
@Override public final void addRequestProperty(String field, String value) {
if (connected) {
throw new IllegalStateException("Cannot add request property after connection is made");
}
if (field == null) {
throw new NullPointerException("field == null");
}
if (value == null) {
// Silently ignore null header values for backwards compatibility with older
// android versions as well as with other URLConnection implementations.
//
// Some implementations send a malformed HTTP header when faced with
// such requests, we respect the spec and ignore the header.
Platform.get().logW("Ignoring header " + field + " because its value was null.");
return;
}
// TODO: Deprecate use of X-Android-Transports header?
if ("X-Android-Transports".equals(field) || "X-Android-Protocols".equals(field)) {
setProtocols(value, true /* append */);
} else {
requestHeaders.add(field, value);
}
}
/*
* Splits and validates a comma-separated string of protocols.
* When append == false, we require that the transport list contains "http/1.1".
* Throws {@link IllegalStateException} when one of the protocols isn't
* defined in {@link Protocol OkHttp's protocol enumeration}.
*/
private void setProtocols(String protocolsString, boolean append) {
List