Code Monkey home page Code Monkey logo

okhttp's Introduction

OkHttp

See the project website for documentation and APIs.

HTTP is the way modern applications network. It’s how we exchange data & media. Doing HTTP efficiently makes your stuff load faster and saves bandwidth.

OkHttp is an HTTP client that’s efficient by default:

  • HTTP/2 support allows all requests to the same host to share a socket.
  • Connection pooling reduces request latency (if HTTP/2 isn’t available).
  • Transparent GZIP shrinks download sizes.
  • Response caching avoids the network completely for repeat requests.

OkHttp perseveres when the network is troublesome: it will silently recover from common connection problems. If your service has multiple IP addresses, OkHttp will attempt alternate addresses if the first connect fails. This is necessary for IPv4+IPv6 and services hosted in redundant data centers. OkHttp supports modern TLS features (TLS 1.3, ALPN, certificate pinning). It can be configured to fall back for broad connectivity.

Using OkHttp is easy. Its request/response API is designed with fluent builders and immutability. It supports both synchronous blocking calls and async calls with callbacks.

Get a URL

This program downloads a URL and prints its contents as a string. Full source.

OkHttpClient client = new OkHttpClient();

String run(String url) throws IOException {
  Request request = new Request.Builder()
      .url(url)
      .build();

  try (Response response = client.newCall(request).execute()) {
    return response.body().string();
  }
}

Post to a Server

This program posts data to a service. Full source.

public static final MediaType JSON = MediaType.get("application/json");

OkHttpClient client = new OkHttpClient();

String post(String url, String json) throws IOException {
  RequestBody body = RequestBody.create(json, JSON);
  Request request = new Request.Builder()
      .url(url)
      .post(body)
      .build();
  try (Response response = client.newCall(request).execute()) {
    return response.body().string();
  }
}

Further examples are on the OkHttp Recipes page.

Requirements

OkHttp works on Android 5.0+ (API level 21+) and Java 8+.

OkHttp depends on Okio for high-performance I/O and the Kotlin standard library. Both are small libraries with strong backward-compatibility.

We highly recommend you keep OkHttp up-to-date. As with auto-updating web browsers, staying current with HTTPS clients is an important defense against potential security problems. We track the dynamic TLS ecosystem and adjust OkHttp to improve connectivity and security.

OkHttp uses your platform's built-in TLS implementation. On Java platforms OkHttp also supports Conscrypt, which integrates BoringSSL with Java. OkHttp will use Conscrypt if it is the first security provider:

Security.insertProviderAt(Conscrypt.newProvider(), 1);

The OkHttp 3.12.x branch supports Android 2.3+ (API level 9+) and Java 7+. These platforms lack support for TLS 1.2 and should not be used.

Releases

Our change log has release history.

The latest release is available on Maven Central.

implementation("com.squareup.okhttp3:okhttp:4.12.0")

Snapshot builds are available. R8 and ProGuard rules are available.

Also, we have a bill of materials (BOM) available to help you keep OkHttp artifacts up to date and be sure about version compatibility.

    dependencies {
       // define a BOM and its version
       implementation(platform("com.squareup.okhttp3:okhttp-bom:4.12.0"))

       // define any required OkHttp artifacts without version
       implementation("com.squareup.okhttp3:okhttp")
       implementation("com.squareup.okhttp3:logging-interceptor")
    }

MockWebServer

OkHttp includes a library for testing HTTP, HTTPS, and HTTP/2 clients.

The latest release is available on Maven Central.

testImplementation("com.squareup.okhttp3:mockwebserver:4.12.0")

GraalVM Native Image

Building your native images with Graal https://www.graalvm.org/ should work automatically. This is not currently in a final released version, so 5.0.0-alpha.2 should be used. Please report any bugs or workarounds you find.

See the okcurl module for an example build.

$ ./gradlew okcurl:nativeImage
$ ./okcurl/build/graal/okcurl https://httpbin.org/get

License

Copyright 2019 Square, Inc.

Licensed 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.

okhttp's People

Contributors

15characterlimi avatar adriancole avatar amirlivneh avatar artem-zinnatullin avatar christiankatzmann avatar cketti avatar dave-r12 avatar edenman avatar egorand avatar ericaschulz avatar erikghonyan avatar galderz avatar goooler avatar jakewharton avatar jawnnypoo avatar jeremy-techson avatar lingmingyb avatar mescortes avatar monkey-mas avatar narayank avatar nfuller avatar nightlynexus avatar oldergod avatar pforhan avatar renovate[bot] avatar shaishavgandhi avatar swankjesse avatar tanghuaizhe avatar yschimke avatar zacsweers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

