diff --git a/CALLS.md b/CALLS.md new file mode 100644 index 000000000..4fa1b9cae --- /dev/null +++ b/CALLS.md @@ -0,0 +1,62 @@ +Calls +===== + +The HTTP client’s job is to accept your request and produce its response. This is simple in theory but it gets tricky in practice. + +#### [Requests](http://square.github.io/okhttp/3.x/okhttp/okhttp3/Request.html) + +Each HTTP request contains a URL, a method (like `GET` or `POST`), and a list of headers. Requests may also contain a body: a data stream of a specific content type. + +#### [Responses](http://square.github.io/okhttp/3.x/okhttp/okhttp3/Response.html) + +The response answers the request with a code (like 200 for success or 404 for not found), headers, and its own optional body. + +#### Rewriting Requests + +When you provide OkHttp with an HTTP request, you’re describing the request at a high-level: _“fetch me this URL with these headers.”_ For correctness and efficiency, OkHttp rewrites your request before transmitting it. + +OkHttp may add headers that are absent from the original request, including `Content-Length`, `Transfer-Encoding`, `User-Agent`, `Host`, `Connection`, and `Content-Type`. It will add an `Accept-Encoding` header for transparent response compression unless the header is already present. If you’ve got cookies, OkHttp will add a `Cookie` header with them. + +Some requests will have a cached response. When this cached response isn’t fresh, OkHttp can do a _conditional GET_ to download an updated response if it’s newer than what’s cached. This requires headers like `If-Modified-Since` and `If-None-Match` to be added. + +#### Rewriting Responses + +If transparent compression was used, OkHttp will drop the corresponding response headers `Content-Encoding` and `Content-Length` because they don’t apply to the decompressed response body. + +If a conditional GET was successful, responses from the network and cache are merged as directed by the spec. + +#### Follow-up Requests + +When your requested URL has moved, the webserver will return a response code like `302` to indicate the document’s new URL. OkHttp will follow the redirect to retrieve a final response. + +If the response issues an authorization challenge, OkHttp will ask the [`Authenticator`](http://square.github.io/okhttp/3.x/okhttp/okhttp3/Authenticator.html) (if one is configured) to satisfy the challenge. If the authenticator supplies a credential, the request is retried with that credential included. + +#### Retrying Requests + +Sometimes connections fail: either a pooled connection was stale and disconnected, or the webserver itself couldn’t be reached. OkHttp will retry the request with a different route if one is available. + +#### [Calls](http://square.github.io/okhttp/3.x/okhttp/okhttp3/Call.html) + +With rewrites, redirects, follow-ups and retries, your simple request may yield many requests and responses. OkHttp uses `Call` to model the task of satisfying your request through however many intermediate requests and responses are necessary. Typically this isn’t many! But it’s comforting to know that your code will continue to work if your URLs are redirected or if you failover to an alternate IP address. + +Calls are executed in one of two ways: + + * **Synchronous:** your thread blocks until the response is readable. + * **Asynchronous:** you enqueue the request on any thread, and get [called back](http://square.github.io/okhttp/3.x/okhttp/okhttp3/Callback.html) on another thread when the response is readable. + +Calls can be canceled from any thread. This will fail the call if it hasn’t yet completed! Code that is writing the request body or reading the response body will suffer an `IOException` when its call is canceled. + +#### Dispatch + +For synchronous calls, you bring your own thread and are responsible for managing how many simultaneous requests you make. Too many simultaneous connections wastes resources; too few harms latency. + +For asynchronous calls, [`Dispatcher`](http://square.github.io/okhttp/3.x/okhttp/okhttp3/Dispatcher.html) implements policy for maximum simultaneous requests. You can set maximums per-webserver (default is 5), and overall (default is 64). + + +----- + + + + + +
← HomeOkHttp User's GuideConnections →
diff --git a/CHANGELOG.md b/CHANGELOG.md index ec8f64357..814958df0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1304,8 +1304,7 @@ _2014-12-30_ running SSLv3, you must manually configure your own `ConnectionSpec`. * **OkHttp now offers interceptors.** Interceptors are a powerful mechanism - that can monitor, rewrite, and retry calls. The [project - wiki](https://github.com/square/okhttp/wiki/Interceptors) has a full + that can monitor, rewrite, and retry calls. The [interceptors doc](INTERCEPTORS.md) is a full introduction to this new API. * New: APIs to iterate and selectively clear the response cache. @@ -1788,5 +1787,5 @@ Initial release. [require_android_5]: https://medium.com/square-corner-blog/okhttp-3-13-requires-android-5-818bb78d07ce [obsolete_apache_client]: https://gist.github.com/swankjesse/09721f72039e3a46cf50f94323deb82d [obsolete_url_factory]: https://gist.github.com/swankjesse/dd91c0a8854e1559b00f5fc9c7bfae70 - [tls_configuration_history]: https://github.com/square/okhttp/wiki/TLS-Configuration-History + [tls_configuration_history]: TLS_CONFIGURATION_HISTORY.md [grpc_http2]: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md diff --git a/CONCURRENCY.md b/CONCURRENCY.md new file mode 100644 index 000000000..eeb0fa219 --- /dev/null +++ b/CONCURRENCY.md @@ -0,0 +1,98 @@ +Concurrency +=========== + +This document describes the concurrency considerations for http/2 connections and the connection pool within OkHttp. + +## HTTP/2 Connections + +The HttpURLConnection API is a blocking API. You make a blocking write to send a request, and a blocking read to receive the response. + +#### Blocking APIs + +Blocking APIs are convenient because you get top-to-bottom procedural code without indirection. Network calls work like regular method calls: ask for data and it is returned. If the request fails, you get a stacktrace right were the call was made. + +Blocking APIs may be inefficient because you hold a thread idle while waiting on the network. Threads are expensive because they have both a memory overhead and a context-switching overhead. + +#### Framed protocols + +Framed protocols like http/2 don't lend themselves to blocking APIs. Each application-layer thread wants to do blocking I/O for a specific stream, but the streams are multiplexed on the socket. You can't just talk to the socket, you need to cooperate with the other application-layer threads that you're sharing it with. + +Framing rules make it impractical to implement http/2 correctly on a single blocking thread. The flow-control features introduce feedback between reads and writes, requiring writes to acknowledge reads and reads to throttle writes. + +In OkHttp we expose a blocking API over a framed protocol. This document explains the code and policy that makes that work. + +### Threads + +#### Application's calling thread + +The application-layer must block on writing I/O. We can't return from a write until we've pushed its bytes onto the socket. Otherwise, if the write fails we are unable to deliver its IOException to the application. We would have told the application layer that the write succeeded, but it didn't! + +The application-layer can also do blocking reads. If the application asks to read and there's nothing available, we need to hold that thread until either the bytes arrive, the stream is closed, or a timeout elapses. If we get bytes but there's nobody asking for them, we buffer them. We don't consider bytes as delivered for flow control until they're consumed by the application. + +Consider an application streaming a video over http/2. Perhaps the user pauses the video and the application stops reading bytes from this stream. The buffer will fill up, and flow control prevents the server from sending more data on this stream. When the user unpauses her video the buffer drains, the read is acknowledged, and the server proceeds to stream data. + +#### Shared reader thread + +We can't rely on application threads to read data from the socket. Application threads are transient: sometimes they're reading and writing and sometimes they're off doing application-layer things. But the socket is permanent, and it needs constant attention: we dispatch all incoming frames so the connection is good-to-go when the application layer needs it. + +So we have a dedicated thread for every socket that just reads frames and dispatches them. + +The reader thread must never run application-layer code. Otherwise one slow stream can hold up the entire connection. + +Similarly, the reader thread must never block on writing because this can deadlock the connection. Consider a client and server that both violate this rule. If you get unlucky, they could fill up their TCP buffers (so that writes block) and then use their reader threads to write a frame. Nobody is reading on either end, and the buffers are never drained. + +#### Do-stuff-later pool + +Sometimes there's an action required like calling the application layer or responding to a ping, and the thread discovering the action is not the thread that should do the work. We enqueue a runnable on this executor and it gets handled by one of the executor's threads. + +### Locks + +We have 3 different things that we synchronize on. + +#### Http2Connection + +This lock guards internal state of each connection. This lock is never held for blocking operations. That means that we acquire the lock, read or write a few fields and release the lock. No I/O and no application-layer callbacks. + +#### Http2Stream + +This lock guards the internal state of each stream. As above, it is never held for blocking operations. When we need to hold an application thread to block a read, we use wait/notify on this lock. This works because the lock is released while `wait()` is waiting. + +#### Http2Writer + +Socket writes are guarded by the Http2Writer. Only one stream can write at a time so that messages are not interleaved. Writes are either made by application-layer threads or the do-stuff-later pool. + +### Holding multiple locks + +You're allowed to take the Http2Connection lock while holding the Http2Writer lock. But not vice-versa. Because taking the Http2Writer lock can block. + +This is necessary for bookkeeping when creating new streams. Correct framing requires that stream IDs are sequential on the socket, so we need to bundle assigning the ID with sending the `SYN_STREAM` frame. + +## Connection Pool + +### Background + +A primary responsibility for any HTTP client is to efficiently manage network connections. Creating and establishing new connections require a fair amount of overhead and added latency. OkHttp will make every effort to reuse existing connections to avoid this overhead and added latency. + +Every OkHttpClient uses a connection pool. Its job is to maintain a reference to all open connections. When an HTTP request is started, OkHttp will attempt to reuse an existing connection from the pool. If there are no existing connections, a new one is created and put into the connection pool. For http/2, the connection can be reused immediately. For http/1, the request must be completed before it can be reused. + +Since HTTP requests frequently happen in parallel, the connection pool implementation must be thread-safe. + +### ConnectionPool, RealConnection, and StreamAllocation + +The primary classes involved with establishing, sharing and terminating connections are ConnectionPool, RealConnection and StreamAllocation. + +**ConnectionPool**: Manages reuse of HTTP and HTTP/2 connections for reduced latency. Every OkHttpClient has one, and its lifetime spans the lifetime of the OkHttpClient. + +**RealConnection**: The socket and streams of an HTTP and HTTP/2 connection. These are created on demand to fulfill HTTP requests. They may be reused for many HTTP request/response exchanges. Their lifetime is typically shorter than ConnectionPool. + +**StreamAllocation**: Coordinates the relationship between connections, streams and calls. These are created for a single HTTP request/response exchange. Their lifetime is typically shorter than RealConnection. + +### Locks + +A single lock is used to synchronize and guard the state of ConnectionPool, RealConnection and StreamAllocation. + +### ConnectionPool + +The fields in ConnectionPool, RealConnection and StreamAllocation are all guarded by the connection pool instance. This lock is never held while doing I/O (even closing a socket) to prevent contention. + +A single lock is preferred to avoid deadlock scenarios and the added overhead of aggregate lock/unlock that would occur if multiple locks were used. \ No newline at end of file diff --git a/CONNECTIONS.md b/CONNECTIONS.md new file mode 100644 index 000000000..a80e0b5cd --- /dev/null +++ b/CONNECTIONS.md @@ -0,0 +1,52 @@ +Connections +=========== + +Although you provide only the URL, OkHttp plans its connection to your webserver using three types: URL, Address, and Route. + +#### [URLs](http://square.github.io/okhttp/3.x/okhttp/okhttp3/HttpUrl.html) + +URLs (like `https://github.com/square/okhttp`) are fundamental to HTTP and the Internet. In addition to being a universal, decentralized naming scheme for everything on the web, they also specify how to access web resources. + +URLs are abstract: + + * They specify that the call may be plaintext (`http`) or encrypted (`https`), but not which cryptographic algorithms should be used. Nor do they specify how to verify the peer's certificates (the [HostnameVerifier](http://developer.android.com/reference/javax/net/ssl/HostnameVerifier.html)) or which certificates can be trusted (the [SSLSocketFactory](http://developer.android.com/reference/org/apache/http/conn/ssl/SSLSocketFactory.html)). + * They don't specify whether a specific proxy server should be used or how to authenticate with that proxy server. + +They're also concrete: each URL identifies a specific path (like `/square/okhttp`) and query (like `?q=sharks&lang=en`). Each webserver hosts many URLs. + +#### [Addresses](http://square.github.io/okhttp/3.x/okhttp/okhttp3/Address.html) + +Addresses specify a webserver (like `github.com`) and all of the **static** configuration necessary to connect to that server: the port number, HTTPS settings, and preferred network protocols (like HTTP/2 or SPDY). + +URLs that share the same address may also share the same underlying TCP socket connection. Sharing a connection has substantial performance benefits: lower latency, higher throughput (due to [TCP slow start](http://www.igvita.com/2011/10/20/faster-web-vs-tcp-slow-start/)) and conserved battery. OkHttp uses a [ConnectionPool](http://square.github.io/okhttp/3.x/okhttp/okhttp3/ConnectionPool.html) that automatically reuses HTTP/1.x connections and multiplexes HTTP/2 and SPDY connections. + +In OkHttp some fields of the address come from the URL (scheme, hostname, port) and the rest come from the [OkHttpClient](http://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html). + +#### [Routes](http://square.github.io/okhttp/3.x/okhttp/okhttp3/Route.html) + +Routes supply the **dynamic** information necessary to actually connect to a webserver. This is the specific IP address to attempt (as discovered by a DNS query), the exact proxy server to use (if a [ProxySelector](http://developer.android.com/reference/java/net/ProxySelector.html) is in use), and which version of TLS to negotiate (for HTTPS connections). + +There may be many routes for a single address. For example, a webserver that is hosted in multiple datacenters may yield multiple IP addresses in its DNS response. + +#### [Connections](http://square.github.io/okhttp/3.x/okhttp/okhttp3/Connection.html) + +When you request a URL with OkHttp, here's what it does: + + 1. It uses the URL and configured OkHttpClient to create an **address**. This address specifies how we'll connect to the webserver. + 2. It attempts to retrieve a connection with that address from the **connection pool**. + 3. If it doesn't find a connection in the pool, it selects a **route** to attempt. This usually means making a DNS request to get the server's IP addresses. It then selects a TLS version and proxy server if necessary. + 4. If it's a new route, it connects by building either a direct socket connection, a TLS tunnel (for HTTPS over an HTTP proxy), or a direct TLS connection. It does TLS handshakes as necessary. + 5. It sends the HTTP request and reads the response. + +If there's a problem with the connection, OkHttp will select another route and try again. This allows OkHttp to recover when a subset of a server's addresses are unreachable. It's also useful when a pooled connection is stale or if the attempted TLS version is unsupported. + +Once the response has been received, the connection will be returned to the pool so it can be reused for a future request. Connections are evicted from the pool after a period of inactivity. + + +---- + + + + + +
← CallsOkHttp User's GuideRecipes →
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..99e1e86cc --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,39 @@ +Contributing +============ + +Keeping the project small and stable limits our ability to accept new contributors. We are not +seeking new committers at this time, but some small contributions are welcome. + +If you've found a security problem, please follow our [bug bounty](BUG-BOUNTY.md) program. + +If you've found a bug, please contribute a failing test case so we can study and fix it. + +If you have a new feature idea, please build it in an external library. There are +[many libraries](WORKS_WITH_OKHTTP.md) that sit on top or hook in via existing APIs. If you build +something that integrates with OkHttp, tell us so that we can link it! + +Before code can be accepted all contributors must complete our +[Individual Contributor License Agreement (CLA)](https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1). + + +Code Contributions +------------------ + +Get working code on a personal branch with tests passing before you submit a PR: + +``` +./gradlew clean check +``` + +Please make every effort to follow existing conventions and style in order to keep the code as +readable as possible. + +Contribute code changes through GitHub by forking the repository and sending a pull request. We +squash all pull requests on merge. + + +Committer's Guides +------------------ + + * [Concurrency](CONCURRENCY.md) + * [Releasing](RELEASING.md) diff --git a/EVENTS.md b/EVENTS.md new file mode 100644 index 000000000..80180d68f --- /dev/null +++ b/EVENTS.md @@ -0,0 +1,248 @@ +Events +====== + +Events allow you to capture metrics on your application’s HTTP calls. Use events to monitor: + + * The size and frequency of the HTTP calls your application makes. If you’re making too many calls, or your calls are too large, you should know about it! + * The performance of these calls on the underlying network. If the network’s performance isn’t sufficient, you need to either improve the network or use less of it. + +### EventListener + +Subclass [EventListener](https://square.github.io/okhttp/3.x/okhttp/okhttp3/EventListener.html) and override methods for the events you are interested in. In a successful HTTP call with no redirects or retries the sequence of events is described by this flow. + +![Events Diagram](https://raw.githubusercontent.com/wiki/square/okhttp/events@2x.png) + +Here’s a [sample event listener](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PrintEventsNonConcurrent.java) that prints each event with a timestamp. + +```java +class PrintingEventListener extends EventListener { + private long callStartNanos; + + private void printEvent(String name) { + long nowNanos = System.nanoTime(); + if (name.equals("callStart")) { + callStartNanos = nowNanos; + } + long elapsedNanos = nowNanos - callStartNanos; + System.out.printf("%.3f %s%n", elapsedNanos / 1000000000d, name); + } + + @Override public void callStart(Call call) { + printEvent("callStart"); + } + + @Override public void callEnd(Call call) { + printEvent("callEnd"); + } + + @Override public void dnsStart(Call call, String domainName) { + printEvent("dnsStart"); + } + + @Override public void dnsEnd(Call call, String domainName, List inetAddressList) { + printEvent("dnsEnd"); + } + + ... +} +``` + +We make a couple calls: + +```java +Request request = new Request.Builder() + .url("https://publicobject.com/helloworld.txt") + .build(); + +System.out.println("REQUEST 1 (new connection)"); +try (Response response = client.newCall(request).execute()) { + // Consume and discard the response body. + response.body().source().readByteString(); +} + +System.out.println("REQUEST 2 (pooled connection)"); +try (Response response = client.newCall(request).execute()) { + // Consume and discard the response body. + response.body().source().readByteString(); +} +``` + +And the listener prints the corresponding events: + +``` +REQUEST 1 (new connection) +0.000 callStart +0.010 dnsStart +0.017 dnsEnd +0.025 connectStart +0.117 secureConnectStart +0.586 secureConnectEnd +0.586 connectEnd +0.587 connectionAcquired +0.588 requestHeadersStart +0.590 requestHeadersEnd +0.591 responseHeadersStart +0.675 responseHeadersEnd +0.676 responseBodyStart +0.679 responseBodyEnd +0.679 connectionReleased +0.680 callEnd +REQUEST 2 (pooled connection) +0.000 callStart +0.001 connectionAcquired +0.001 requestHeadersStart +0.001 requestHeadersEnd +0.002 responseHeadersStart +0.082 responseHeadersEnd +0.082 responseBodyStart +0.082 responseBodyEnd +0.083 connectionReleased +0.083 callEnd +``` + +Notice how no connect events are fired for the second call. It reused the connection from the first request for dramatically better performance. + +### EventListener.Factory + +In the preceding example we used a field, `callStartNanos`, to track the elapsed time of each event. This is handy, but it won’t work if multiple calls are executing concurrently. To accommodate this, use a `Factory` to create a new `EventListener` instance for each `Call`. This allows each listener to keep call-specific state. + +This [sample factory](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PrintEvents.java) creates a unique ID for each call and uses that ID to differentiate calls in log messages. + +```java +class PrintingEventListener extends EventListener { + public static final Factory FACTORY = new Factory() { + final AtomicLong nextCallId = new AtomicLong(1L); + + @Override public EventListener create(Call call) { + long callId = nextCallId.getAndIncrement(); + System.out.printf("%04d %s%n", callId, call.request().url()); + return new PrintingEventListener(callId, System.nanoTime()); + } + }; + + final long callId; + final long callStartNanos; + + public PrintingEventListener(long callId, long callStartNanos) { + this.callId = callId; + this.callStartNanos = callStartNanos; + } + + private void printEvent(String name) { + long elapsedNanos = System.nanoTime() - callStartNanos; + System.out.printf("%04d %.3f %s%n", callId, elapsedNanos / 1000000000d, name); + } + + @Override public void callStart(Call call) { + printEvent("callStart"); + } + + @Override public void callEnd(Call call) { + printEvent("callEnd"); + } + + ... +} +``` + +We can use this listener to race a pair of concurrent HTTP requests: + +```java +Request washingtonPostRequest = new Request.Builder() + .url("https://www.washingtonpost.com/") + .build(); +client.newCall(washingtonPostRequest).enqueue(new Callback() { + ... +}); + +Request newYorkTimesRequest = new Request.Builder() + .url("https://www.nytimes.com/") + .build(); +client.newCall(newYorkTimesRequest).enqueue(new Callback() { + ... +}); +``` + +Running this race over home WiFi shows the Times (`0002`) completes just slightly sooner than the Post (`0001`): + +``` +0001 https://www.washingtonpost.com/ +0001 0.000 callStart +0002 https://www.nytimes.com/ +0002 0.000 callStart +0002 0.010 dnsStart +0001 0.013 dnsStart +0001 0.022 dnsEnd +0002 0.019 dnsEnd +0001 0.028 connectStart +0002 0.025 connectStart +0002 0.072 secureConnectStart +0001 0.075 secureConnectStart +0001 0.386 secureConnectEnd +0002 0.390 secureConnectEnd +0002 0.400 connectEnd +0001 0.403 connectEnd +0002 0.401 connectionAcquired +0001 0.404 connectionAcquired +0001 0.406 requestHeadersStart +0002 0.403 requestHeadersStart +0001 0.414 requestHeadersEnd +0002 0.411 requestHeadersEnd +0002 0.412 responseHeadersStart +0001 0.415 responseHeadersStart +0002 0.474 responseHeadersEnd +0002 0.475 responseBodyStart +0001 0.554 responseHeadersEnd +0001 0.555 responseBodyStart +0002 0.554 responseBodyEnd +0002 0.554 connectionReleased +0002 0.554 callEnd +0001 0.624 responseBodyEnd +0001 0.624 connectionReleased +0001 0.624 callEnd +``` + +The `EventListener.Factory` also makes it possible to limit metrics to a subset of calls. This one captures metrics on a random 10%: + +```java +class MetricsEventListener extends EventListener { + private static final Factory FACTORY = new Factory() { + @Override public EventListener create(Call call) { + if (Math.random() < 0.10) { + return new MetricsEventListener(call); + } else { + return EventListener.NONE; + } + } + }; + + ... +} +``` + +### Events with Failures + +When an operation fails, a failure method is called. This is `connectFailed()` for failures while building a connection to the server, and `callFailed()` when the HTTP call fails permanently. When a failure happens it is possible that a `start` event won’t have a corresponding `end` event. + +![Events Diagram](https://raw.githubusercontent.com/wiki/square/okhttp/events_with_failures@2x.png) + +### Events with Retries and Follow-Ups + +OkHttp is resilient and can automatically recover from some connectivity failures. In this case, the `connectFailed()` event is not terminal and not followed by `callFailed()`. Event listeners will receive multiple events of the same type when retries are attempted. + +A single HTTP call may require follow-up requests to be made to handle authentication challenges, redirects, and HTTP-layer timeouts. In such cases multiple connections, requests, and responses may be attempted. Follow-ups are another reason a single call may trigger multiple events of the same type. + +![Events Diagram](https://raw.githubusercontent.com/wiki/square/okhttp/events_with_failures_and_retries@2x.png) + +### Availability + +Events is available as a public API in OkHttp 3.11. Future releases may introduce new event types; you will need to override the corresponding methods to handle them. + + +---- + + + + + +
← HTTPSOkHttp User's GuideHome →
diff --git a/HTTPS.md b/HTTPS.md new file mode 100644 index 000000000..1338b6dc6 --- /dev/null +++ b/HTTPS.md @@ -0,0 +1,114 @@ +HTTPS +===== + +OkHttp attempts to balance two competing concerns: + + * **Connectivity** to as many hosts as possible. That includes advanced hosts that run the latest versions of [boringssl](https://boringssl.googlesource.com/boringssl/) and less out of date hosts running older versions of [OpenSSL](https://www.openssl.org/). + * **Security** of the connection. This includes verification of the remote webserver with certificates and the privacy of data exchanged with strong ciphers. + +When negotiating a connection to an HTTPS server, OkHttp needs to know which [TLS versions](http://square.github.io/okhttp/3.x/okhttp/okhttp3/TlsVersion.html) and [cipher suites](http://square.github.io/okhttp/3.x/okhttp/okhttp3/CipherSuite.html) to offer. A client that wants to maximize connectivity would include obsolete TLS versions and weak-by-design cipher suites. A strict client that wants to maximize security would be limited to only the latest TLS version and strongest cipher suites. + +Specific security vs. connectivity decisions are implemented by [ConnectionSpec](http://square.github.io/okhttp/3.x/okhttp/okhttp3/ConnectionSpec.html). OkHttp includes four built-in connection specs: + + * `RESTRICTED_TLS` is a secure configuration, intended to meet stricter compliance requirements. + * `MODERN_TLS` is a secure configuration that connects to modern HTTPS servers. + * `COMPATIBLE_TLS` is a secure configuration that connects to secure–but not current–HTTPS servers. + * `CLEARTEXT` is an insecure configuration that is used for `http://` URLs. + +These loosely follow the model set in [Google Cloud Policies](https://cloud.google.com/load-balancing/docs/ssl-policies-concepts). We [track changes](TLS_CONFIGURATION_HISTORY.md) to this policy. + +By default, OkHttp will attempt a `MODERN_TLS` connection. However by configuring the client connectionSpecs you can allow a fall back to `COMPATIBLE_TLS` connection if the modern configuration fails. + +```java +OkHttpClient client = new OkHttpClient.Builder() + .connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS)) + .build(); +``` + +The TLS versions and cipher suites in each spec can change with each release. For example, in OkHttp 2.2 we dropped support for SSL 3.0 in response to the [POODLE](http://googleonlinesecurity.blogspot.ca/2014/10/this-poodle-bites-exploiting-ssl-30.html) attack. And in OkHttp 2.3 we dropped support for [RC4](http://en.wikipedia.org/wiki/RC4#Security). As with your desktop web browser, staying up-to-date with OkHttp is the best way to stay secure. + +You can build your own connection spec with a custom set of TLS versions and cipher suites. For example, this configuration is limited to three highly-regarded cipher suites. Its drawback is that it requires Android 5.0+ and a similarly current webserver. + +```java +ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .tlsVersions(TlsVersion.TLS_1_2) + .cipherSuites( + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) + .build(); + +OkHttpClient client = new OkHttpClient.Builder() + .connectionSpecs(Collections.singletonList(spec)) + .build(); +``` + +#### [Certificate Pinning](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CertificatePinning.java) + +By default, OkHttp trusts the certificate authorities of the host platform. This strategy maximizes connectivity, but it is subject to certificate authority attacks such as the [2011 DigiNotar attack](http://www.computerworld.com/article/2510951/cybercrime-hacking/hackers-spied-on-300-000-iranians-using-fake-google-certificate.html). It also assumes your HTTPS servers’ certificates are signed by a certificate authority. + +Use [CertificatePinner](http://square.github.io/okhttp/3.x/okhttp/okhttp3/CertificatePinner.html) to restrict which certificates and certificate authorities are trusted. Certificate pinning increases security, but limits your server team’s abilities to update their TLS certificates. **Do not use certificate pinning without the blessing of your server’s TLS administrator!** + +``` + public CertificatePinning() { + client = new OkHttpClient.Builder() + .certificatePinner(new CertificatePinner.Builder() + .add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=") + .build()) + .build(); + } + + public void run() throws Exception { + Request request = new Request.Builder() + .url("https://publicobject.com/robots.txt") + .build(); + + Response response = client.newCall(request).execute(); + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + for (Certificate certificate : response.handshake().peerCertificates()) { + System.out.println(CertificatePinner.pin(certificate)); + } + } +``` + +#### [Customizing Trusted Certificates](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java) + +The full code sample shows how to replace the host platform’s certificate authorities with your own set. As above, **do not use custom certificates without the blessing of your server’s TLS administrator!** + +``` + private final OkHttpClient client; + + public CustomTrust() { + SSLContext sslContext = sslContextForTrustedCertificates(trustedCertificatesInputStream()); + client = new OkHttpClient.Builder() + .sslSocketFactory(sslContext.getSocketFactory()) + .build(); + } + + public void run() throws Exception { + Request request = new Request.Builder() + .url("https://publicobject.com/helloworld.txt") + .build(); + + Response response = client.newCall(request).execute(); + System.out.println(response.body().string()); + } + + private InputStream trustedCertificatesInputStream() { + ... // Full source omitted. See sample. + } + + public SSLContext sslContextForTrustedCertificates(InputStream in) { + ... // Full source omitted. See sample. + } +``` + + +---- + + + + + +
← InterceptorsOkHttp User's GuideEvents →
diff --git a/INTERCEPTORS.md b/INTERCEPTORS.md new file mode 100644 index 000000000..00a4d6a55 --- /dev/null +++ b/INTERCEPTORS.md @@ -0,0 +1,206 @@ +Interceptors +============ + +Interceptors are a powerful mechanism that can monitor, rewrite, and retry calls. Here's a simple interceptor that logs the outgoing request and the incoming response. + +```java +class LoggingInterceptor implements Interceptor { + @Override public Response intercept(Interceptor.Chain chain) throws IOException { + Request request = chain.request(); + + long t1 = System.nanoTime(); + logger.info(String.format("Sending request %s on %s%n%s", + request.url(), chain.connection(), request.headers())); + + Response response = chain.proceed(request); + + long t2 = System.nanoTime(); + logger.info(String.format("Received response for %s in %.1fms%n%s", + response.request().url(), (t2 - t1) / 1e6d, response.headers())); + + return response; + } +} +``` + +A call to `chain.proceed(request)` is a critical part of each interceptor’s implementation. This simple-looking method is where all the HTTP work happens, producing a response to satisfy the request. + +Interceptors can be chained. Suppose you have both a compressing interceptor and a checksumming interceptor: you'll need to decide whether data is compressed and then checksummed, or checksummed and then compressed. OkHttp uses lists to track interceptors, and interceptors are called in order. + +![Interceptors Diagram](https://raw.githubusercontent.com/wiki/square/okhttp/interceptors@2x.png) + +#### Application Interceptors + +Interceptors are registered as either _application_ or _network_ interceptors. We'll use the `LoggingInterceptor` defined above to show the difference. + +Register an _application_ interceptor by calling `addInterceptor()` on `OkHttpClient.Builder`: + +```java +OkHttpClient client = new OkHttpClient.Builder() + .addInterceptor(new LoggingInterceptor()) + .build(); + +Request request = new Request.Builder() + .url("http://www.publicobject.com/helloworld.txt") + .header("User-Agent", "OkHttp Example") + .build(); + +Response response = client.newCall(request).execute(); +response.body().close(); +``` + +The URL `http://www.publicobject.com/helloworld.txt` redirects to `https://publicobject.com/helloworld.txt`, and OkHttp follows this redirect automatically. Our application interceptor is called **once** and the response returned from `chain.proceed()` has the redirected response: + +``` +INFO: Sending request http://www.publicobject.com/helloworld.txt on null +User-Agent: OkHttp Example + +INFO: Received response for https://publicobject.com/helloworld.txt in 1179.7ms +Server: nginx/1.4.6 (Ubuntu) +Content-Type: text/plain +Content-Length: 1759 +Connection: keep-alive +``` + +We can see that we were redirected because `response.request().url()` is different from `request.url()`. The two log statements log two different URLs. + +#### Network Interceptors + +Registering a network interceptor is quite similar. Call `addNetworkInterceptor()` instead of `addInterceptor()`: + +```java +OkHttpClient client = new OkHttpClient.Builder() + .addNetworkInterceptor(new LoggingInterceptor()) + .build(); + +Request request = new Request.Builder() + .url("http://www.publicobject.com/helloworld.txt") + .header("User-Agent", "OkHttp Example") + .build(); + +Response response = client.newCall(request).execute(); +response.body().close(); +``` + +When we run this code, the interceptor runs twice. Once for the initial request to `http://www.publicobject.com/helloworld.txt`, and another for the redirect to `https://publicobject.com/helloworld.txt`. + +``` +INFO: Sending request http://www.publicobject.com/helloworld.txt on Connection{www.publicobject.com:80, proxy=DIRECT hostAddress=54.187.32.157 cipherSuite=none protocol=http/1.1} +User-Agent: OkHttp Example +Host: www.publicobject.com +Connection: Keep-Alive +Accept-Encoding: gzip + +INFO: Received response for http://www.publicobject.com/helloworld.txt in 115.6ms +Server: nginx/1.4.6 (Ubuntu) +Content-Type: text/html +Content-Length: 193 +Connection: keep-alive +Location: https://publicobject.com/helloworld.txt + +INFO: Sending request https://publicobject.com/helloworld.txt on Connection{publicobject.com:443, proxy=DIRECT hostAddress=54.187.32.157 cipherSuite=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA protocol=http/1.1} +User-Agent: OkHttp Example +Host: publicobject.com +Connection: Keep-Alive +Accept-Encoding: gzip + +INFO: Received response for https://publicobject.com/helloworld.txt in 80.9ms +Server: nginx/1.4.6 (Ubuntu) +Content-Type: text/plain +Content-Length: 1759 +Connection: keep-alive +``` + +The network requests also contain more data, such as the `Accept-Encoding: gzip` header added by OkHttp to advertise support for response compression. The network interceptor's `Chain` has a non-null `Connection` that can be used to interrogate the IP address and TLS configuration that were used to connect to the webserver. + +#### Choosing between application and network interceptors + +Each interceptor chain has relative merits. + +**Application interceptors** + + * Don't need to worry about intermediate responses like redirects and retries. + * Are always invoked once, even if the HTTP response is served from the cache. + * Observe the application's original intent. Unconcerned with OkHttp-injected headers like `If-None-Match`. + * Permitted to short-circuit and not call `Chain.proceed()`. + * Permitted to retry and make multiple calls to `Chain.proceed()`. + +**Network Interceptors** + + * Able to operate on intermediate responses like redirects and retries. + * Not invoked for cached responses that short-circuit the network. + * Observe the data just as it will be transmitted over the network. + * Access to the `Connection` that carries the request. + +#### Rewriting Requests + +Interceptors can add, remove, or replace request headers. They can also transform the body of those requests that have one. For example, you can use an application interceptor to add request body compression if you're connecting to a webserver known to support it. + +```java +/** This interceptor compresses the HTTP request body. Many webservers can't handle this! */ +final class GzipRequestInterceptor implements Interceptor { + @Override public Response intercept(Interceptor.Chain chain) throws IOException { + Request originalRequest = chain.request(); + if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) { + return chain.proceed(originalRequest); + } + + Request compressedRequest = originalRequest.newBuilder() + .header("Content-Encoding", "gzip") + .method(originalRequest.method(), gzip(originalRequest.body())) + .build(); + return chain.proceed(compressedRequest); + } + + private RequestBody gzip(final RequestBody body) { + return new RequestBody() { + @Override public MediaType contentType() { + return body.contentType(); + } + + @Override public long contentLength() { + return -1; // We don't know the compressed length in advance! + } + + @Override public void writeTo(BufferedSink sink) throws IOException { + BufferedSink gzipSink = Okio.buffer(new GzipSink(sink)); + body.writeTo(gzipSink); + gzipSink.close(); + } + }; + } +} +``` + +#### Rewriting Responses + +Symmetrically, interceptors can rewrite response headers and transform the response body. This is generally more dangerous than rewriting request headers because it may violate the webserver's expectations! + +If you're in a tricky situation and prepared to deal with the consequences, rewriting response headers is a powerful way to work around problems. For example, you can fix a server's misconfigured `Cache-Control` response header to enable better response caching: + +```java +/** Dangerous interceptor that rewrites the server's cache-control header. */ +private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { + @Override public Response intercept(Interceptor.Chain chain) throws IOException { + Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .header("Cache-Control", "max-age=60") + .build(); + } +}; +``` + +Typically this approach works best when it complements a corresponding fix on the webserver! + +#### Availability + +OkHttp's interceptors require OkHttp 2.2 or better. Unfortunately, interceptors do not work with `OkUrlFactory`, or the libraries that build on it, including [Retrofit](http://square.github.io/retrofit/) ≤ 1.8 and [Picasso](http://square.github.io/picasso/) ≤ 2.4. + + +---- + + + + + +
← RecipesOkHttp User's GuideHTTPS →
diff --git a/README.md b/README.md index 1f23ee4a7..db443e501 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,21 @@ OkHttp ====== -An HTTP & HTTP/2 client for Android and Java applications. For more information see [the -website][website] and [the wiki][wiki]. +An HTTP & HTTP/2 client for Android and Java applications. + +Docs +---- + + * [**User's Guide**](CALLS.md) (includes [Calls](CALLS.md), [Connections](CONNECTIONS.md), + [Recipes](RECIPES.md), [Interceptors](INTERCEPTORS.md), [HTTPS](HTTPS.md), [Events](EVENTS.md)) + * [**4.x API**][4x_okhttp] (also [dnsoverhttps][4x_dnsoverhttps], + [logging-interceptor][4x_logging], [sse][4x_sse], [tls][4x_tls], + [urlconnection][4x_urlconnection], [mockwebserver][4x_mockwebserver]) + * [**3.x API**][3x_okhttp] (also [dnsoverhttps][3x_dnsoverhttps], + [logging-interceptor][3x_logging], [sse][3x_sse], [tls][3x_tls], + [urlconnection][3x_urlconnection], [mockwebserver][3x_mockwebserver]) + * [**StackOverflow**](http://stackoverflow.com/questions/tagged/okhttp?sort=active) + * [**Works with OkHttp**](WORKS_WITH_OKHTTP.md) Requirements @@ -30,9 +43,11 @@ The OkHttp 3.12.x branch supports Android 2.3+ (API level 9+) and Java 7+. These support for TLS 1.2 and should not be used. But because upgrading is difficult we will backport critical fixes to the [3.12.x branch][okhttp_312x] through December 31, 2020. -Download +Releases -------- +Our [change log](CHANGELOG.md) has release history. + ```kotlin implementation("com.squareup.okhttp3:okhttp:3.14.2") ``` @@ -43,11 +58,7 @@ Snapshot builds are [available][snap]. MockWebServer ------------- -A library for testing HTTP, HTTPS, and HTTP/2 clients. - -MockWebServer coupling with OkHttp is essential for proper testing of HTTP/2 so that code can be shared. - -### Download +OkHttp includes a library for testing HTTP, HTTPS, and HTTP/2 clients. ```kotlin testImplementation("com.squareup.okhttp3:mockwebserver:3.14.2") @@ -81,7 +92,21 @@ License [okhttp_312x]: https://github.com/square/okhttp/tree/okhttp_3.12.x [okio]: https://github.com/square/okio/ [snap]: https://oss.sonatype.org/content/repositories/snapshots/ - [tls_history]: https://github.com/square/okhttp/wiki/TLS-Configuration-History + [tls_history]: TLS_CONFIGURATION_HISTORY.md [website]: https://square.github.io/okhttp - [wiki]: https://github.com/square/okhttp/wiki [okhttp3_pro]: https://github.com/square/okhttp/blob/master/okhttp/src/main/resources/META-INF/proguard/okhttp3.pro + + [4x_okhttp]: http://square.github.io/okhttp/4.x/okhttp/okhttp/okhttp3/ + [4x_dnsoverhttps]: http://square.github.io/okhttp/4.x/okhttp-dnsoverhttps/okhttp-dnsoverhttps/okhttp3.dnsoverhttps/ + [4x_logging]: http://square.github.io/okhttp/4.x/logging-interceptor/okhttp-logging-interceptor/okhttp3.logging/ + [4x_sse]: http://square.github.io/okhttp/4.x/okhttp-sse/okhttp-sse/okhttp3.sse/ + [4x_tls]: http://square.github.io/okhttp/4.x/okhttp-tls/okhttp-tls/okhttp3.tls/ + [4x_urlconnection]: http://square.github.io/okhttp/4.x/okhttp-urlconnection/okhttp-urlconnection/okhttp3/ + [4x_mockwebserver]: http://square.github.io/okhttp/4.x/mockwebserver/mockwebserver/okhttp3.mockwebserver/ + [3x_okhttp]: http://square.github.io/okhttp/3.x/okhttp/ + [3x_dnsoverhttps]: http://square.github.io/okhttp/3.x/okhttp-dnsoverhttps/ + [3x_logging]: http://square.github.io/okhttp/3.x/logging-interceptor/ + [3x_sse]: http://square.github.io/okhttp/3.x/okhttp-sse/ + [3x_tls]: http://square.github.io/okhttp/3.x/okhttp-tls/ + [3x_urlconnection]: http://square.github.io/okhttp/3.x/okhttp-urlconnection/ + [3x_mockwebserver]: http://square.github.io/okhttp/3.x/mockwebserver/ \ No newline at end of file diff --git a/RECIPES.md b/RECIPES.md new file mode 100644 index 000000000..664da0435 --- /dev/null +++ b/RECIPES.md @@ -0,0 +1,520 @@ +Recipes +======= + +We've written some recipes that demonstrate how to solve common problems with OkHttp. Read through them to learn about how everything works together. Cut-and-paste these examples freely; that's what they're for. + +#### [Synchronous Get](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/SynchronousGet.java) + +Download a file, print its headers, and print its response body as a string. + +The `string()` method on response body is convenient and efficient for small documents. But if the response body is large (greater than 1 MiB), avoid `string()` because it will load the entire document into memory. In that case, prefer to process the body as a stream. + +```java + private final OkHttpClient client = new OkHttpClient(); + + public void run() throws Exception { + Request request = new Request.Builder() + .url("https://publicobject.com/helloworld.txt") + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + Headers responseHeaders = response.headers(); + for (int i = 0; i < responseHeaders.size(); i++) { + System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i)); + } + + System.out.println(response.body().string()); + } + } +``` + +#### [Asynchronous Get](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/AsynchronousGet.java) + +Download a file on a worker thread, and get called back when the response is readable. The callback is made after the response headers are ready. Reading the response body may still block. OkHttp doesn't currently offer asynchronous APIs to receive a response body in parts. + +```java + private final OkHttpClient client = new OkHttpClient(); + + public void run() throws Exception { + Request request = new Request.Builder() + .url("http://publicobject.com/helloworld.txt") + .build(); + + client.newCall(request).enqueue(new Callback() { + @Override public void onFailure(Call call, IOException e) { + e.printStackTrace(); + } + + @Override public void onResponse(Call call, Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + Headers responseHeaders = response.headers(); + for (int i = 0, size = responseHeaders.size(); i < size; i++) { + System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i)); + } + + System.out.println(responseBody.string()); + } + } + }); + } +``` + +#### [Accessing Headers](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/AccessHeaders.java) + +Typically HTTP headers work like a `Map`: each field has one value or none. But some headers permit multiple values, like Guava's [Multimap](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Multimap.html). For example, it's legal and common for an HTTP response to supply multiple `Vary` headers. OkHttp's APIs attempt to make both cases comfortable. + +When writing request headers, use `header(name, value)` to set the only occurrence of `name` to `value`. If there are existing values, they will be removed before the new value is added. Use `addHeader(name, value)` to add a header without removing the headers already present. + +When reading response a header, use `header(name)` to return the _last_ occurrence of the named value. Usually this is also the only occurrence! If no value is present, `header(name)` will return null. To read all of a field's values as a list, use `headers(name)`. + +To visit all headers, use the `Headers` class which supports access by index. + +```java + private final OkHttpClient client = new OkHttpClient(); + + public void run() throws Exception { + Request request = new Request.Builder() + .url("https://api.github.com/repos/square/okhttp/issues") + .header("User-Agent", "OkHttp Headers.java") + .addHeader("Accept", "application/json; q=0.5") + .addHeader("Accept", "application/vnd.github.v3+json") + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + System.out.println("Server: " + response.header("Server")); + System.out.println("Date: " + response.header("Date")); + System.out.println("Vary: " + response.headers("Vary")); + } + } +``` + +#### [Posting a String](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PostString.java) + +Use an HTTP POST to send a request body to a service. This example posts a markdown document to a web service that renders markdown as HTML. Because the entire request body is in memory simultaneously, avoid posting large (greater than 1 MiB) documents using this API. + +```java + public static final MediaType MEDIA_TYPE_MARKDOWN + = MediaType.parse("text/x-markdown; charset=utf-8"); + + private final OkHttpClient client = new OkHttpClient(); + + public void run() throws Exception { + String postBody = "" + + "Releases\n" + + "--------\n" + + "\n" + + " * _1.0_ May 6, 2013\n" + + " * _1.1_ June 15, 2013\n" + + " * _1.2_ August 11, 2013\n"; + + Request request = new Request.Builder() + .url("https://api.github.com/markdown/raw") + .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody)) + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + System.out.println(response.body().string()); + } + } +``` + +#### [Post Streaming](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PostStreaming.java) + +Here we `POST` a request body as a stream. The content of this request body is being generated as it's being written. This example streams directly into the [Okio](https://github.com/square/okio) buffered sink. Your programs may prefer an `OutputStream`, which you can get from `BufferedSink.outputStream()`. + +```java + public static final MediaType MEDIA_TYPE_MARKDOWN + = MediaType.parse("text/x-markdown; charset=utf-8"); + + private final OkHttpClient client = new OkHttpClient(); + + public void run() throws Exception { + RequestBody requestBody = new RequestBody() { + @Override public MediaType contentType() { + return MEDIA_TYPE_MARKDOWN; + } + + @Override public void writeTo(BufferedSink sink) throws IOException { + sink.writeUtf8("Numbers\n"); + sink.writeUtf8("-------\n"); + for (int i = 2; i <= 997; i++) { + sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i))); + } + } + + private String factor(int n) { + for (int i = 2; i < n; i++) { + int x = n / i; + if (x * i == n) return factor(x) + " × " + i; + } + return Integer.toString(n); + } + }; + + Request request = new Request.Builder() + .url("https://api.github.com/markdown/raw") + .post(requestBody) + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + System.out.println(response.body().string()); + } + } +``` + +#### [Posting a File](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PostFile.java) + +It's easy to use a file as a request body. + +```java + public static final MediaType MEDIA_TYPE_MARKDOWN + = MediaType.parse("text/x-markdown; charset=utf-8"); + + private final OkHttpClient client = new OkHttpClient(); + + public void run() throws Exception { + File file = new File("README.md"); + + Request request = new Request.Builder() + .url("https://api.github.com/markdown/raw") + .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file)) + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + System.out.println(response.body().string()); + } + } +``` + +#### [Posting form parameters](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PostForm.java) + +Use `FormBody.Builder` to build a request body that works like an HTML `
` tag. Names and values will be encoded using an HTML-compatible form URL encoding. + +```java + private final OkHttpClient client = new OkHttpClient(); + + public void run() throws Exception { + RequestBody formBody = new FormBody.Builder() + .add("search", "Jurassic Park") + .build(); + Request request = new Request.Builder() + .url("https://en.wikipedia.org/w/index.php") + .post(formBody) + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + System.out.println(response.body().string()); + } + } +``` + +#### [Posting a multipart request](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PostMultipart.java) + +`MultipartBody.Builder` can build sophisticated request bodies compatible with HTML file upload forms. Each part of a multipart request body is itself a request body, and can define its own headers. If present, these headers should describe the part body, such as its `Content-Disposition`. The `Content-Length` and `Content-Type` headers are added automatically if they're available. + +```java + /** + * The imgur client ID for OkHttp recipes. If you're using imgur for anything other than running + * these examples, please request your own client ID! https://api.imgur.com/oauth2 + */ + private static final String IMGUR_CLIENT_ID = "..."; + private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png"); + + private final OkHttpClient client = new OkHttpClient(); + + public void run() throws Exception { + // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image + RequestBody requestBody = new MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart("title", "Square Logo") + .addFormDataPart("image", "logo-square.png", + RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png"))) + .build(); + + Request request = new Request.Builder() + .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID) + .url("https://api.imgur.com/3/image") + .post(requestBody) + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + System.out.println(response.body().string()); + } + } +``` + +#### [Parse a JSON Response With Moshi](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/ParseResponseWithMoshi.java) + +[Moshi](https://github.com/square/moshi) is a handy API for converting between JSON and Java objects. Here we're using it to decode a JSON response from a GitHub API. + +Note that `ResponseBody.charStream()` uses the `Content-Type` response header to select which charset to use when decoding the response body. It defaults to `UTF-8` if no charset is specified. + +```java + private final OkHttpClient client = new OkHttpClient(); + private final Moshi moshi = new Moshi.Builder().build(); + private final JsonAdapter gistJsonAdapter = moshi.adapter(Gist.class); + + public void run() throws Exception { + Request request = new Request.Builder() + .url("https://api.github.com/gists/c2a7c39532239ff261be") + .build(); + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + Gist gist = gistJsonAdapter.fromJson(response.body().source()); + + for (Map.Entry entry : gist.files.entrySet()) { + System.out.println(entry.getKey()); + System.out.println(entry.getValue().content); + } + } + } + + static class Gist { + Map files; + } + + static class GistFile { + String content; + } +``` + +#### [Response Caching](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CacheResponse.java) + +To cache responses, you'll need a cache directory that you can read and write to, and a limit on the cache's size. The cache directory should be private, and untrusted applications should not be able to read its contents! + +It is an error to have multiple caches accessing the same cache directory simultaneously. Most applications should call `new OkHttpClient()` exactly once, configure it with their cache, and use that same instance everywhere. Otherwise the two cache instances will stomp on each other, corrupt the response cache, and possibly crash your program. + +Response caching uses HTTP headers for all configuration. You can add request headers like `Cache-Control: max-stale=3600` and OkHttp's cache will honor them. Your webserver configures how long responses are cached with its own response headers, like `Cache-Control: max-age=9600`. There are cache headers to force a cached response, force a network response, or force the network response to be validated with a conditional GET. + +```java + private final OkHttpClient client; + + public CacheResponse(File cacheDirectory) throws Exception { + int cacheSize = 10 * 1024 * 1024; // 10 MiB + Cache cache = new Cache(cacheDirectory, cacheSize); + + client = new OkHttpClient.Builder() + .cache(cache) + .build(); + } + + public void run() throws Exception { + Request request = new Request.Builder() + .url("http://publicobject.com/helloworld.txt") + .build(); + + String response1Body; + try (Response response1 = client.newCall(request).execute()) { + if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1); + + response1Body = response1.body().string(); + System.out.println("Response 1 response: " + response1); + System.out.println("Response 1 cache response: " + response1.cacheResponse()); + System.out.println("Response 1 network response: " + response1.networkResponse()); + } + + String response2Body; + try (Response response2 = client.newCall(request).execute()) { + if (!response2.isSuccessful()) throw new IOException("Unexpected code " + response2); + + response2Body = response2.body().string(); + System.out.println("Response 2 response: " + response2); + System.out.println("Response 2 cache response: " + response2.cacheResponse()); + System.out.println("Response 2 network response: " + response2.networkResponse()); + } + + System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body)); + } +``` +To prevent a response from using the cache, use [`CacheControl.FORCE_NETWORK`](http://square.github.io/okhttp/3.x/okhttp/okhttp3/CacheControl.html#FORCE_NETWORK). To prevent it from using the network, use [`CacheControl.FORCE_CACHE`](http://square.github.io/okhttp/3.x/okhttp/okhttp3/CacheControl.html#FORCE_CACHE). Be warned: if you use `FORCE_CACHE` and the response requires the network, OkHttp will return a `504 Unsatisfiable Request` response. + +#### [Canceling a Call](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CancelCall.java) + +Use `Call.cancel()` to stop an ongoing call immediately. If a thread is currently writing a request or reading a response, it will receive an `IOException`. Use this to conserve the network when a call is no longer necessary; for example when your user navigates away from an application. Both synchronous and asynchronous calls can be canceled. + +```java + private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + private final OkHttpClient client = new OkHttpClient(); + + public void run() throws Exception { + Request request = new Request.Builder() + .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay. + .build(); + + final long startNanos = System.nanoTime(); + final Call call = client.newCall(request); + + // Schedule a job to cancel the call in 1 second. + executor.schedule(new Runnable() { + @Override public void run() { + System.out.printf("%.2f Canceling call.%n", (System.nanoTime() - startNanos) / 1e9f); + call.cancel(); + System.out.printf("%.2f Canceled call.%n", (System.nanoTime() - startNanos) / 1e9f); + } + }, 1, TimeUnit.SECONDS); + + System.out.printf("%.2f Executing call.%n", (System.nanoTime() - startNanos) / 1e9f); + try (Response response = call.execute()) { + System.out.printf("%.2f Call was expected to fail, but completed: %s%n", + (System.nanoTime() - startNanos) / 1e9f, response); + } catch (IOException e) { + System.out.printf("%.2f Call failed as expected: %s%n", + (System.nanoTime() - startNanos) / 1e9f, e); + } + } +``` + +#### [Timeouts](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/ConfigureTimeouts.java) + +Use timeouts to fail a call when its peer is unreachable. Network partitions can be due to client connectivity problems, server availability problems, or anything between. OkHttp supports connect, read, and write timeouts. + +```java + private final OkHttpClient client; + + public ConfigureTimeouts() throws Exception { + client = new OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .build(); + } + + public void run() throws Exception { + Request request = new Request.Builder() + .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay. + .build(); + + try (Response response = client.newCall(request).execute()) { + System.out.println("Response completed: " + response); + } + } +``` + +#### [Per-call Configuration](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PerCallSettings.java) + +All the HTTP client configuration lives in `OkHttpClient` including proxy settings, timeouts, and caches. When you need to change the configuration of a single call, call `OkHttpClient.newBuilder()`. This returns a builder that shares the same connection pool, dispatcher, and configuration with the original client. In the example below, we make one request with a 500 ms timeout and another with a 3000 ms timeout. + +```java + private final OkHttpClient client = new OkHttpClient(); + + public void run() throws Exception { + Request request = new Request.Builder() + .url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay. + .build(); + + // Copy to customize OkHttp for this request. + OkHttpClient client1 = client.newBuilder() + .readTimeout(500, TimeUnit.MILLISECONDS) + .build(); + try (Response response = client1.newCall(request).execute()) { + System.out.println("Response 1 succeeded: " + response); + } catch (IOException e) { + System.out.println("Response 1 failed: " + e); + } + + // Copy to customize OkHttp for this request. + OkHttpClient client2 = client.newBuilder() + .readTimeout(3000, TimeUnit.MILLISECONDS) + .build(); + try (Response response = client2.newCall(request).execute()) { + System.out.println("Response 2 succeeded: " + response); + } catch (IOException e) { + System.out.println("Response 2 failed: " + e); + } + } +``` + +#### [Handling authentication](https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/Authenticate.java) + +OkHttp can automatically retry unauthenticated requests. When a response is `401 Not Authorized`, an `Authenticator` is asked to supply credentials. Implementations should build a new request that includes the missing credentials. If no credentials are available, return null to skip the retry. + +Use `Response.challenges()` to get the schemes and realms of any authentication challenges. When fulfilling a `Basic` challenge, use `Credentials.basic(username, password)` to encode the request header. + +```java + private final OkHttpClient client; + + public Authenticate() { + client = new OkHttpClient.Builder() + .authenticator(new Authenticator() { + @Override public Request authenticate(Route route, Response response) throws IOException { + if (response.request().header("Authorization") != null) { + return null; // Give up, we've already attempted to authenticate. + } + + System.out.println("Authenticating for response: " + response); + System.out.println("Challenges: " + response.challenges()); + String credential = Credentials.basic("jesse", "password1"); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }) + .build(); + } + + public void run() throws Exception { + Request request = new Request.Builder() + .url("http://publicobject.com/secrets/hellosecret.txt") + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + System.out.println(response.body().string()); + } + } +``` + +To avoid making many retries when authentication isn't working, you can return null to give up. For example, you may want to skip the retry when these exact credentials have already been attempted: + +```java + if (credential.equals(response.request().header("Authorization"))) { + return null; // If we already failed with these credentials, don't retry. + } +``` + +You may also skip the retry when you’ve hit an application-defined attempt limit: + +```java + if (responseCount(response) >= 3) { + return null; // If we've failed 3 times, give up. + } +``` + +This above code relies on this `responseCount()` method: + +```java + private int responseCount(Response response) { + int result = 1; + while ((response = response.priorResponse()) != null) { + result++; + } + return result; + } +``` + + +---- + + + + + +
← ConnectionsOkHttp User's GuideInterceptors →
diff --git a/SECURITY.md b/SECURITY.md index b58275bd5..8efac6ea6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,4 +1,5 @@ -# Security Policy +Security Policy +=============== ## Supported Versions diff --git a/TLS_CONFIGURATION_HISTORY.md b/TLS_CONFIGURATION_HISTORY.md new file mode 100644 index 000000000..4798b7572 --- /dev/null +++ b/TLS_CONFIGURATION_HISTORY.md @@ -0,0 +1,264 @@ +TLS Configuration History +========================= + +OkHttp tracks the dynamic TLS ecosystem to balance connectivity and security. This page is a log of +changes we've made over time to OkHttp's default TLS options. + +[OkHttp 3.14][OkHttp314] +------------------------ + +_RELEASE TBD_ + +Remove 2 TLSv1.3 cipher suites that are neither available on OkHttp’s host platforms nor enabled in releases of Chrome and Firefox. + +##### RESTRICTED_TLS cipher suites + + * TLS_AES_128_GCM_SHA256[¹][tlsv13_only] + * TLS_AES_256_GCM_SHA384[¹][tlsv13_only] + * TLS_CHACHA20_POLY1305_SHA256[¹][tlsv13_only] + * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + * TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + * **REMOVED:** ~~TLS_AES_128_CCM_SHA256[¹][tlsv13_only]~~ + * **REMOVED:** ~~TLS_AES_128_CCM_8_SHA256[¹][tlsv13_only]~~ + +##### MODERN_TLS / COMPATIBLE_TLS cipher suites + + * TLS_AES_128_GCM_SHA256[¹][tlsv13_only] + * TLS_AES_256_GCM_SHA384[¹][tlsv13_only] + * TLS_CHACHA20_POLY1305_SHA256[¹][tlsv13_only] + * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + * TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_AES_128_GCM_SHA256[²][http2_naughty] + * TLS_RSA_WITH_AES_256_GCM_SHA384[²][http2_naughty] + * TLS_RSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_3DES_EDE_CBC_SHA[²][http2_naughty] + * **REMOVED:** ~~TLS_AES_128_CCM_SHA256[¹][tlsv13_only]~~ + * **REMOVED:** ~~TLS_AES_128_CCM_8_SHA256[¹][tlsv13_only]~~ + +[OkHttp 3.13][OkHttp313] +------------------------ + +_2019-02-04_ + +Remove TLSv1.1 and TLSv1 from MODERN_TLS. Change COMPATIBLE_TLS to support all TLS versions. + +##### RESTRICTED_TLS versions + +* TLSv1.3 +* TLSv1.2 + +##### MODERN_TLS versions + +* TLSv1.3 +* TLSv1.2 +* **REMOVED:** ~~TLSv1.1~~ +* **REMOVED:** ~~TLSv1~~ + +##### COMPATIBLE_TLS versions + +* **NEW:** TLSv1.3 +* **NEW:** TLSv1.2 +* **NEW:** TLSv1.1 +* TLSv1 + +[OkHttp 3.12][OkHttp312] +------------------------ + +_2018-11-16_ + +Added support for TLSv1.3. + +##### RESTRICTED_TLS cipher suites + + * **NEW:** TLS_AES_128_GCM_SHA256[¹][tlsv13_only] + * **NEW:** TLS_AES_256_GCM_SHA384[¹][tlsv13_only] + * **NEW:** TLS_CHACHA20_POLY1305_SHA256[¹][tlsv13_only] + * **NEW:** TLS_AES_128_CCM_SHA256[¹][tlsv13_only] + * **NEW:** TLS_AES_128_CCM_8_SHA256[¹][tlsv13_only] + * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + * TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + +##### MODERN_TLS / COMPATIBLE_TLS cipher suites + + * **NEW:** TLS_AES_128_GCM_SHA256[¹][tlsv13_only] + * **NEW:** TLS_AES_256_GCM_SHA384[¹][tlsv13_only] + * **NEW:** TLS_CHACHA20_POLY1305_SHA256[¹][tlsv13_only] + * **NEW:** TLS_AES_128_CCM_SHA256[¹][tlsv13_only] + * **NEW:** TLS_AES_128_CCM_8_SHA256[¹][tlsv13_only] + * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + * TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_AES_128_GCM_SHA256[²][http2_naughty] + * TLS_RSA_WITH_AES_256_GCM_SHA384[²][http2_naughty] + * TLS_RSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_3DES_EDE_CBC_SHA[²][http2_naughty] + +##### RESTRICTED_TLS versions + +* **NEW:** TLSv1.3 +* TLSv1.2 + +##### MODERN_TLS versions + +* **NEW:** TLSv1.3 +* TLSv1.2 +* TLSv1.1 +* TLSv1 + +##### COMPATIBLE_TLS versions + +* TLSv1 + +[OkHttp 3.11][OkHttp311] +------------------------ + +_2018-07-12_ + +Added a new extra strict RESTRICTED_TLS configuration inspired by [Google Cloud’s similar policy][googlecloud_ssl_policy]. It is appropriate when both the host platform +(JVM/Conscrypt/Android) and target webserver are current. + +##### RESTRICTED_TLS cipher suites + + * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + * TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + +##### RESTRICTED_TLS versions + + * TLSv1.2 + +[OkHttp 3.10][OkHttp310] +------------------------ + +_2018-02-24_ + +Remove two rarely-used cipher suites from the default set. This tracks a Chromium change to remove these cipher suites because they are fragile and rarely-used. + +##### MODERN_TLS / COMPATIBLE_TLS cipher suites + + * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + * TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_AES_128_GCM_SHA256[²][http2_naughty] + * TLS_RSA_WITH_AES_256_GCM_SHA384[²][http2_naughty] + * TLS_RSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_3DES_EDE_CBC_SHA[²][http2_naughty] + * **REMOVED:** ~~TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA~~ + * **REMOVED:** ~~TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA~~ + + +[OkHttp 3.5][OkHttp35] +---------------------- + +_2016-11-30_ + +Remove three old cipher suites and add five new ones. This tracks changes in what's available on +Android and Java, and also what cipher suites recent releases of Chrome and Firefox support by +default. + +##### MODERN_TLS / COMPATIBLE_TLS cipher suites + + * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * **NEW:** TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * **NEW:** TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * **NEW:** TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + * **NEW:** TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_AES_128_GCM_SHA256[²][http2_naughty] + * **NEW:** TLS_RSA_WITH_AES_256_GCM_SHA384[²][http2_naughty] + * TLS_RSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_3DES_EDE_CBC_SHA[²][http2_naughty] + * **REMOVED:** ~~TLS_DHE_RSA_WITH_AES_128_CBC_SHA~~ + * **REMOVED:** ~~TLS_DHE_RSA_WITH_AES_128_GCM_SHA256~~ + * **REMOVED:** ~~TLS_DHE_RSA_WITH_AES_256_CBC_SHA~~ + +[OkHttp 3.0][OkHttp30] +---------------------- + +_2016-01-13_ + +##### MODERN_TLS / COMPATIBLE_TLS cipher suites + + * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_AES_128_GCM_SHA256[²][http2_naughty] + * TLS_RSA_WITH_AES_128_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_AES_256_CBC_SHA[²][http2_naughty] + * TLS_RSA_WITH_3DES_EDE_CBC_SHA[²][http2_naughty] + + +##### MODERN_TLS versions + + * TLSv1.2 + * TLSv1.1 + * TLSv1 + +##### COMPATIBLE_TLS versions + + * TLSv1 + +--- + + +#### ¹ TLSv1.3 Only + +Cipher suites that are only available with TLSv1.3. + + +#### ² HTTP/2 Cipher Suite Denylist + +Cipher suites that are [discouraged for use][http2_denylist] with HTTP/2. OkHttp includes them because better suites are not commonly available. For example, none of the better cipher suites listed above shipped with Android 4.4 or Java 7. + + [OkHttp314]: https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-3140 + [OkHttp313]: https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-3130 + [OkHttp312]: https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-3120 + [OkHttp311]: https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-3110 + [OkHttp310]: https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-3100 + [OkHttp35]: https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-350 + [OkHttp30]: https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-300 + [googlecloud_ssl_policy]: https://cloud.google.com/load-balancing/docs/ssl-policies-concepts + [tlsv13_only]: #tlsv13_only + [http2_naughty]: #http2_naughty + [http2_denylist]: https://tools.ietf.org/html/rfc7540#appendix-A diff --git a/WORKS_WITH_OKHTTP.md b/WORKS_WITH_OKHTTP.md new file mode 100644 index 000000000..c80991820 --- /dev/null +++ b/WORKS_WITH_OKHTTP.md @@ -0,0 +1,36 @@ +Works with OkHttp +================= + +Here’s some libraries that work nicely with OkHttp. + + * [Chuck](https://github.com/jgilfelt/chuck): An in-app HTTP inspector for Android OkHttp clients. + * [Communicator](https://github.com/Taig/Communicator): An OkHttp wrapper for Scala built with Android in mind. + * [CWAC-NetSecurity](https://github.com/commonsguy/cwac-netsecurity): Simplifying Secure Internet Access. + * [Fresco](https://github.com/facebook/fresco): An Android library for managing images and the memory they use. + * [Glide](https://github.com/bumptech/glide): An image loading and caching library for Android focused on smooth scrolling. + * [GoogleAppEngineOkHttp](https://github.com/apkelly/GoogleAppEngineOkHttp): An OkHttp Call that works on Google App Engine. + * [Hunter](https://github.com/Leaking/Hunter): Configure all OkHttpClients centrally. + * [ModernHttpClient](https://github.com/paulcbetts/ModernHttpClient): Xamarin HTTP API that uses native implementations. + * ⬜️ [Moshi](https://github.com/square/moshi): A modern JSON library for Android and Java. + * [Ok2Curl](https://github.com/mrmike/Ok2Curl): Convert OkHttp requests into curl logs. + * [OkHttp AWS Signer](https://github.com/babbel/okhttp-aws-signer): AWS V4 signing algorithm for OkHttp requests + * [okhttp-digest](https://github.com/rburgst/okhttp-digest): A digest authenticator for OkHttp. + * [OkHttp Idling Resource](https://github.com/JakeWharton/okhttp-idling-resource): An Espresso IdlingResource for OkHttp. + * [okhttp-client-mock](https://github.com/gmazzo/okhttp-client-mock): A simple OKHttp client mock, using a programmable request interceptor. + * [OkHttp Profiler](https://plugins.jetbrains.com/plugin/11249-okhttp-profiler): An IntelliJ plugin for monitoring OkHttp calls. + * [OkReplay](https://github.com/airbnb/okreplay): Record and replay OkHttp network interaction in your tests. + * [okhttp-signpost](https://github.com/pakerfeldt/okhttp-signpost): OAuth signing with signpost and OkHttp. + * [okhttp-staleiferror-interceptor](https://github.com/PeelTechnologies/okhttp-staleiferror-interceptor/): serve stale responses when the server isn’t reachable. + * [okhttp-stats](https://github.com/flipkart-incubator/okhttp-stats): Get stats like average network speed. + * [OkHttp-Xamarin](https://github.com/paulcbetts/OkHttp-Xamarin): Xamarin bindings for OkHttp. + * ⬜️ [Okio](https://github.com/square/okio/): A modern I/O API for Java. + * [OkLog](https://github.com/simonpercic/OkLog): Response logging interceptor for OkHttp. Logs a URL link with URL-encoded response for every OkHttp call. + * [Okurl](https://github.com/yschimke/okurl/wiki) A curl-like client for social networks and other APIs. + * [PersistentCookieJar](https://github.com/franmontiel/PersistentCookieJar): A persistent `CookieJar`. + * ⬜️ [Picasso](https://github.com/square/picasso): A powerful image downloading and caching library for Android. + * ⬜️ [Retrofit](https://github.com/square/retrofit): Type-safe HTTP client for Android and Java by Square. + * [Smash](https://github.com/appformation/smash): A Volley-inspired networking library. + * [Stetho](https://github.com/facebook/stetho): Stetho is a debug bridge for Android applications. + * [Thrifty](https://github.com/Microsoft/thrifty): An implementation of Apache Thrift for Android. + * [Volley-OkHttp-Android](https://github.com/lxdvs/Volley-OkHttp-Android): A fork of Volley with changes to work with OkHttp. + * ⬜️ [Wire](https://github.com/square/wire): Clean, lightweight protocol buffers for Android and Java. diff --git a/okhttp-logging-interceptor/README.md b/okhttp-logging-interceptor/README.md index 5da532419..690a29087 100644 --- a/okhttp-logging-interceptor/README.md +++ b/okhttp-logging-interceptor/README.md @@ -42,4 +42,4 @@ implementation("com.squareup.okhttp3:logging-interceptor:3.14.2") - [1]: https://github.com/square/okhttp/wiki/Interceptors + [1]: ../INTERCEPTORS.md diff --git a/website/index.html b/website/index.html index 02c69c6c9..b03867ad2 100644 --- a/website/index.html +++ b/website/index.html @@ -162,7 +162,6 @@ limitations under the License.
  • License