okhttp's Issues

ConnectionPool crash

E/AndroidRuntime(28150): java.lang.NullPointerException
E/AndroidRuntime(28150): at com.android.okhttp.internal.http.SpdyTransport.makeReusable(SpdyTransport.java:84)
E/AndroidRuntime(28150): at com.android.okhttp.internal.http.HttpEngine.release(HttpEngine.java:432)
E/AndroidRuntime(28150): at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:352)
E/AndroidRuntime(28150): at com.android.okhttp.internal.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:96)
E/AndroidRuntime(28150): at com.android.okhttp.internal.http.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:169)

Possibly unsafe concurrent accesses to DiskLruCache.redundantOpCount

All accesses to com.squareup.okhttp.internal.DiskLruCache.redundantOpCount except the ones in method com.squareup.okhttp.internal.DiskLruCache.readJournal() are protected by a lock:

  • DiskLRUCache.redundantOpCount
    • DiskLRUCache.cleanupCallable.call()[DiskLRUCache]
    • DiskLRUCache.completeEdit(Editor editor, boolean success)[DiskLRUCache]
      • DiskLRUCache.editor.abort()
      • DiskLRUCache.editor.commit()
      • DiskLRUCache.get(String key)[DiskLRUCache]
        • HttpResponseCache.get(URI uri, String requestMethod, Map<String, List> requestHeaders)
    • DiskLRUCache.journalRebuildRequired(), reads line 568, 569
      • DiskLRUCache.cleanupCallable.call()[DiskLRUCache]
      • DiskLRUCache.completeEdit(Editor editor, boolean success)[DiskLRUCache]
      • DiskLRUCache.get(String key)[DiskLRUCache]
      • DiskLRUCache.remove(String key)[DiskLRUCache]
  • DiskLRUCache.readJournal(), write line 272
    • DiskLRUCache.open(File directory, int appVersion, int valueCount, long maxSize)
      • HttpResponseCache.HttpResponseCache(File directory, long maxSize)
  • DiskLRUCache.remove(String key)[DiskLRUCache]
    • HttpResponseCache.put(URI uri, URLConnection urlConnection)
    • DiskLRUCache.editor.commit()
    • DiskLRUCache.trimToSize()

Wouldn't it be safer to protected the accesses to com.squareup.okhttp.internal.DiskLruCache.redundantOpCount in method com.squareup.okhttp.internal.DiskLruCache.readJournal() as well?

File handle leak in DiskLruCache.get() in case of FileNotFoundException

The master branch contains the current code snippet:

InputStream[] ins = new InputStream[valueCount];
try {
  for (int i = 0; i < valueCount; i++) {
    ins[i] = new FileInputStream(entry.getCleanFile(i));
  }
} catch (FileNotFoundException e) {
  // a file must have been deleted manually!
  return null;
}

In case of the FNFE, any input streams previously created in ins aren't closed.

Public API for HTTP response cache

We need something equivalent to Android's HttpResponseCache class, that lets you install the cache, configure its size and possibly clear it.

Throw the right exception on a malformed status line

This test currently fails:

public void testMalformedStatusLine() throws IOException {
    server.enqueue(new MockResponse().setStatus("HTP/1.1 200 OK"));
    server.play();

    OkHttpConnection urlConnection = OkHttpConnection.open(server.getUrl("/"));
    try {
        urlConnection.getResponseCode();
        fail();
    } catch (IOException expected) {
    }
}

Code and documentation to use okhttp

There's no documentation or code that allows a potential users of okhttp to use it in an Android app or a regular, non-Android program. Such support code and documentation would sure be helpful.

Better sharing for Executors (thread pools)

Currently each SPDY connection creates its own ExecutorService for read, write and callbacks. We could do the same work with fewer resources by using fewer ExecutorServices.

Along with this we should improve thread naming, so that stack dumps show application-level thread information, like SPDY reader: http://api.squareup.com or SPDY callback: http://api.squareup.com stream 5.

IllegalArgumentException: Buffer size <= 0 when doing post request

I did not have time to check since I have just to donwload a json from a webservice,
but I experienced issues with the library while doing a post request.
I had successfully made the request with default HttpUrlConnection class but i wanted to move to OkHttp due to its features.

i have my calls:

final String url = request.getRequestURL();
final JSONObject bodyObj = request.getRequestBody();
final byte[] body = bodyObj.toString().getBytes();
URL urlObj = new URL(url);
// OK HTTP
OkHttpClient client = new OkHttpClient();
HttpURLConnection connection = client.open(urlObj);
OutputStreamWriter out = null;
InputStream in = null;
try {
// Write the request.
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Content-Length", Integer.toString(body.length));
out = connection.getOutputStream();
out.write(body);
out.close();
// Read the response.
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new IOException("Unexpected HTTP response: " + connection.getResponseCode() + " " + connection.getResponseMessage());
}
in = connection.getInputStream();
return readStream(in);
} finally {
// Clean up.
if (out != null) out.close();
if (in != null) in.close();

}

I got an exception while doing out = connection.getOutputStream();
The code above is like your code from examples, and i get the exception in Class: Connection.java at line 93/94 when it does:
int mtu = Platform.get().getMtu(socket);
in = new BufferedInputStream(in, mtu);
I get mtu = -1; and hence the allocation will throw exception.
If i do new BufferedInputStream(in) i got exception anyway, the only solution i found is to do:
// Use MTU-sized buffers to send fewer packets.
int mtu = Platform.get().getMtu(socket);
if (mtu <= 0) {
mtu = 1400;
}
in = new BufferedInputStream(in, mtu);
I took 1400 from a method in your classes.
Changing the code to the above will do the connection correctly. Is it a bug or am i doing something wrong?

Remember failed routes

We aren't very smart about not making the same mistake twice when it comes to route failures. Suppose we get 2 IP addresses corresponding to datacenter EAST and datacenter WEST. If we attempt to connect to EAST and it fails, we don't remember that failure for subsequent connection attempts.

Each OkHttpClient's RouteSelector should know about routes that have previously failed and try them last.

Add URLStreamHandlerFactory implementation so URL.openConnection() uses OkHttp

Currently, to use OkHttp, all code has to be changed to use OkHttpClient instead of the normal URL.openConnection() method. Besides being invasive, and requiring changes to all libraries, it's also a maintenance problem - OkHttpClient is nice and all, but someday people may want to move to something else.

It would be nice if OkHttp included an implementation of java.net.URLStreamHandlerFactory. For extra credit, it would be really nice if OkHttpClient had an "install" method that simply called URL.setURLStreamHandlerFactory(...) for easy use by applications. Even better would be if that install method only installed the OkHttp stream handler factory if the Android SDK version is below a given level... that way, applications will always use the ideal client.

With this approach, all existing code that uses URL.openConnection() would just work without any modification.

Feel free to look at my code if you so chose for reference: https://github.com/candrews/HttpResponseCache/blob/master/src/main/java/com/integralblue/httpresponsecache/HttpResponseCache.java#L178

New, non-static authenticator

The java.net.Authenticator API pushes all authentication through a single implementation. This doesn't scale to apps that have multiple independent modules.

Possibly unsafe concurrent accesses to SpdyConnection.spdyWriter

The field com.squareup.okhttp.internal.spdy.SpdyConnection.spdyWriter may be accessed in parallel without proper synchronization.

* SpdyConnection.spdyWriter
** SpdyConnection.SpdyConnection(Builder builder)
*** SpdyConnection.build()
** SpdyConnection.newStream(List<String> requestHeaders, boolean out, boolean in), read line 177
*** SpdyTransport.writeRequestHeaders()
**** SpdyConnectionTest....
** SpdyConnection.writeSynReply(int streamId, int flags, List<String> alternating)
*** SpdyStream.reply(List<String> responseHeaders, boolean out)
** SpdyConnection.writeFrame(byte[] bytes, int offset, int length)[SpdyConnection.spdyWriter]
*** SpdyStream.writeFrame(boolean last)
** SpdyConnection.writeSynReset(int streamId, int statusCode)
*** SpdyConnection.writeSynResetLater(final int streamId, final int statusCode)
*** SpdyStream.close(int rstStatusCode)
** SpdyConnection.writeWindowUpdate(int streamId, int deltaWindowSize)
*** SpdyConnection.writeWindowUpdateLater(final int streamId, final int deltaWindowSize)
** SpdyConnection.writePing(int id, Ping ping)[SpdyConnection.spdyWriter]
*** SpdyConnection.ping()
*** SpdyConnection.writePingLater(final int streamId, final Ping ping)
** SpdyConnection.noop()
*** SpdyConnectionTest.noop()
** SpdyConnection.flush()[SpdyConnection.spdyWriter]
*** SpdyStream.SpdyDataOutputStream.close()
*** SpdyStream.SpdyDataOutputStream.flush()
** SpdyConnection.shutdown(int statusCode)[SpdyConnection.spdyWriter]
*** SpdyConnection.close(int shutdownStatusCode, int rstStatusCode)
*** SpdyConnectionTest....
** SpdyConnecction.close(int shutdownStatusCode, int rstStatusCode)[SpdyConnection.class]
*** SpdyConnection.close()
*** SpdyConnection.reader.run()

The above notation is described in issue #145.

The call graph for accesses to com.squareup.okhttp.internal.spdy.SpdyConnection.spdyWriter shows that some of the accesses to this field are protected, e.g., SpdyConnection.close() uses the lock object SpdyConnection.class to protect access to this field and SpdyConnection.writeFrame uses SpdyConnection.spdyWriter as the lock object. However, SpdyConnection.writeSynReset(int, int) and SpdyConnection.writeWindowUpdate(int, int) do not protect their accesses to field SpdyConnection.spdyWriter

Keshmesh found this issue when we marked method com.squareup.okhttp.internal.mockspdyserver.newStream(requestHeaders,out,in) as an entry point. Nonetheless, if you're confident that the unprotected accesses to com.squareup.okhttp.internal.spdy.SpdyConnection.spdyWriter do not occur in practice, you may ignore this issue.

Use a good hostname verifier on the desktop

The core library's default hostname verifier on Android is good: it follows the TLS specs and validates that the certificate covers the hostname.

On the desktop, the story is not so good. The default hostname verifier returns false always. Apparently in the RI's HttpsURLConnection they do two rounds of hostname verification: first in the library and then again in the user's hostname verifier if the library fails. We need to either do likewise, or make our hostname verifier stronger.

Possibly unsafe concurrent accesses to DiskLruCache.Entry.currentEditor

The accesses to com.squareup.okhttp.internal.DiskLruCache.Entry.currentEditor are protected in the following methods:

  1. com.squareup.okhttp.internal.DiskLruCache.close()
  2. com.squareup.okhttp.internal.DiskLruCache.completeEdit(Editor, boolean)
  3. com.squareup.okhttp.internal.DiskLruCache.edit(String, long)
  4. com.squareup.okhttp.internal.DiskLruCache.Editor.newInputStream(int)
  5. com.squareup.okhttp.internal.DiskLruCache.Editor.newOutputStream(int)
  6. com.squareup.okhttp.internal.DiskLruCache.rebuildJournal()
  7. com.squareup.okhttp.internal.DiskLruCache.remove(String)
  8. com.squareup.okhttp.internal.DiskLruCache.flush()

However, accesses to com.squareup.okhttp.internal.DiskLruCache.Entry.currentEditor are not protected in the following methods or their callers:

  1. com.squareup.okhttp.internal.DiskLruCache.processJournal()
  2. com.squareup.okhttp.internal.DiskLruCache.readJournalLine(String)

Do the accesses to com.squareup.okhttp.internal.DiskLruCache.Entry.currentEditor need to be protected against concurrent accesses in the above two methods?

Possibly unsafe concurrent accesses to DiskLruCache.maxSize

The accesses to com.squareup.okhttp.internal.DiskLruCache.maxSize are protected in the following methods:

  1. com.squareup.okhttp.internal.DiskLruCache.completeEdit(Editor, boolean)
  2. com.squareup.okhttp.internal.DiskLruCache.setMaxSize(long)

However, accesses to com.squareup.okhttp.internal.DiskLruCache.maxSize are not protected in the following methods:

  1. com.squareup.okhttp.internal.DiskLruCache.getMaxSize(). Fortunately, this method doesn't seem to be used at the time. Nonetheless, it could lead to bugs if it gets used in future as it is.
  2. com.squareup.okhttp.internal.DiskLruCache.trimToSize(). Although accesses to DiskLruCache.size are not synchronized inside this method, all current call sites of this method are inside synchronized methods or blocks.

Would it be safer to protect concurrent accesses to com.squareup.okhttp.internal.DiskLruCache.maxSize inside com.squareup.okhttp.internal.DiskLruCache.getMaxSize()?

Possibly unsafe concurrent accesses to DiskLruCache.size

The accesses to com.squareup.okhttp.internal.DiskLruCache.size are protected in the following methods:

  1. com.squareup.okhttp.internal.DiskLruCache.completeEdit(Editor, boolean)
  2. com.squareup.okhttp.internal.DiskLruCache.remove(String)
  3. com.squareup.okhttp.internal.DiskLruCache.size()

However, accesses to com.squareup.okhttp.internal.DiskLruCache.size are not protected in the following methods:

  1. com.squareup.okhttp.internal.DiskLruCache.processJournal()
  2. com.squareup.okhttp.internal.DiskLruCache.trimToSize(). Although accesses to DiskLruCache.size are not synchronized inside this method, all current call sites of this method are inside synchronized methods or blocks.

Would it be safer to protect concurrent accesses to com.squareup.okhttp.internal.DiskLruCache.size inside com.squareup.okhttp.internal.DiskLruCache.processJournal()?

Possibly unsafe concurrent accesses to DiskLruCache.journalWriter

Note: This issue looks more of a code smell. Although, it may lead to confusion and bugs in future, it doesn't seem like a real bug at the moment. Nonetheless, due to the subtleties of concurrency bugs and my limited familiarity with the code base of okhttp and its conventions, I'd rather report the problem and leave it to you to decide about the right course of action.

Field com.squareup.okhttp.internal.DiskLruCache.journalWriter is being accessed as follows:

  • DiskLRUCache.journalWriter
    • DiskLRUCache.cleanupCallable.call()[DiskLRUCache.class]
    • DiskLRUCache.checkNotClosed(), read line 612
      • DiskLRUCache.edit(String key, long expectedSequenceNumber)[DiskLRUCache.class]
      • DiskLRUCache.flush()[DiskLRUCache.class]
      • DiskLRUCache.get(String key)[DiskLRUCache.class]
      • DiskLRUCache.remove(String key)[DiskLRUCache.class]
    • DiskLRUCache.close()[DiskLRUCache.class]
      • DiskLRUCache.delete()
      • Util.closeAll(Closeable a, Closeable b)
      • Util.closeQuietly(Closeable closeable)
    • DiskLRUCache.completeEdit(Editor editor, boolean success)[DiskLRUCache.class]
      • DiskLRUCache.editor.abort()
      • DiskLRUCache.editor.commit()
      • DiskLRUCache.edit(String key, long expectedSequenceNumber)[DiskLRUCache.class]
      • DiskLRUCache.edit(String key)
      • DiskLRUCache.snapshot.edit()
    • DiskLRUCache.flush()[DiskLRUCache.class]
    • DiskLRUCache.get(String key)[DiskLRUCache.class]
      • HttpResponseCache.get(URI uri, String requestMethod, Map<String, List> requestHeaders)
    • DiskLRUCache.isClosed()
    • DiskLRUCache.open(File directory, int appVersion, int valueCount, long maxSize), read/write line 229
      • HttpResponseCache.HttpResponseCache(File directory, long maxSize)
        • HttpResponseCacheTest.setUp()
        • UrlConnectionTest.initResponseCache()
        • HttpOverSpdyTest.setUp()
    • DiskLRUCache.rebuildJournal()[DiskLRUCache.class]
      • DiskLRUCache.cleanupCallable.call()[DiskLRUCache.class]
      • DiskLRUCache.open(File directory, int appVersion, int valueCount, long maxSize)
    • DiskLRUCache.remove(String key)[DiskLRUCache.class]
      • HttpResponseCache.put(URI uri, URLConnection urlConnection)
      • DiskLRUCache.editor.commit()
      • DiskLRUCache.trimToSize()

The above call graph shows that accesses to DiskLRUCache.journalWriter are protected by locking DiskLRUCache.class, except in the following methods:

  1. DiskLRUCache.checkNotClosed()
  2. DiskLRUCache.isClosed()
  3. com.squareup.okhttp.internal.DiskLruCache.open(File, int, int, long)

Currently, the callers of method (1) lock DiskLRUCache.class before invoking it. As long as, the callers of (1) continue to take the lock, (1) does not have to be synchronized.

Method (2) is unused.

Method (3) is currently only called by HttpResponseCache.HttpResponseCache(File directory, long maxSize), which in turn is only called from test classes. Method (3) is a factory method for DiskLRUCache. Although method (3) is a factory method and only used in test classes, I think this case is worth further investigation.

"Reuse of HttpsUrlConnection when android OS proxy is set; CONNECT is send through negotiated SSL layer"

From Android issue 55003,

Tested on 4.0.4 phone, 4.2.2 tablet.

I came across this when testing SandroProxy with Google Plus.
SandroProxy will be changed to handle this situation to send send 200 Ok to client so there will be no errors. In mitm mode.
But when pass-through mode is on, ssl tunnel remains the same and errors will still occurs.

Or am I missing something and this is normal data flow for HttpsUrlConnection? :)

Fix JettyNpnProvider warnings on Dalvik

OkHttp refers to a class that isn't available on Dalvik. When it does so, we get this ugly warning in logcat:

W/dalvikvm( 6379): Link of class 'Lcom/squareup/okhttp/libcore/util/Libcore$JettyNpnProvider;' failed
D/dalvikvm( 6379): DexOpt: unable to opt direct call 0x3690 at 0x48 in Lcom/squareup/okhttp/libcore/util/Libcore;.setNpnProtocols
I/dalvikvm( 6379): Failed resolving Lcom/squareup/okhttp/libcore/util/Libcore$JettyNpnProvider; interface 4317 'Lorg/eclipse/jetty/npn/NextProtoNego$ClientProvider;'

The warning is benign, but it's distracting and makes OkHttp look broken!

Failures in NPN on desktop for 2nd SPDY connection to https://www.google.com/

I've written code that attempts multiple simultaneous SPDY connections to the same host. It avoids connection reuse by using different hostname verifier for each request.

        printSite(new URL("https://www.google.com/"));
        printSite(new URL("https://www.google.com/"));
        printSite(new URL("https://www.google.com/"));
        printSite(new URL("https://www.google.com/"));

This fails with the following exceptions:

java.net.SocketException: Broken pipe
    at java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
    at sun.security.ssl.OutputRecord.writeBuffer(OutputRecord.java:377)
    at sun.security.ssl.OutputRecord.write(OutputRecord.java:363)
    at sun.security.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:830)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:801)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122)
    at java.io.OutputStream.write(OutputStream.java:75)
    at libcore.net.http.HttpTransport.writeRequestHeaders(HttpTransport.java:133)
    at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:616)
    at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:284)
    at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:432)
    at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:133)
    at libcore.net.http.ManualHttpsTest.printSite(ManualHttpsTest.java:52)
    at libcore.net.http.ManualHttpsTest.main(ManualHttpsTest.java:33)
javax.net.ssl.SSLException: Received fatal alert: unexpected_message
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1977)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1093)
    at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:884)
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:102)
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
    at libcore.io.Streams.readAsciiLine(Streams.java:202)
    at libcore.net.http.RawHeaders.fromBytes(RawHeaders.java:312)
    at libcore.net.http.HttpTransport.readResponseHeaders(HttpTransport.java:137)
    at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:628)
    at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:284)
    at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:432)
    at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:133)
    at libcore.net.http.ManualHttpsTest.printSite(ManualHttpsTest.java:52)
    at libcore.net.http.ManualHttpsTest.main(ManualHttpsTest.java:35)

DiskLruCache.rebuildJournal() fails silently on Windows

journalFileTmp.renameTo(journalFile);
journalWriter = new BufferedWriter(new FileWriter(journalFile, true));

On Windows, renameTo() fails if the destination file already exists. The above code ignores the method's return value, effectively using the old/uncompacted journal file going forward, allowing it grow out of bounds.

Noticed by DiskLruCacheTest.rebuildJournalOnRepeatedReads() which runs forever here.

Possible unsafe concurrent accesses to SpdyConnection.idleStartTimeNs

The field com.squareup.okhttp.internal.spdy.SpdyConnection.idleStartTimeNs may be accessed in parallel without proper synchronization.

* SpdyConnection.idleStartTimeNs
** SpdyConnection.setIdle(boolean value), write line 146
*** SpdyConnection.close(int shutdownStatusCode, int rstStatusCode)[SpdyConnection.class]
**** SpdyConnection.close()
**** SpdyConnection.reader.run()
*** SpdyConnection.newStream(List<String> requestHeaders, boolean out, boolean in)[SpdyConnection.spdyWriter]
**** SpdyTransport.writeRequestHandlers()
**** SpdyConnectionTest....
*** SpdyConnection.removeStream(int streamId)[SpdyConnection.class]
**** SpdyConnection.reader.rstStream(int flags, int streamId, int statusCode)
**** SpdyConnection.synStream(int flags, int streamId, int associatedStreamId, int priority, int slot,List<String> nameValueBlock)[SpdyConnection.class]
**** SpdyStream.cancelStreamIfNecessary()[SpdyStream.class]
**** SpdyStream.closeInternal(int rstStatusCode)[SpdyStream.class]
**** SpdyStream.receiveFin()[SpdyStream.class]
**** SpdyStream.receiveReply(List<String> strings)[SpdyStream.class]
** SpdyConnection.isIdle()
*** Connection.isIdle()
** SpdyConnection.getIdleStartTimeNs()
*** Connection.getIdleStartTimeNs()

Legend: The call graph listed above is reprsented in the following notation. For example, the following indicates that shared field F1 is writen by M1 on line 10, and M1 is invoked by M2. In addition, the objects shown in the brackets indicate the lock objects that the methods use to protect accesses to the shared field. For example, M2 protects its call to M1 by lock object LO1 in the follwoing example.

* Shared field F1
** M1(parameters), write line 10
*** M2(parameters)[LO1]

The call graph for accesses to com.squareup.okhttp.internal.spdy.SpdyConnection.idleStartTimeNs shows that some of the accesses to this field are protected, e.g., SpdyConnection.close() uses the lock object SpdyConnection.class to protect access to this field, while SpdyConnection.isIdle() and SpdyConnection.getIdleStartTimeNs() do not protect their accesses to field SpdyConnection.idleStartTimeNs

Note that accesses to idleStartTimeNs may be currently safe. Maintainers of the code are in a better position than us to decide if current accesses to this field are safe or not. Anyways, future changes to the code might introduce an unsafe concurrent access to the field accidentally. So, depending on your desired level of safety, you may decide to add more protection for concurrent accesses to idleStartTimeNs. Simply making idleStartTimeNs a volatile field is enough to ensure that concurrent accesses to this field are safe.

OkHttp changes the global SSL context, breaks other HTTP clients

We're enabling SPDY for the shared SSL context, and other HTTP clients like HttpURLConnection don't anticipate this, causing them to freak out and crash the app.

@skyisle's original report...

Here is backtrace.

DEBUG I backtrace:
DEBUG I #00 pc 00022430 /system/lib/libssl.so (SSL_select_next_proto+25)
DEBUG I #1 pc 000222ef /system/lib/libjavacore.so
DEBUG I #2 pc 0002905f /system/lib/libssl.so (ssl_parse_serverhello_tlsext+458)
DEBUG I #3 pc 00015957 /system/lib/libssl.so (ssl3_get_server_hello+894)
DEBUG I #4 pc 00018193 /system/lib/libssl.so (ssl3_connect+618)
DEBUG I #5 pc 000235d7 /system/lib/libssl.so (SSL_connect+18)
DEBUG I #6 pc 0001126b /system/lib/libssl.so (ssl23_connect+1970)
DEBUG I #7 pc 0002350f /system/lib/libssl.so (SSL_do_handshake+66)
DEBUG I #8 pc 00024bc5 /system/lib/libjavacore.so
DEBUG I #9 pc 0001e490 /system/lib/libdvm.so (dvmPlatformInvoke+112)
DEBUG I #10 pc 0004d2b1 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const_, JValue_, Method const_, Thread_)+396)
DEBUG I #11 pc 000278a0 /system/lib/libdvm.so
DEBUG I #12 pc 0002b77c /system/lib/libdvm.so (dvmInterpret(Thread_, Method const_, JValue_)+176)
DEBUG I #13 pc 0005fae5 /system/lib/libdvm.so (dvmCallMethodV(Thread_, Method const_, Object_, bool, JValue_, std::va_list)+272)
DEBUG I #14 pc 0005fb0f /system/lib/libdvm.so (dvmCallMethod(Thread
, Method const
, Object_, JValue*, ...)+20)
DEBUG I #15 pc 0005466f /system/lib/libdvm.so
DEBUG I #16 pc 0000e418 /system/lib/libc.so (__thread_entry+72)
DEBUG I #17 pc 0000db0c /system/lib/libc.so (pthread_create+168)
DEBUG I #18 pc 00052f34

Enable TLSv1.1 and TLSv1.2

I was thinking enableTlsExtensions(SSLSocket socket, String uriHost) might want to enable non-default protocols. we don't enable TLSv1.1 and TLSv1.2 in Android because there are non-compatible servers, but given that okhttp client falls back to SSLv3 if there are problems, it seems like it might be good to do that here.

On the other hand, maybe it should only be done if the SSLSocketFactory is a default one, since they might have specified one to specifically set the enable protocols.

Automatic gzip + accept range don't interact well

We run into problems because we try to uncompress a partial document.

java.util.zip.ZipException: Not in GZIP format
    at java.util.zip.GZIPInputStream.readHeader(GZIPInputStream.java:164)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:78)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:90)
    at com.squareup.okhttp.internal.http.HttpEngine.initContentStream(HttpEngine.java:452)
    at com.squareup.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:666)
    at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:334)
    at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:283)
    at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:454)
    at com.squareup.okhttp.internal.http.GzipTest.testRange(ExoticSslTest.java:65)

Work around by adding this header:

    ohc.setRequestProperty("Accept-Encoding", "identity");

NoSuchMethodError: java.util.LinkedList.descendingIterator

W/Square ( 2218): Uncaught exception on thread HTTP Benchmark
W/Square ( 2218): java.lang.NoSuchMethodError: java.util.LinkedList.descendingIterator
W/Square ( 2218): at com.squareup.okhttp.ConnectionPool.get(ConnectionPool.java:163)
W/Square ( 2218): at com.squareup.okhttp.internal.http.RouteSelector.next(RouteSelector.java:99)
W/Square ( 2218): at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:280)
W/Square ( 2218): at com.squareup.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:249)
W/Square ( 2218): at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:199)
W/Square ( 2218): at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:332)
W/Square ( 2218): at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:283)
W/Square ( 2218): at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:454)
W/Square ( 2218): at com.squareup.okhttp.internal.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:138)
W/Square ( 2218): at com.squareup.http.AbstractOkHttpClient.execute(AbstractOkHttpClient.java:149)
W/Square ( 2218): at com.squareup.http.AbstractOkHttpClient.execute(AbstractOkHttpClient.java:95)
W/Square ( 2218): at com.squareup.cardcase.development.HttpClientBenchmarkService$HttpBenchmark.measure(HttpClientBenchmarkService.java:107)
W/Square ( 2218): at com.squareup.cardcase.development.HttpClientBenchmarkService$HttpBenchmark.run(HttpClientBenchmarkService.java:92)
W/Square ( 2218): at java.lang.Thread.run(Thread.java:1096)

Make OkHttp work on Java < 7

It appears that due to the dependency on DeflaterOutputStream(OutputStream out, boolean syncFlush), OkHttp must be compiled on Java 7 and will only run on Java 7 or Android.

Ideally: could okhttp use the syncFlush DeflaterOutputStream constructor if it's available, but if it's not, use some other means (perhaps jzlib) of accomplishing the same goals?

Less than ideally: use reflection as described by @swankjesse at https://code.google.com/p/android/issues/detail?id=14297#c2 so that the library can at least be compiled on Java < 7. This will also at least allow the use of animal-sniffer so that automated checks can be done at package time to ensure that only Java 5 APIs are used, raising confidence that the library will work at runtime.

Allow more than 5 redirects

The code currently will only follow a maximum of 5 redirects based on HTTP/1.0 guidance. However in practice there are apps that need to follow more. Oracle's HttpURLConnection doesn't document any such limit.

/**
 * HTTP 1.1 doesn't specify how many redirects to follow, but HTTP/1.0
 * recommended 5. http://www.w3.org/Protocols/HTTP/1.0/spec.html#Code3xx
 */
private static final int MAX_REDIRECTS = 5;

Keep alive duration default and configurability

The default keep alive duration is 5 minutes and might too much in the context of an Android application.

I think we should:

  • make this configurable,
  • set it to a better default when running on Android.

SSLException with OkHttp and SSLCertificateSocketFactory

javax.net.ssl.SSLException: Write error: ssl=0x72ea6ed0: I/O error during system call, Broken pipe
at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_write(Native Method)
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:706)
at com.android.okhttp.internal.http.HttpTransport$ChunkedOutputStream.write(HttpTransport.java:322)

Better support for SETTINGS

The spdy/2 spec wants us to store settings somewhere durable (like HTTP cookies) so we can honor each server's advice when we create new SPDY connections later.

Currently we aren't doing this. We may want to.

It's more interesting if we ever want to send SETTINGS frames, since then we'll be obligated to remember what the server told us, even if we aren't otherwise interested.

4xx & 5xx throw exceptions

I don't think I'm the only one connecting to APIs that return non-2xx status codes.

It's frustrating to handle error cases as exception cases for two reasons:

  1. These aren't truly "exceptional" (a la PragProg) -- sometimes you request a resource that's not there, or you try to submit params that aren't quite right. This should be handled in regular application flow, not exception handlers.
  2. This makes it impossible to grab the InputStream which might contain some useful data about what went wrong (eg, error messages).

Is there some way to turn off this behavior?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.