diff options
34 files changed, 4258 insertions, 46 deletions
diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 000000000..ee67bad4b --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,41 @@ +Copyright 2014, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------- + +This product contains a modified portion of 'OkHttp', an open source +HTTP & SPDY client for Android and Java applications, which can be obtained +at: + + * LICENSE: + * okhttp/third_party/okhttp/LICENSE (Apache License 2.0) + * HOMEPAGE: + * https://github.com/square/okhttp + * LOCATION_IN_GRPC: + * okhttp/third_party/okhttp
\ No newline at end of file diff --git a/all/build.gradle b/all/build.gradle index e67b6b470..e7a235a62 100644 --- a/all/build.gradle +++ b/all/build.gradle @@ -75,6 +75,10 @@ jacocoTestReport { additionalSourceDirs = files(subprojects.sourceSets.main.allSource.srcDirs) sourceDirectories = files(subprojects.sourceSets.main.allSource.srcDirs) classDirectories = files(subprojects.sourceSets.main.output) + classDirectories = files(classDirectories.files.collect { + fileTree(dir: it, + exclude: ['**/io/grpc/okhttp/internal/**']) + }) } coveralls { diff --git a/build.gradle b/build.gradle index 717ea3c9e..144e1e975 100644 --- a/build.gradle +++ b/build.gradle @@ -131,6 +131,7 @@ subprojects { jsr305: 'com.google.code.findbugs:jsr305:3.0.0', oauth_client: 'com.google.auth:google-auth-library-oauth2-http:0.3.0', okhttp: 'com.squareup.okhttp:okhttp:2.5.0', + okio: 'com.squareup.okio:okio:1.6.0', protobuf: "com.google.protobuf:protobuf-java:${protobufVersion}", protobuf_nano: "com.google.protobuf.nano:protobuf-javanano:${protobufNanoVersion}", protobuf_plugin: 'com.google.protobuf:protobuf-gradle-plugin:0.7.0', diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4cbfb745d..3279ebc89 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Mon Sep 21 10:27:21 PDT 2015 +#Tue May 12 09:49:30 PDT 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/okhttp/build.gradle b/okhttp/build.gradle index af8ca0e27..62b2f53d7 100644 --- a/okhttp/build.gradle +++ b/okhttp/build.gradle @@ -5,16 +5,27 @@ plugins { description = "gRPC: OkHttp" dependencies { compile project(':grpc-core'), - libraries.okhttp + libraries.okhttp, + libraries.okio // Tests depend on base class defined by core module. testCompile project(':grpc-core').sourceSets.test.output } +project.sourceSets { + main { + java { + srcDir "${projectDir}/third_party/okhttp/java" + } + } +} + +checkstyleMain.exclude '**/io/grpc/okhttp/internal/**' + // Configure the animal sniffer plugin animalsniffer { signature = "org.codehaus.mojo.signature:java16:+@signature" } -javadoc.exclude 'com/squareup/**' +javadoc.exclude 'io/grpc/okhttp/internal/**' javadoc.options.links 'http://square.github.io/okhttp/javadoc/' diff --git a/okhttp/src/main/java/io/grpc/okhttp/AsyncFrameWriter.java b/okhttp/src/main/java/io/grpc/okhttp/AsyncFrameWriter.java index c2be096d2..57eb77201 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/AsyncFrameWriter.java +++ b/okhttp/src/main/java/io/grpc/okhttp/AsyncFrameWriter.java @@ -33,12 +33,11 @@ package io.grpc.okhttp; import com.google.common.base.Preconditions; -import com.squareup.okhttp.internal.framed.ErrorCode; -import com.squareup.okhttp.internal.framed.FrameWriter; -import com.squareup.okhttp.internal.framed.Header; -import com.squareup.okhttp.internal.framed.Settings; - import io.grpc.internal.SerializingExecutor; +import io.grpc.okhttp.internal.framed.ErrorCode; +import io.grpc.okhttp.internal.framed.FrameWriter; +import io.grpc.okhttp.internal.framed.Header; +import io.grpc.okhttp.internal.framed.Settings; import okio.Buffer; diff --git a/okhttp/src/main/java/io/grpc/okhttp/Headers.java b/okhttp/src/main/java/io/grpc/okhttp/Headers.java index b90954e68..d413587d2 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/Headers.java +++ b/okhttp/src/main/java/io/grpc/okhttp/Headers.java @@ -37,11 +37,10 @@ import static io.grpc.internal.GrpcUtil.USER_AGENT_KEY; import com.google.common.base.Preconditions; -import com.squareup.okhttp.internal.framed.Header; - import io.grpc.Metadata; import io.grpc.internal.GrpcUtil; import io.grpc.internal.TransportFrameUtil; +import io.grpc.okhttp.internal.framed.Header; import okio.ByteString; diff --git a/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java index 339285422..02f7176a8 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java @@ -77,6 +77,7 @@ public class OkHttpChannelBuilder extends .tlsVersions(TlsVersion.TLS_1_2) .supportsTlsExtensions(true) .build(); + private static final Resource<ExecutorService> SHARED_EXECUTOR = new Resource<ExecutorService>() { @Override @@ -172,7 +173,7 @@ public class OkHttpChannelBuilder extends * For secure connection, provides a ConnectionSpec to specify Cipher suite and * TLS versions. * - * <p>By default DEFAULT_CONNECTION_SPEC will be used. + * <p>By default {@link #DEFAULT_CONNECTION_SPEC} will be used. */ public final OkHttpChannelBuilder connectionSpec(ConnectionSpec connectionSpec) { this.connectionSpec = connectionSpec; @@ -265,7 +266,7 @@ public class OkHttpChannelBuilder extends @Override public ClientTransport newClientTransport() { return new OkHttpClientTransport(host, port, authority, executor, socketFactory, - connectionSpec, maxMessageSize); + Utils.convertSpec(connectionSpec), maxMessageSize); } @Override diff --git a/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java index 3de99086c..36c487789 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java @@ -34,15 +34,14 @@ package io.grpc.okhttp; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; -import com.squareup.okhttp.internal.framed.ErrorCode; -import com.squareup.okhttp.internal.framed.Header; - import io.grpc.Metadata; import io.grpc.MethodDescriptor.MethodType; import io.grpc.Status; import io.grpc.internal.ClientStreamListener; import io.grpc.internal.Http2ClientStream; import io.grpc.internal.WritableBuffer; +import io.grpc.okhttp.internal.framed.ErrorCode; +import io.grpc.okhttp.internal.framed.Header; import okio.Buffer; diff --git a/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java index 0f52c9b1b..1d73ec9dc 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java @@ -39,18 +39,6 @@ import com.google.common.base.Stopwatch; import com.google.common.base.Ticker; import com.google.common.util.concurrent.SettableFuture; -import com.squareup.okhttp.ConnectionSpec; -import com.squareup.okhttp.OkHttpTlsUpgrader; -import com.squareup.okhttp.internal.framed.ErrorCode; -import com.squareup.okhttp.internal.framed.FrameReader; -import com.squareup.okhttp.internal.framed.FrameWriter; -import com.squareup.okhttp.internal.framed.Header; -import com.squareup.okhttp.internal.framed.HeadersMode; -import com.squareup.okhttp.internal.framed.Http2; -import com.squareup.okhttp.internal.framed.OkHttpSettingsUtil; -import com.squareup.okhttp.internal.framed.Settings; -import com.squareup.okhttp.internal.framed.Variant; - import io.grpc.Metadata; import io.grpc.MethodDescriptor; import io.grpc.MethodDescriptor.MethodType; @@ -61,6 +49,15 @@ import io.grpc.internal.ClientTransport; import io.grpc.internal.GrpcUtil; import io.grpc.internal.Http2Ping; import io.grpc.internal.SerializingExecutor; +import io.grpc.okhttp.internal.ConnectionSpec; +import io.grpc.okhttp.internal.framed.ErrorCode; +import io.grpc.okhttp.internal.framed.FrameReader; +import io.grpc.okhttp.internal.framed.FrameWriter; +import io.grpc.okhttp.internal.framed.Header; +import io.grpc.okhttp.internal.framed.HeadersMode; +import io.grpc.okhttp.internal.framed.Http2; +import io.grpc.okhttp.internal.framed.Settings; +import io.grpc.okhttp.internal.framed.Variant; import okio.Buffer; import okio.BufferedSink; diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/OkHttpProtocolNegotiator.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpProtocolNegotiator.java index c15080250..f2caedc8a 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/OkHttpProtocolNegotiator.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpProtocolNegotiator.java @@ -29,9 +29,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.squareup.okhttp.internal; +package io.grpc.okhttp; -import com.squareup.okhttp.Protocol; +import io.grpc.okhttp.internal.OptionalMethod; +import io.grpc.okhttp.internal.Platform; +import io.grpc.okhttp.internal.Protocol; +import io.grpc.okhttp.internal.Util; import java.io.IOException; import java.net.Socket; @@ -44,7 +47,7 @@ import javax.net.ssl.SSLSocket; /** * A helper class located in package com.squareup.okhttp.internal for TLS negotiation. */ -public class OkHttpProtocolNegotiator { +class OkHttpProtocolNegotiator { private static final Platform PLATFORM = Platform.get(); private static OkHttpProtocolNegotiator NEGOTIATOR = createNegotiator(); diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/framed/OkHttpSettingsUtil.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpSettingsUtil.java index 264ca4cba..b0862f49f 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/framed/OkHttpSettingsUtil.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpSettingsUtil.java @@ -29,12 +29,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.squareup.okhttp.internal.framed; +package io.grpc.okhttp; + +import io.grpc.okhttp.internal.framed.Settings; /** * A utility class help gRPC get/set the necessary fields of OkHttp's Settings. */ -public class OkHttpSettingsUtil { +class OkHttpSettingsUtil { public static final int MAX_CONCURRENT_STREAMS = Settings.MAX_CONCURRENT_STREAMS; public static final int INITIAL_WINDOW_SIZE = Settings.INITIAL_WINDOW_SIZE; diff --git a/okhttp/src/main/java/com/squareup/okhttp/OkHttpTlsUpgrader.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpTlsUpgrader.java index 039552a34..6fa1f7bd7 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/OkHttpTlsUpgrader.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpTlsUpgrader.java @@ -29,11 +29,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.squareup.okhttp; +package io.grpc.okhttp; import com.google.common.base.Preconditions; -import com.squareup.okhttp.internal.OkHttpProtocolNegotiator; +import io.grpc.okhttp.internal.ConnectionSpec; +import io.grpc.okhttp.internal.Protocol; import java.io.IOException; import java.net.Socket; @@ -48,7 +49,7 @@ import javax.net.ssl.SSLSocketFactory; * A helper class that located in package com.squareup.okhttp, so that we can use OkHttp internals * to do TLS upgrading. */ -public final class OkHttpTlsUpgrader { +final class OkHttpTlsUpgrader { private static final String HTTP2_PROTOCOL_NAME = "h2"; private static final List<Protocol> TLS_PROTOCOLS = diff --git a/okhttp/src/main/java/io/grpc/okhttp/OutboundFlowController.java b/okhttp/src/main/java/io/grpc/okhttp/OutboundFlowController.java index 3e68b61a1..628ceeb86 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OutboundFlowController.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OutboundFlowController.java @@ -39,7 +39,7 @@ import static java.lang.Math.min; import com.google.common.base.Preconditions; -import com.squareup.okhttp.internal.framed.FrameWriter; +import io.grpc.okhttp.internal.framed.FrameWriter; import okio.Buffer; diff --git a/okhttp/src/main/java/io/grpc/okhttp/Utils.java b/okhttp/src/main/java/io/grpc/okhttp/Utils.java index c7201aa27..4d3919ef2 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/Utils.java +++ b/okhttp/src/main/java/io/grpc/okhttp/Utils.java @@ -31,10 +31,11 @@ package io.grpc.okhttp; -import com.squareup.okhttp.internal.framed.Header; - import io.grpc.Metadata; import io.grpc.internal.TransportFrameUtil; +import io.grpc.okhttp.internal.CipherSuite; +import io.grpc.okhttp.internal.ConnectionSpec; +import io.grpc.okhttp.internal.framed.Header; import java.util.List; @@ -63,6 +64,26 @@ class Utils { return TransportFrameUtil.toRawSerializedHeaders(headerValues); } + static ConnectionSpec convertSpec(com.squareup.okhttp.ConnectionSpec spec) { + List<com.squareup.okhttp.TlsVersion> tlsVersionList = spec.tlsVersions(); + String[] tlsVersions = new String[tlsVersionList.size()]; + for (int i = 0; i < tlsVersions.length; i++) { + tlsVersions[i] = tlsVersionList.get(i).javaName(); + } + + List<com.squareup.okhttp.CipherSuite> cipherSuiteList = spec.cipherSuites(); + CipherSuite[] cipherSuites = new CipherSuite[cipherSuiteList.size()]; + for (int i = 0; i < cipherSuites.length; i++) { + cipherSuites[i] = CipherSuite.valueOf(cipherSuiteList.get(i).name()); + } + + return new ConnectionSpec.Builder(spec.isTls()) + .supportsTlsExtensions(spec.supportsTlsExtensions()) + .tlsVersions(tlsVersions) + .cipherSuites(cipherSuites) + .build(); + } + private Utils() { // Prevents instantiation } diff --git a/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java b/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java index 165d7d176..1f9507970 100644 --- a/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java +++ b/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java @@ -63,14 +63,6 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; -import com.squareup.okhttp.internal.framed.ErrorCode; -import com.squareup.okhttp.internal.framed.FrameReader; -import com.squareup.okhttp.internal.framed.FrameWriter; -import com.squareup.okhttp.internal.framed.Header; -import com.squareup.okhttp.internal.framed.HeadersMode; -import com.squareup.okhttp.internal.framed.OkHttpSettingsUtil; -import com.squareup.okhttp.internal.framed.Settings; - import io.grpc.Metadata; import io.grpc.MethodDescriptor; import io.grpc.MethodDescriptor.MethodType; @@ -81,6 +73,13 @@ import io.grpc.internal.ClientStreamListener; import io.grpc.internal.ClientTransport; import io.grpc.internal.GrpcUtil; import io.grpc.okhttp.OkHttpClientTransport.ClientFrameHandler; +import io.grpc.okhttp.internal.ConnectionSpec; +import io.grpc.okhttp.internal.framed.ErrorCode; +import io.grpc.okhttp.internal.framed.FrameReader; +import io.grpc.okhttp.internal.framed.FrameWriter; +import io.grpc.okhttp.internal.framed.Header; +import io.grpc.okhttp.internal.framed.HeadersMode; +import io.grpc.okhttp.internal.framed.Settings; import okio.Buffer; diff --git a/okhttp/third_party/okhttp/LICENSE b/okhttp/third_party/okhttp/LICENSE new file mode 100644 index 000000000..7a4a3ea24 --- /dev/null +++ b/okhttp/third_party/okhttp/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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.
\ No newline at end of file diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/CipherSuite.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/CipherSuite.java new file mode 100644 index 000000000..bc2a9b7f0 --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/CipherSuite.java @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2014 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal; + +import static java.lang.Integer.MAX_VALUE; + +/** + * <a href="https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml">TLS cipher + * suites</a>. + * + * <p><strong>Not all cipher suites are supported on all platforms.</strong> As newer cipher suites + * are created (for stronger privacy, better performance, etc.) they will be adopted by the platform + * and then exposed here. Cipher suites that are not available on either Android (through API level + * 20) or Java (through JDK 8) are omitted for brevity. + * + * <p>See also <a href="https://android.googlesource.com/platform/external/conscrypt/+/master/src/main/java/org/conscrypt/NativeCrypto.java">NativeCrypto.java</a> + * from conscrypt, which lists the cipher suites supported by Android. + */ +public enum CipherSuite { + // Last updated 2014-11-11 using cipher suites from Android 21 and Java 8. + + // TLS_NULL_WITH_NULL_NULL("TLS_NULL_WITH_NULL_NULL", 0x0000, 5246, MAX_VALUE, MAX_VALUE), + TLS_RSA_WITH_NULL_MD5("SSL_RSA_WITH_NULL_MD5", 0x0001, 5246, 6, 10), + TLS_RSA_WITH_NULL_SHA("SSL_RSA_WITH_NULL_SHA", 0x0002, 5246, 6, 10), + TLS_RSA_EXPORT_WITH_RC4_40_MD5("SSL_RSA_EXPORT_WITH_RC4_40_MD5", 0x0003, 4346, 6, 10), + TLS_RSA_WITH_RC4_128_MD5("SSL_RSA_WITH_RC4_128_MD5", 0x0004, 5246, 6, 10), + TLS_RSA_WITH_RC4_128_SHA("SSL_RSA_WITH_RC4_128_SHA", 0x0005, 5246, 6, 10), + // TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5", 0x0006, 4346, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_IDEA_CBC_SHA("TLS_RSA_WITH_IDEA_CBC_SHA", 0x0007, 5469, MAX_VALUE, MAX_VALUE), + TLS_RSA_EXPORT_WITH_DES40_CBC_SHA("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0008, 4346, 6, 10), + TLS_RSA_WITH_DES_CBC_SHA("SSL_RSA_WITH_DES_CBC_SHA", 0x0009, 5469, 6, 10), + TLS_RSA_WITH_3DES_EDE_CBC_SHA("SSL_RSA_WITH_3DES_EDE_CBC_SHA", 0x000a, 5246, 6, 10), + // TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x000b, 4346, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_DES_CBC_SHA("TLS_DH_DSS_WITH_DES_CBC_SHA", 0x000c, 5469, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", 0x000d, 5246, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA("SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x000e, 4346, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_DES_CBC_SHA("TLS_DH_RSA_WITH_DES_CBC_SHA", 0x000f, 5469, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", 0x0010, 5246, MAX_VALUE, MAX_VALUE), + TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x0011, 4346, 6, 10), + TLS_DHE_DSS_WITH_DES_CBC_SHA("SSL_DHE_DSS_WITH_DES_CBC_SHA", 0x0012, 5469, 6, 10), + TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", 0x0013, 5246, 6, 10), + TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0014, 4346, 6, 10), + TLS_DHE_RSA_WITH_DES_CBC_SHA("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0015, 5469, 6, 10), + TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", 0x0016, 5246, 6, 10), + TLS_DH_anon_EXPORT_WITH_RC4_40_MD5("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", 0x0017, 4346, 6, 10), + TLS_DH_anon_WITH_RC4_128_MD5("SSL_DH_anon_WITH_RC4_128_MD5", 0x0018, 5246, 6, 10), + TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", 0x0019, 4346, 6, 10), + TLS_DH_anon_WITH_DES_CBC_SHA("SSL_DH_anon_WITH_DES_CBC_SHA", 0x001a, 5469, 6, 10), + TLS_DH_anon_WITH_3DES_EDE_CBC_SHA("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", 0x001b, 5246, 6, 10), + TLS_KRB5_WITH_DES_CBC_SHA("TLS_KRB5_WITH_DES_CBC_SHA", 0x001e, 2712, 6, MAX_VALUE), + TLS_KRB5_WITH_3DES_EDE_CBC_SHA("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", 0x001f, 2712, 6, MAX_VALUE), + TLS_KRB5_WITH_RC4_128_SHA("TLS_KRB5_WITH_RC4_128_SHA", 0x0020, 2712, 6, MAX_VALUE), + // TLS_KRB5_WITH_IDEA_CBC_SHA("TLS_KRB5_WITH_IDEA_CBC_SHA", 0x0021, 2712, MAX_VALUE, MAX_VALUE), + TLS_KRB5_WITH_DES_CBC_MD5("TLS_KRB5_WITH_DES_CBC_MD5", 0x0022, 2712, 6, MAX_VALUE), + TLS_KRB5_WITH_3DES_EDE_CBC_MD5("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", 0x0023, 2712, 6, MAX_VALUE), + TLS_KRB5_WITH_RC4_128_MD5("TLS_KRB5_WITH_RC4_128_MD5", 0x0024, 2712, 6, MAX_VALUE), + // TLS_KRB5_WITH_IDEA_CBC_MD5("TLS_KRB5_WITH_IDEA_CBC_MD5", 0x0025, 2712, MAX_VALUE, MAX_VALUE), + TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", 0x0026, 2712, 6, MAX_VALUE), + // TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", 0x0027, 2712, MAX_VALUE, MAX_VALUE), + TLS_KRB5_EXPORT_WITH_RC4_40_SHA("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", 0x0028, 2712, 6, MAX_VALUE), + TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", 0x0029, 2712, 6, MAX_VALUE), + // TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", 0x002a, 2712, MAX_VALUE, MAX_VALUE), + TLS_KRB5_EXPORT_WITH_RC4_40_MD5("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", 0x002b, 2712, 6, MAX_VALUE), + // TLS_PSK_WITH_NULL_SHA("TLS_PSK_WITH_NULL_SHA", 0x002c, 4785, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_NULL_SHA("TLS_DHE_PSK_WITH_NULL_SHA", 0x002d, 4785, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_NULL_SHA("TLS_RSA_PSK_WITH_NULL_SHA", 0x002e, 4785, MAX_VALUE, MAX_VALUE), + TLS_RSA_WITH_AES_128_CBC_SHA("TLS_RSA_WITH_AES_128_CBC_SHA", 0x002f, 5246, 6, 10), + // TLS_DH_DSS_WITH_AES_128_CBC_SHA("TLS_DH_DSS_WITH_AES_128_CBC_SHA", 0x0030, 5246, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_AES_128_CBC_SHA("TLS_DH_RSA_WITH_AES_128_CBC_SHA", 0x0031, 5246, MAX_VALUE, MAX_VALUE), + TLS_DHE_DSS_WITH_AES_128_CBC_SHA("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 0x0032, 5246, 6, 10), + TLS_DHE_RSA_WITH_AES_128_CBC_SHA("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 0x0033, 5246, 6, 10), + TLS_DH_anon_WITH_AES_128_CBC_SHA("TLS_DH_anon_WITH_AES_128_CBC_SHA", 0x0034, 5246, 6, 10), + TLS_RSA_WITH_AES_256_CBC_SHA("TLS_RSA_WITH_AES_256_CBC_SHA", 0x0035, 5246, 6, 10), + // TLS_DH_DSS_WITH_AES_256_CBC_SHA("TLS_DH_DSS_WITH_AES_256_CBC_SHA", 0x0036, 5246, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_AES_256_CBC_SHA("TLS_DH_RSA_WITH_AES_256_CBC_SHA", 0x0037, 5246, MAX_VALUE, MAX_VALUE), + TLS_DHE_DSS_WITH_AES_256_CBC_SHA("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", 0x0038, 5246, 6, 10), + TLS_DHE_RSA_WITH_AES_256_CBC_SHA("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", 0x0039, 5246, 6, 10), + TLS_DH_anon_WITH_AES_256_CBC_SHA("TLS_DH_anon_WITH_AES_256_CBC_SHA", 0x003a, 5246, 6, 10), + TLS_RSA_WITH_NULL_SHA256("TLS_RSA_WITH_NULL_SHA256", 0x003b, 5246, 7, 21), + TLS_RSA_WITH_AES_128_CBC_SHA256("TLS_RSA_WITH_AES_128_CBC_SHA256", 0x003c, 5246, 7, 21), + TLS_RSA_WITH_AES_256_CBC_SHA256("TLS_RSA_WITH_AES_256_CBC_SHA256", 0x003d, 5246, 7, 21), + // TLS_DH_DSS_WITH_AES_128_CBC_SHA256("TLS_DH_DSS_WITH_AES_128_CBC_SHA256", 0x003e, 5246, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_AES_128_CBC_SHA256("TLS_DH_RSA_WITH_AES_128_CBC_SHA256", 0x003f, 5246, MAX_VALUE, MAX_VALUE), + TLS_DHE_DSS_WITH_AES_128_CBC_SHA256("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", 0x0040, 5246, 7, 21), + // TLS_RSA_WITH_CAMELLIA_128_CBC_SHA("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0041, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0042, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0043, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0044, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0045, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", 0x0046, 5932, MAX_VALUE, MAX_VALUE), + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", 0x0067, 5246, 7, 21), + // TLS_DH_DSS_WITH_AES_256_CBC_SHA256("TLS_DH_DSS_WITH_AES_256_CBC_SHA256", 0x0068, 5246, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_AES_256_CBC_SHA256("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x0069, 5246, MAX_VALUE, MAX_VALUE), + TLS_DHE_DSS_WITH_AES_256_CBC_SHA256("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", 0x006a, 5246, 7, 21), + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", 0x006b, 5246, 7, 21), + TLS_DH_anon_WITH_AES_128_CBC_SHA256("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x006c, 5246, 7, 21), + TLS_DH_anon_WITH_AES_256_CBC_SHA256("TLS_DH_anon_WITH_AES_256_CBC_SHA256", 0x006d, 5246, 7, 21), + // TLS_RSA_WITH_CAMELLIA_256_CBC_SHA("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0084, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0085, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0086, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0087, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0088, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", 0x0089, 5932, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_RC4_128_SHA("TLS_PSK_WITH_RC4_128_SHA", 0x008a, 4279, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_3DES_EDE_CBC_SHA("TLS_PSK_WITH_3DES_EDE_CBC_SHA", 0x008b, 4279, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_AES_128_CBC_SHA("TLS_PSK_WITH_AES_128_CBC_SHA", 0x008c, 4279, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_AES_256_CBC_SHA("TLS_PSK_WITH_AES_256_CBC_SHA", 0x008d, 4279, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_RC4_128_SHA("TLS_DHE_PSK_WITH_RC4_128_SHA", 0x008e, 4279, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA("TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", 0x008f, 4279, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_AES_128_CBC_SHA("TLS_DHE_PSK_WITH_AES_128_CBC_SHA", 0x0090, 4279, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_AES_256_CBC_SHA("TLS_DHE_PSK_WITH_AES_256_CBC_SHA", 0x0091, 4279, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_RC4_128_SHA("TLS_RSA_PSK_WITH_RC4_128_SHA", 0x0092, 4279, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA("TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", 0x0093, 4279, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_AES_128_CBC_SHA("TLS_RSA_PSK_WITH_AES_128_CBC_SHA", 0x0094, 4279, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_AES_256_CBC_SHA("TLS_RSA_PSK_WITH_AES_256_CBC_SHA", 0x0095, 4279, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_SEED_CBC_SHA("TLS_RSA_WITH_SEED_CBC_SHA", 0x0096, 4162, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_SEED_CBC_SHA("TLS_DH_DSS_WITH_SEED_CBC_SHA", 0x0097, 4162, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_SEED_CBC_SHA("TLS_DH_RSA_WITH_SEED_CBC_SHA", 0x0098, 4162, MAX_VALUE, MAX_VALUE), + // TLS_DHE_DSS_WITH_SEED_CBC_SHA("TLS_DHE_DSS_WITH_SEED_CBC_SHA", 0x0099, 4162, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_SEED_CBC_SHA("TLS_DHE_RSA_WITH_SEED_CBC_SHA", 0x009a, 4162, MAX_VALUE, MAX_VALUE), + // TLS_DH_anon_WITH_SEED_CBC_SHA("TLS_DH_anon_WITH_SEED_CBC_SHA", 0x009b, 4162, MAX_VALUE, MAX_VALUE), + TLS_RSA_WITH_AES_128_GCM_SHA256("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x009c, 5288, 8, 21), + TLS_RSA_WITH_AES_256_GCM_SHA384("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x009d, 5288, 8, 21), + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x009e, 5288, 8, 21), + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x009f, 5288, 8, 21), + // TLS_DH_RSA_WITH_AES_128_GCM_SHA256("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0x00a0, 5288, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_AES_256_GCM_SHA384("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0x00a1, 5288, MAX_VALUE, MAX_VALUE), + TLS_DHE_DSS_WITH_AES_128_GCM_SHA256("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x00a2, 5288, 8, 21), + TLS_DHE_DSS_WITH_AES_256_GCM_SHA384("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x00a3, 5288, 8, 21), + // TLS_DH_DSS_WITH_AES_128_GCM_SHA256("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0x00a4, 5288, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_AES_256_GCM_SHA384("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0x00a5, 5288, MAX_VALUE, MAX_VALUE), + TLS_DH_anon_WITH_AES_128_GCM_SHA256("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x00a6, 5288, 8, 21), + TLS_DH_anon_WITH_AES_256_GCM_SHA384("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x00a7, 5288, 8, 21), + // TLS_PSK_WITH_AES_128_GCM_SHA256("TLS_PSK_WITH_AES_128_GCM_SHA256", 0x00a8, 5487, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_AES_256_GCM_SHA384("TLS_PSK_WITH_AES_256_GCM_SHA384", 0x00a9, 5487, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_AES_128_GCM_SHA256("TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", 0x00aa, 5487, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_AES_256_GCM_SHA384("TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", 0x00ab, 5487, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_AES_128_GCM_SHA256("TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", 0x00ac, 5487, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_AES_256_GCM_SHA384("TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", 0x00ad, 5487, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_AES_128_CBC_SHA256("TLS_PSK_WITH_AES_128_CBC_SHA256", 0x00ae, 5487, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_AES_256_CBC_SHA384("TLS_PSK_WITH_AES_256_CBC_SHA384", 0x00af, 5487, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_NULL_SHA256("TLS_PSK_WITH_NULL_SHA256", 0x00b0, 5487, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_NULL_SHA384("TLS_PSK_WITH_NULL_SHA384", 0x00b1, 5487, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_AES_128_CBC_SHA256("TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", 0x00b2, 5487, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_AES_256_CBC_SHA384("TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", 0x00b3, 5487, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_NULL_SHA256("TLS_DHE_PSK_WITH_NULL_SHA256", 0x00b4, 5487, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_NULL_SHA384("TLS_DHE_PSK_WITH_NULL_SHA384", 0x00b5, 5487, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_AES_128_CBC_SHA256("TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", 0x00b6, 5487, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_AES_256_CBC_SHA384("TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", 0x00b7, 5487, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_NULL_SHA256("TLS_RSA_PSK_WITH_NULL_SHA256", 0x00b8, 5487, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_NULL_SHA384("TLS_RSA_PSK_WITH_NULL_SHA384", 0x00b9, 5487, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00ba, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bb, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00bc, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bd, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00be, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", 0x00bf, 5932, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c0, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c1, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c2, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c3, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c4, 5932, MAX_VALUE, MAX_VALUE), + // TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", 0x00c5, 5932, MAX_VALUE, MAX_VALUE), + TLS_EMPTY_RENEGOTIATION_INFO_SCSV("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", 0x00ff, 5746, 6, 14), + TLS_ECDH_ECDSA_WITH_NULL_SHA("TLS_ECDH_ECDSA_WITH_NULL_SHA", 0xc001, 4492, 7, 14), + TLS_ECDH_ECDSA_WITH_RC4_128_SHA("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", 0xc002, 4492, 7, 14), + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xc003, 4492, 7, 14), + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", 0xc004, 4492, 7, 14), + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", 0xc005, 4492, 7, 14), + TLS_ECDHE_ECDSA_WITH_NULL_SHA("TLS_ECDHE_ECDSA_WITH_NULL_SHA", 0xc006, 4492, 7, 14), + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 0xc007, 4492, 7, 14), + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xc008, 4492, 7, 14), + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", 0xc009, 4492, 7, 14), + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", 0xc00a, 4492, 7, 14), + TLS_ECDH_RSA_WITH_NULL_SHA("TLS_ECDH_RSA_WITH_NULL_SHA", 0xc00b, 4492, 7, 14), + TLS_ECDH_RSA_WITH_RC4_128_SHA("TLS_ECDH_RSA_WITH_RC4_128_SHA", 0xc00c, 4492, 7, 14), + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", 0xc00d, 4492, 7, 14), + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", 0xc00e, 4492, 7, 14), + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", 0xc00f, 4492, 7, 14), + TLS_ECDHE_RSA_WITH_NULL_SHA("TLS_ECDHE_RSA_WITH_NULL_SHA", 0xc010, 4492, 7, 14), + TLS_ECDHE_RSA_WITH_RC4_128_SHA("TLS_ECDHE_RSA_WITH_RC4_128_SHA", 0xc011, 4492, 7, 14), + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", 0xc012, 4492, 7, 14), + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 0xc013, 4492, 7, 14), + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 0xc014, 4492, 7, 14), + TLS_ECDH_anon_WITH_NULL_SHA("TLS_ECDH_anon_WITH_NULL_SHA", 0xc015, 4492, 7, 14), + TLS_ECDH_anon_WITH_RC4_128_SHA("TLS_ECDH_anon_WITH_RC4_128_SHA", 0xc016, 4492, 7, 14), + TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", 0xc017, 4492, 7, 14), + TLS_ECDH_anon_WITH_AES_128_CBC_SHA("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", 0xc018, 4492, 7, 14), + TLS_ECDH_anon_WITH_AES_256_CBC_SHA("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", 0xc019, 4492, 7, 14), + // TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA("TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", 0xc01a, 5054, MAX_VALUE, MAX_VALUE), + // TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA("TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", 0xc01b, 5054, MAX_VALUE, MAX_VALUE), + // TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", 0xc01c, 5054, MAX_VALUE, MAX_VALUE), + // TLS_SRP_SHA_WITH_AES_128_CBC_SHA("TLS_SRP_SHA_WITH_AES_128_CBC_SHA", 0xc01d, 5054, MAX_VALUE, MAX_VALUE), + // TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA("TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", 0xc01e, 5054, MAX_VALUE, MAX_VALUE), + // TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA("TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", 0xc01f, 5054, MAX_VALUE, MAX_VALUE), + // TLS_SRP_SHA_WITH_AES_256_CBC_SHA("TLS_SRP_SHA_WITH_AES_256_CBC_SHA", 0xc020, 5054, MAX_VALUE, MAX_VALUE), + // TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xc021, 5054, MAX_VALUE, MAX_VALUE), + // TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xc022, 5054, MAX_VALUE, MAX_VALUE), + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 0xc023, 5289, 7, 21), + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", 0xc024, 5289, 7, 21), + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", 0xc025, 5289, 7, 21), + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", 0xc026, 5289, 7, 21), + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", 0xc027, 5289, 7, 21), + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", 0xc028, 5289, 7, 21), + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", 0xc029, 5289, 7, 21), + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", 0xc02a, 5289, 7, 21), + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02b, 5289, 8, 21), + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02c, 5289, 8, 21), + TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02d, 5289, 8, 21), + TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02e, 5289, 8, 21), + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0xc02f, 5289, 8, 21), + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0xc030, 5289, 8, 21), + TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0xc031, 5289, 8, 21), + TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0xc032, 5289, 8, 21), + // TLS_ECDHE_PSK_WITH_RC4_128_SHA("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xc033, 5489, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xc034, 5489, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", 0xc035, 5489, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", 0xc036, 5489, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", 0xc037, 5489, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", 0xc038, 5489, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_PSK_WITH_NULL_SHA("TLS_ECDHE_PSK_WITH_NULL_SHA", 0xc039, 5489, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_PSK_WITH_NULL_SHA256("TLS_ECDHE_PSK_WITH_NULL_SHA256", 0xc03a, 5489, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_PSK_WITH_NULL_SHA384("TLS_ECDHE_PSK_WITH_NULL_SHA384", 0xc03b, 5489, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_ARIA_128_CBC_SHA256("TLS_RSA_WITH_ARIA_128_CBC_SHA256", 0xc03c, 6209, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_ARIA_256_CBC_SHA384("TLS_RSA_WITH_ARIA_256_CBC_SHA384", 0xc03d, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256("TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256", 0xc03e, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384("TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384", 0xc03f, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256("TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256", 0xc040, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384("TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384", 0xc041, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256("TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", 0xc042, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384("TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", 0xc043, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256("TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", 0xc044, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384("TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", 0xc045, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DH_anon_WITH_ARIA_128_CBC_SHA256("TLS_DH_anon_WITH_ARIA_128_CBC_SHA256", 0xc046, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DH_anon_WITH_ARIA_256_CBC_SHA384("TLS_DH_anon_WITH_ARIA_256_CBC_SHA384", 0xc047, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256("TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", 0xc048, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384("TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", 0xc049, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256("TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", 0xc04a, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384("TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", 0xc04b, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256("TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", 0xc04c, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384("TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", 0xc04d, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256("TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", 0xc04e, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384("TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", 0xc04f, 6209, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_ARIA_128_GCM_SHA256("TLS_RSA_WITH_ARIA_128_GCM_SHA256", 0xc050, 6209, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_ARIA_256_GCM_SHA384("TLS_RSA_WITH_ARIA_256_GCM_SHA384", 0xc051, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256("TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256", 0xc052, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384("TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384", 0xc053, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256("TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256", 0xc054, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384("TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384", 0xc055, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256("TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256", 0xc056, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384("TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384", 0xc057, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256("TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256", 0xc058, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384("TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384", 0xc059, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DH_anon_WITH_ARIA_128_GCM_SHA256("TLS_DH_anon_WITH_ARIA_128_GCM_SHA256", 0xc05a, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DH_anon_WITH_ARIA_256_GCM_SHA384("TLS_DH_anon_WITH_ARIA_256_GCM_SHA384", 0xc05b, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256("TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", 0xc05c, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384("TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", 0xc05d, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256("TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", 0xc05e, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384("TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", 0xc05f, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256("TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", 0xc060, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384("TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", 0xc061, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256("TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", 0xc062, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384("TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", 0xc063, 6209, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_ARIA_128_CBC_SHA256("TLS_PSK_WITH_ARIA_128_CBC_SHA256", 0xc064, 6209, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_ARIA_256_CBC_SHA384("TLS_PSK_WITH_ARIA_256_CBC_SHA384", 0xc065, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256("TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", 0xc066, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384("TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", 0xc067, 6209, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256("TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256", 0xc068, 6209, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384("TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384", 0xc069, 6209, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_ARIA_128_GCM_SHA256("TLS_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06a, 6209, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_ARIA_256_GCM_SHA384("TLS_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06b, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256("TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06c, 6209, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384("TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06d, 6209, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256("TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06e, 6209, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384("TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06f, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256("TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", 0xc070, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384("TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", 0xc071, 6209, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc072, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc073, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc074, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc075, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256("TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc076, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384("TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc077, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256("TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc078, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384("TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc079, 6367, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256("TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07a, 6367, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384("TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07b, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256("TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07c, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384("TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07d, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256("TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07e, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384("TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07f, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256("TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", 0xc080, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384("TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", 0xc081, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256("TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256", 0xc082, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384("TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384", 0xc083, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256("TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256", 0xc084, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384("TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384", 0xc085, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc086, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc087, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc088, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc089, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256("TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc08a, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384("TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc08b, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256("TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc08c, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384("TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc08d, 6367, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256("TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc08e, 6367, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384("TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc08f, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256("TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc090, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384("TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc091, 6367, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256("TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc092, 6367, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384("TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc093, 6367, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256("TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc094, 6367, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384("TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc095, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256("TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc096, 6367, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384("TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc097, 6367, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256("TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc098, 6367, MAX_VALUE, MAX_VALUE), + // TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384("TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc099, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256("TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc09a, 6367, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384("TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc09b, 6367, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_AES_128_CCM("TLS_RSA_WITH_AES_128_CCM", 0xc09c, 6655, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_AES_256_CCM("TLS_RSA_WITH_AES_256_CCM", 0xc09d, 6655, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_AES_128_CCM("TLS_DHE_RSA_WITH_AES_128_CCM", 0xc09e, 6655, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_AES_256_CCM("TLS_DHE_RSA_WITH_AES_256_CCM", 0xc09f, 6655, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_AES_128_CCM_8("TLS_RSA_WITH_AES_128_CCM_8", 0xc0a0, 6655, MAX_VALUE, MAX_VALUE), + // TLS_RSA_WITH_AES_256_CCM_8("TLS_RSA_WITH_AES_256_CCM_8", 0xc0a1, 6655, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_AES_128_CCM_8("TLS_DHE_RSA_WITH_AES_128_CCM_8", 0xc0a2, 6655, MAX_VALUE, MAX_VALUE), + // TLS_DHE_RSA_WITH_AES_256_CCM_8("TLS_DHE_RSA_WITH_AES_256_CCM_8", 0xc0a3, 6655, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_AES_128_CCM("TLS_PSK_WITH_AES_128_CCM", 0xc0a4, 6655, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_AES_256_CCM("TLS_PSK_WITH_AES_256_CCM", 0xc0a5, 6655, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_AES_128_CCM("TLS_DHE_PSK_WITH_AES_128_CCM", 0xc0a6, 6655, MAX_VALUE, MAX_VALUE), + // TLS_DHE_PSK_WITH_AES_256_CCM("TLS_DHE_PSK_WITH_AES_256_CCM", 0xc0a7, 6655, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_AES_128_CCM_8("TLS_PSK_WITH_AES_128_CCM_8", 0xc0a8, 6655, MAX_VALUE, MAX_VALUE), + // TLS_PSK_WITH_AES_256_CCM_8("TLS_PSK_WITH_AES_256_CCM_8", 0xc0a9, 6655, MAX_VALUE, MAX_VALUE), + // TLS_PSK_DHE_WITH_AES_128_CCM_8("TLS_PSK_DHE_WITH_AES_128_CCM_8", 0xc0aa, 6655, MAX_VALUE, MAX_VALUE), + // TLS_PSK_DHE_WITH_AES_256_CCM_8("TLS_PSK_DHE_WITH_AES_256_CCM_8", 0xc0ab, 6655, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_ECDSA_WITH_AES_128_CCM("TLS_ECDHE_ECDSA_WITH_AES_128_CCM", 0xc0ac, 7251, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_ECDSA_WITH_AES_256_CCM("TLS_ECDHE_ECDSA_WITH_AES_256_CCM", 0xc0ad, 7251, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8("TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", 0xc0ae, 7251, MAX_VALUE, MAX_VALUE), + // TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8("TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", 0xc0af, 7251, MAX_VALUE, MAX_VALUE), + ; + + final String javaName; + + /** + * @param javaName the name used by Java APIs for this cipher suite. Different than the IANA name + * for older cipher suites because the prefix is {@code SSL_} instead of {@code TLS_}. + * @param value the integer identifier for this cipher suite. (Documentation only.) + * @param rfc the RFC describing this cipher suite. (Documentation only.) + * @param sinceJavaVersion the first major Java release supporting this cipher suite. + * @param sinceAndroidVersion the first Android SDK version supporting this cipher suite. + */ + private CipherSuite( + String javaName, int value, int rfc, int sinceJavaVersion, int sinceAndroidVersion) { + this.javaName = javaName; + } + + public static CipherSuite forJavaName(String javaName) { + return javaName.startsWith("SSL_") + ? valueOf("TLS_" + javaName.substring(4)) + : valueOf(javaName); + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/ConnectionSpec.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/ConnectionSpec.java new file mode 100644 index 000000000..457e9c301 --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/ConnectionSpec.java @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2014 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal; + +import java.util.Arrays; +import java.util.List; +import javax.net.ssl.SSLSocket; + +/** + * Specifies configuration for the socket connection that HTTP traffic travels through. For {@code + * https:} URLs, this includes the TLS version and cipher suites to use when negotiating a secure + * connection. + */ +public final class ConnectionSpec { + + // This is a subset of the cipher suites supported in Chrome 37, current as of 2014-10-5. + // All of these suites are available on Android 5.0; earlier releases support a subset of + // these suites. https://github.com/square/okhttp/issues/330 + private static final CipherSuite[] APPROVED_CIPHER_SUITES = new CipherSuite[] { + 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, + + // Note that the following cipher suites are all on HTTP/2's bad cipher suites list. We'll + // continue to include them until better suites are commonly available. For example, none + // of the better cipher suites listed above shipped with Android 4.4 or Java 7. + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, + CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA, + }; + + /** A modern TLS connection with extensions like SNI and ALPN available. */ + public static final ConnectionSpec MODERN_TLS = new Builder(true) + .cipherSuites(APPROVED_CIPHER_SUITES) + .tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0) + .supportsTlsExtensions(true) + .build(); + + /** A backwards-compatible fallback connection for interop with obsolete servers. */ + public static final ConnectionSpec COMPATIBLE_TLS = new Builder(MODERN_TLS) + .tlsVersions(TlsVersion.TLS_1_0) + .supportsTlsExtensions(true) + .build(); + + /** Unencrypted, unauthenticated connections for {@code http:} URLs. */ + public static final ConnectionSpec CLEARTEXT = new Builder(false).build(); + + final boolean tls; + + /** + * Used if tls == true. The cipher suites to set on the SSLSocket. {@code null} means "use + * default set". + */ + private final String[] cipherSuites; + + /** Used if tls == true. The TLS protocol versions to use. */ + private final String[] tlsVersions; + + final boolean supportsTlsExtensions; + + private ConnectionSpec(Builder builder) { + this.tls = builder.tls; + this.cipherSuites = builder.cipherSuites; + this.tlsVersions = builder.tlsVersions; + this.supportsTlsExtensions = builder.supportsTlsExtensions; + } + + public boolean isTls() { + return tls; + } + + /** + * Returns the cipher suites to use for a connection. This method can return {@code null} if the + * cipher suites enabled by default should be used. + */ + public List<CipherSuite> cipherSuites() { + if (cipherSuites == null) { + return null; + } + CipherSuite[] result = new CipherSuite[cipherSuites.length]; + for (int i = 0; i < cipherSuites.length; i++) { + result[i] = CipherSuite.forJavaName(cipherSuites[i]); + } + return Util.immutableList(result); + } + + public List<TlsVersion> tlsVersions() { + TlsVersion[] result = new TlsVersion[tlsVersions.length]; + for (int i = 0; i < tlsVersions.length; i++) { + result[i] = TlsVersion.forJavaName(tlsVersions[i]); + } + return Util.immutableList(result); + } + + public boolean supportsTlsExtensions() { + return supportsTlsExtensions; + } + + /** Applies this spec to {@code sslSocket}. */ + public void apply(SSLSocket sslSocket, boolean isFallback) { + ConnectionSpec specToApply = supportedSpec(sslSocket, isFallback); + + sslSocket.setEnabledProtocols(specToApply.tlsVersions); + + String[] cipherSuitesToEnable = specToApply.cipherSuites; + // null means "use default set". + if (cipherSuitesToEnable != null) { + sslSocket.setEnabledCipherSuites(cipherSuitesToEnable); + } + } + + /** + * Returns a copy of this that omits cipher suites and TLS versions not enabled by + * {@code sslSocket}. + */ + private ConnectionSpec supportedSpec(SSLSocket sslSocket, boolean isFallback) { + String[] cipherSuitesToEnable = null; + if (cipherSuites != null) { + String[] cipherSuitesToSelectFrom = sslSocket.getEnabledCipherSuites(); + cipherSuitesToEnable = + Util.intersect(String.class, cipherSuites, cipherSuitesToSelectFrom); + } + + if (isFallback) { + // In accordance with https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00 + // the SCSV cipher is added to signal that a protocol fallback has taken place. + final String fallbackScsv = "TLS_FALLBACK_SCSV"; + boolean socketSupportsFallbackScsv = + Arrays.asList(sslSocket.getSupportedCipherSuites()).contains(fallbackScsv); + + if (socketSupportsFallbackScsv) { + // Add the SCSV cipher to the set of enabled cipher suites iff it is supported. + String[] oldEnabledCipherSuites = cipherSuitesToEnable != null + ? cipherSuitesToEnable + : sslSocket.getEnabledCipherSuites(); + String[] newEnabledCipherSuites = new String[oldEnabledCipherSuites.length + 1]; + System.arraycopy(oldEnabledCipherSuites, 0, + newEnabledCipherSuites, 0, oldEnabledCipherSuites.length); + newEnabledCipherSuites[newEnabledCipherSuites.length - 1] = fallbackScsv; + cipherSuitesToEnable = newEnabledCipherSuites; + } + } + + String[] protocolsToSelectFrom = sslSocket.getEnabledProtocols(); + String[] protocolsToEnable = Util.intersect(String.class, tlsVersions, protocolsToSelectFrom); + return new Builder(this) + .cipherSuites(cipherSuitesToEnable) + .tlsVersions(protocolsToEnable) + .build(); + } + + /** + * Returns {@code true} if the socket, as currently configured, supports this ConnectionSpec. + * In order for a socket to be compatible the enabled cipher suites and protocols must intersect. + * + * <p>For cipher suites, at least one of the {@link #cipherSuites() required cipher suites} must + * match the socket's enabled cipher suites. If there are no required cipher suites the socket + * must have at least one cipher suite enabled. + * + * <p>For protocols, at least one of the {@link #tlsVersions() required protocols} must match the + * socket's enabled protocols. + */ + public boolean isCompatible(SSLSocket socket) { + if (!tls) { + return false; + } + + String[] enabledProtocols = socket.getEnabledProtocols(); + boolean requiredProtocolsEnabled = nonEmptyIntersection(tlsVersions, enabledProtocols); + if (!requiredProtocolsEnabled) { + return false; + } + + boolean requiredCiphersEnabled; + if (cipherSuites == null) { + requiredCiphersEnabled = socket.getEnabledCipherSuites().length > 0; + } else { + String[] enabledCipherSuites = socket.getEnabledCipherSuites(); + requiredCiphersEnabled = nonEmptyIntersection(cipherSuites, enabledCipherSuites); + } + return requiredCiphersEnabled; + } + + /** + * An N*M intersection that terminates if any intersection is found. The sizes of both + * arguments are assumed to be so small, and the likelihood of an intersection so great, that it + * is not worth the CPU cost of sorting or the memory cost of hashing. + */ + private static boolean nonEmptyIntersection(String[] a, String[] b) { + if (a == null || b == null || a.length == 0 || b.length == 0) { + return false; + } + for (String toFind : a) { + if (contains(b, toFind)) { + return true; + } + } + return false; + } + + private static <T> boolean contains(T[] array, T value) { + for (T arrayValue : array) { + if (Util.equal(value, arrayValue)) { + return true; + } + } + return false; + } + + @Override public boolean equals(Object other) { + if (!(other instanceof ConnectionSpec)) return false; + if (other == this) return true; + + ConnectionSpec that = (ConnectionSpec) other; + if (this.tls != that.tls) return false; + + if (tls) { + if (!Arrays.equals(this.cipherSuites, that.cipherSuites)) return false; + if (!Arrays.equals(this.tlsVersions, that.tlsVersions)) return false; + if (this.supportsTlsExtensions != that.supportsTlsExtensions) return false; + } + + return true; + } + + @Override public int hashCode() { + int result = 17; + if (tls) { + result = 31 * result + Arrays.hashCode(cipherSuites); + result = 31 * result + Arrays.hashCode(tlsVersions); + result = 31 * result + (supportsTlsExtensions ? 0 : 1); + } + return result; + } + + @Override public String toString() { + if (tls) { + List<CipherSuite> cipherSuites = cipherSuites(); + String cipherSuitesString = cipherSuites == null ? "[use default]" : cipherSuites.toString(); + return "ConnectionSpec(cipherSuites=" + cipherSuitesString + + ", tlsVersions=" + tlsVersions() + + ", supportsTlsExtensions=" + supportsTlsExtensions + + ")"; + } else { + return "ConnectionSpec()"; + } + } + + public static final class Builder { + private boolean tls; + private String[] cipherSuites; + private String[] tlsVersions; + private boolean supportsTlsExtensions; + + public Builder(boolean tls) { + this.tls = tls; + } + + public Builder(ConnectionSpec connectionSpec) { + this.tls = connectionSpec.tls; + this.cipherSuites = connectionSpec.cipherSuites; + this.tlsVersions = connectionSpec.tlsVersions; + this.supportsTlsExtensions = connectionSpec.supportsTlsExtensions; + } + + public Builder cipherSuites(CipherSuite... cipherSuites) { + if (!tls) throw new IllegalStateException("no cipher suites for cleartext connections"); + + // Convert enums to the string names Java wants. This makes a defensive copy! + String[] strings = new String[cipherSuites.length]; + for (int i = 0; i < cipherSuites.length; i++) { + strings[i] = cipherSuites[i].javaName; + } + this.cipherSuites = strings; + return this; + } + + public Builder cipherSuites(String... cipherSuites) { + if (!tls) throw new IllegalStateException("no cipher suites for cleartext connections"); + + if (cipherSuites == null) { + this.cipherSuites = null; + } else { + // This makes a defensive copy! + this.cipherSuites = cipherSuites.clone(); + } + + return this; + } + + public Builder tlsVersions(TlsVersion... tlsVersions) { + if (!tls) throw new IllegalStateException("no TLS versions for cleartext connections"); + if (tlsVersions.length == 0) { + throw new IllegalArgumentException("At least one TlsVersion is required"); + } + + // Convert enums to the string names Java wants. This makes a defensive copy! + String[] strings = new String[tlsVersions.length]; + for (int i = 0; i < tlsVersions.length; i++) { + strings[i] = tlsVersions[i].javaName; + } + this.tlsVersions = strings; + return this; + } + + public Builder tlsVersions(String... tlsVersions) { + if (!tls) throw new IllegalStateException("no TLS versions for cleartext connections"); + + if (tlsVersions == null) { + this.tlsVersions = null; + } else { + // This makes a defensive copy! + this.tlsVersions = tlsVersions.clone(); + } + + return this; + } + + public Builder supportsTlsExtensions(boolean supportsTlsExtensions) { + if (!tls) throw new IllegalStateException("no TLS extensions for cleartext connections"); + this.supportsTlsExtensions = supportsTlsExtensions; + return this; + } + + public ConnectionSpec build() { + return new ConnectionSpec(this); + } + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/OptionalMethod.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/OptionalMethod.java new file mode 100644 index 000000000..cb9357fb1 --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/OptionalMethod.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Duck-typing for methods: Represents a method that may or may not be present on an object. + * + * @param <T> the type of the object the method might be on, typically an interface or base class + */ +public class OptionalMethod<T> { + + /** The return type of the method. null means "don't care". */ + private final Class<?> returnType; + + private final String methodName; + + @SuppressWarnings("rawtypes") + private final Class[] methodParams; + + /** + * Creates an optional method. + * + * @param returnType the return type to required, null if it does not matter + * @param methodName the name of the method + * @param methodParams the method parameter types + */ + @SuppressWarnings("rawtypes") + public OptionalMethod(Class<?> returnType, String methodName, Class... methodParams) { + this.returnType = returnType; + this.methodName = methodName; + this.methodParams = methodParams; + } + + /** + * Returns true if the method exists on the supplied {@code target}. + */ + public boolean isSupported(T target) { + return getMethod(target.getClass()) != null; + } + + /** + * Invokes the method on {@code target} with {@code args}. If the method does not exist or is not + * public then {@code null} is returned. See also + * {@link #invokeOptionalWithoutCheckedException(Object, Object...)}. + * + * @throws IllegalArgumentException if the arguments are invalid + * @throws InvocationTargetException if the invocation throws an exception + */ + public Object invokeOptional(T target, Object... args) throws InvocationTargetException { + Method m = getMethod(target.getClass()); + if (m == null) { + return null; + } + try { + return m.invoke(target, args); + } catch (IllegalAccessException e) { + return null; + } + } + + /** + * Invokes the method on {@code target}. If the method does not exist or is not + * public then {@code null} is returned. Any RuntimeException thrown by the method is thrown, + * checked exceptions are wrapped in an {@link AssertionError}. + * + * @throws IllegalArgumentException if the arguments are invalid + */ + public Object invokeOptionalWithoutCheckedException(T target, Object... args) { + try { + return invokeOptional(target, args); + } catch (InvocationTargetException e) { + Throwable targetException = e.getTargetException(); + if (targetException instanceof RuntimeException) { + throw (RuntimeException) targetException; + } + AssertionError error = new AssertionError("Unexpected exception"); + error.initCause(targetException); + throw error; + } + } + + /** + * Invokes the method on {@code target} with {@code args}. Throws an error if the method is not + * supported. See also {@link #invokeWithoutCheckedException(Object, Object...)}. + * + * @throws IllegalArgumentException if the arguments are invalid + * @throws InvocationTargetException if the invocation throws an exception + */ + public Object invoke(T target, Object... args) throws InvocationTargetException { + Method m = getMethod(target.getClass()); + if (m == null) { + throw new AssertionError("Method " + methodName + " not supported for object " + target); + } + try { + return m.invoke(target, args); + } catch (IllegalAccessException e) { + // Method should be public: we checked. + AssertionError error = new AssertionError("Unexpectedly could not call: " + m); + error.initCause(e); + throw error; + } + } + + /** + * Invokes the method on {@code target}. Throws an error if the method is not supported. Any + * RuntimeException thrown by the method is thrown, checked exceptions are wrapped in + * an {@link AssertionError}. + * + * @throws IllegalArgumentException if the arguments are invalid + */ + public Object invokeWithoutCheckedException(T target, Object... args) { + try { + return invoke(target, args); + } catch (InvocationTargetException e) { + Throwable targetException = e.getTargetException(); + if (targetException instanceof RuntimeException) { + throw (RuntimeException) targetException; + } + AssertionError error = new AssertionError("Unexpected exception"); + error.initCause(targetException); + throw error; + } + } + + /** + * Perform a lookup for the method. No caching. + * In order to return a method the method name and arguments must match those specified when + * the {@link OptionalMethod} was created. If the return type is specified (i.e. non-null) it + * must also be compatible. The method must also be public. + */ + private Method getMethod(Class<?> clazz) { + Method method = null; + if (methodName != null) { + method = getPublicMethod(clazz, methodName, methodParams); + if (method != null + && returnType != null + && !returnType.isAssignableFrom(method.getReturnType())) { + + // If the return type is non-null it must be compatible. + method = null; + } + } + return method; + } + + @SuppressWarnings("rawtypes") + private static Method getPublicMethod(Class<?> clazz, String methodName, Class[] parameterTypes) { + Method method = null; + try { + method = clazz.getMethod(methodName, parameterTypes); + if ((method.getModifiers() & Modifier.PUBLIC) == 0) { + method = null; + } + } catch (NoSuchMethodException e) { + // None. + } + return method; + } +} + diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java new file mode 100644 index 000000000..5561c654f --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2012 Square, Inc. + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal; + +import java.io.IOException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.net.ssl.SSLSocket; +import okio.Buffer; + +/** + * Access to platform-specific features. + * + * <h3>Server name indication (SNI)</h3> + * Supported on Android 2.3+. + * + * <h3>Session Tickets</h3> + * Supported on Android 2.3+. + * + * <h3>Android Traffic Stats (Socket Tagging)</h3> + * Supported on Android 4.0+. + * + * <h3>ALPN (Application Layer Protocol Negotiation)</h3> + * Supported on Android 5.0+. The APIs were present in Android 4.4, but that implementation was + * unstable. + * + * Supported on OpenJDK 7 and 8 (via the JettyALPN-boot library). + */ +public class Platform { + public static final Logger logger = Logger.getLogger(Platform.class.getName()); + + private static final Platform PLATFORM = findPlatform(); + + public static Platform get() { + return PLATFORM; + } + + /** Prefix used on custom headers. */ + public String getPrefix() { + return "OkHttp"; + } + + public void logW(String warning) { + System.out.println(warning); + } + + public void tagSocket(Socket socket) throws SocketException { + } + + public void untagSocket(Socket socket) throws SocketException { + } + + /** + * Configure TLS extensions on {@code sslSocket} for {@code route}. + * + * @param hostname non-null for client-side handshakes; null for + * server-side handshakes. + */ + public void configureTlsExtensions(SSLSocket sslSocket, String hostname, + List<Protocol> protocols) { + } + + /** + * Called after the TLS handshake to release resources allocated by {@link + * #configureTlsExtensions}. + */ + public void afterHandshake(SSLSocket sslSocket) { + } + + /** Returns the negotiated protocol, or null if no protocol was negotiated. */ + public String getSelectedProtocol(SSLSocket socket) { + return null; + } + + public void connectSocket(Socket socket, InetSocketAddress address, + int connectTimeout) throws IOException { + socket.connect(address, connectTimeout); + } + + /** Attempt to match the host runtime to a capable Platform implementation. */ + private static Platform findPlatform() { + // Attempt to find Android 2.3+ APIs. + try { + try { + Class.forName("com.android.org.conscrypt.OpenSSLSocketImpl"); + } catch (ClassNotFoundException e) { + // Older platform before being unbundled. + Class.forName("org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl"); + } + + OptionalMethod<Socket> setUseSessionTickets + = new OptionalMethod<Socket>(null, "setUseSessionTickets", boolean.class); + OptionalMethod<Socket> setHostname + = new OptionalMethod<Socket>(null, "setHostname", String.class); + Method trafficStatsTagSocket = null; + Method trafficStatsUntagSocket = null; + OptionalMethod<Socket> getAlpnSelectedProtocol = null; + OptionalMethod<Socket> setAlpnProtocols = null; + + // Attempt to find Android 4.0+ APIs. + try { + Class<?> trafficStats = Class.forName("android.net.TrafficStats"); + trafficStatsTagSocket = trafficStats.getMethod("tagSocket", Socket.class); + trafficStatsUntagSocket = trafficStats.getMethod("untagSocket", Socket.class); + + // Attempt to find Android 5.0+ APIs. + try { + Class.forName("android.net.Network"); // Arbitrary class added in Android 5.0. + getAlpnSelectedProtocol = + new OptionalMethod<Socket>(byte[].class, "getAlpnSelectedProtocol"); + setAlpnProtocols = new OptionalMethod<Socket>(null, "setAlpnProtocols", byte[].class); + } catch (ClassNotFoundException ignored) { + } + } catch (ClassNotFoundException ignored) { + } catch (NoSuchMethodException ignored) { + } + + return new Android(setUseSessionTickets, setHostname, trafficStatsTagSocket, + trafficStatsUntagSocket, getAlpnSelectedProtocol, setAlpnProtocols); + } catch (ClassNotFoundException ignored) { + // This isn't an Android runtime. + } + + // Find Jetty's ALPN extension for OpenJDK. + try { + String negoClassName = "org.eclipse.jetty.alpn.ALPN"; + Class<?> negoClass = Class.forName(negoClassName); + Class<?> providerClass = Class.forName(negoClassName + "$Provider"); + Class<?> clientProviderClass = Class.forName(negoClassName + "$ClientProvider"); + Class<?> serverProviderClass = Class.forName(negoClassName + "$ServerProvider"); + Method putMethod = negoClass.getMethod("put", SSLSocket.class, providerClass); + Method getMethod = negoClass.getMethod("get", SSLSocket.class); + Method removeMethod = negoClass.getMethod("remove", SSLSocket.class); + return new JdkWithJettyBootPlatform( + putMethod, getMethod, removeMethod, clientProviderClass, serverProviderClass); + } catch (ClassNotFoundException ignored) { + } catch (NoSuchMethodException ignored) { + } + + return new Platform(); + } + + /** Android 2.3 or better. */ + private static class Android extends Platform { + private final OptionalMethod<Socket> setUseSessionTickets; + private final OptionalMethod<Socket> setHostname; + + // Non-null on Android 4.0+. + private final Method trafficStatsTagSocket; + private final Method trafficStatsUntagSocket; + + // Non-null on Android 5.0+. + private final OptionalMethod<Socket> getAlpnSelectedProtocol; + private final OptionalMethod<Socket> setAlpnProtocols; + + public Android(OptionalMethod<Socket> setUseSessionTickets, OptionalMethod<Socket> setHostname, + Method trafficStatsTagSocket, Method trafficStatsUntagSocket, + OptionalMethod<Socket> getAlpnSelectedProtocol, OptionalMethod<Socket> setAlpnProtocols) { + this.setUseSessionTickets = setUseSessionTickets; + this.setHostname = setHostname; + this.trafficStatsTagSocket = trafficStatsTagSocket; + this.trafficStatsUntagSocket = trafficStatsUntagSocket; + this.getAlpnSelectedProtocol = getAlpnSelectedProtocol; + this.setAlpnProtocols = setAlpnProtocols; + } + + @Override public void connectSocket(Socket socket, InetSocketAddress address, + int connectTimeout) throws IOException { + try { + socket.connect(address, connectTimeout); + } catch (SecurityException se) { + // Before android 4.3, socket.connect could throw a SecurityException + // if opening a socket resulted in an EACCES error. + IOException ioException = new IOException("Exception in connect"); + ioException.initCause(se); + throw ioException; + } + } + + @Override public void configureTlsExtensions( + SSLSocket sslSocket, String hostname, List<Protocol> protocols) { + // Enable SNI and session tickets. + if (hostname != null) { + setUseSessionTickets.invokeOptionalWithoutCheckedException(sslSocket, true); + setHostname.invokeOptionalWithoutCheckedException(sslSocket, hostname); + } + + // Enable ALPN. + if (setAlpnProtocols != null && setAlpnProtocols.isSupported(sslSocket)) { + Object[] parameters = { concatLengthPrefixed(protocols) }; + setAlpnProtocols.invokeWithoutCheckedException(sslSocket, parameters); + } + } + + @Override public String getSelectedProtocol(SSLSocket socket) { + if (getAlpnSelectedProtocol == null) return null; + if (!getAlpnSelectedProtocol.isSupported(socket)) return null; + + byte[] alpnResult = (byte[]) getAlpnSelectedProtocol.invokeWithoutCheckedException(socket); + return alpnResult != null ? new String(alpnResult, Util.UTF_8) : null; + } + + @Override public void tagSocket(Socket socket) throws SocketException { + if (trafficStatsTagSocket == null) return; + + try { + trafficStatsTagSocket.invoke(null, socket); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e.getCause()); + } + } + + @Override public void untagSocket(Socket socket) throws SocketException { + if (trafficStatsUntagSocket == null) return; + + try { + trafficStatsUntagSocket.invoke(null, socket); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e.getCause()); + } + } + } + + /** + * OpenJDK 7+ with {@code org.mortbay.jetty.alpn/alpn-boot} in the boot class path. + */ + private static class JdkWithJettyBootPlatform extends Platform { + private final Method putMethod; + private final Method getMethod; + private final Method removeMethod; + private final Class<?> clientProviderClass; + private final Class<?> serverProviderClass; + + public JdkWithJettyBootPlatform(Method putMethod, Method getMethod, Method removeMethod, + Class<?> clientProviderClass, Class<?> serverProviderClass) { + this.putMethod = putMethod; + this.getMethod = getMethod; + this.removeMethod = removeMethod; + this.clientProviderClass = clientProviderClass; + this.serverProviderClass = serverProviderClass; + } + + @Override public void configureTlsExtensions( + SSLSocket sslSocket, String hostname, List<Protocol> protocols) { + List<String> names = new ArrayList<String>(protocols.size()); + for (int i = 0, size = protocols.size(); i < size; i++) { + Protocol protocol = protocols.get(i); + if (protocol == Protocol.HTTP_1_0) continue; // No HTTP/1.0 for ALPN. + names.add(protocol.toString()); + } + try { + Object provider = Proxy.newProxyInstance(Platform.class.getClassLoader(), + new Class<?>[] { clientProviderClass, serverProviderClass }, new JettyNegoProvider(names)); + putMethod.invoke(null, sslSocket, provider); + } catch (InvocationTargetException e) { + throw new AssertionError(e); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + } + + @Override public void afterHandshake(SSLSocket sslSocket) { + try { + removeMethod.invoke(null, sslSocket); + } catch (IllegalAccessException ignored) { + throw new AssertionError(); + } catch (InvocationTargetException ignored) { + } + } + + @Override public String getSelectedProtocol(SSLSocket socket) { + try { + JettyNegoProvider provider = + (JettyNegoProvider) Proxy.getInvocationHandler(getMethod.invoke(null, socket)); + if (!provider.unsupported && provider.selected == null) { + logger.log(Level.INFO, "ALPN callback dropped: SPDY and HTTP/2 are disabled. " + + "Is alpn-boot on the boot class path?"); + return null; + } + return provider.unsupported ? null : provider.selected; + } catch (InvocationTargetException e) { + throw new AssertionError(); + } catch (IllegalAccessException e) { + throw new AssertionError(); + } + } + } + + /** + * Handle the methods of ALPN's ClientProvider and ServerProvider + * without a compile-time dependency on those interfaces. + */ + private static class JettyNegoProvider implements InvocationHandler { + /** This peer's supported protocols. */ + private final List<String> protocols; + /** Set when remote peer notifies ALPN is unsupported. */ + private boolean unsupported; + /** The protocol the server selected. */ + private String selected; + + public JettyNegoProvider(List<String> protocols) { + this.protocols = protocols; + } + + @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String methodName = method.getName(); + Class<?> returnType = method.getReturnType(); + if (args == null) { + args = Util.EMPTY_STRING_ARRAY; + } + if (methodName.equals("supports") && boolean.class == returnType) { + return true; // ALPN is supported. + } else if (methodName.equals("unsupported") && void.class == returnType) { + this.unsupported = true; // Peer doesn't support ALPN. + return null; + } else if (methodName.equals("protocols") && args.length == 0) { + return protocols; // Client advertises these protocols. + } else if ((methodName.equals("selectProtocol") || methodName.equals("select")) + && String.class == returnType && args.length == 1 && args[0] instanceof List) { + @SuppressWarnings("unchecked") + List<String> peerProtocols = (List) args[0]; + // Pick the first known protocol the peer advertises. + for (int i = 0, size = peerProtocols.size(); i < size; i++) { + if (protocols.contains(peerProtocols.get(i))) { + return selected = peerProtocols.get(i); + } + } + return selected = protocols.get(0); // On no intersection, try peer's first protocol. + } else if ((methodName.equals("protocolSelected") || methodName.equals("selected")) + && args.length == 1) { + this.selected = (String) args[0]; // Server selected this protocol. + return null; + } else { + return method.invoke(this, args); + } + } + } + + /** + * Returns the concatenation of 8-bit, length prefixed protocol names. + * http://tools.ietf.org/html/draft-agl-tls-nextprotoneg-04#page-4 + */ + public static byte[] concatLengthPrefixed(List<Protocol> protocols) { + Buffer result = new Buffer(); + for (int i = 0, size = protocols.size(); i < size; i++) { + Protocol protocol = protocols.get(i); + if (protocol == Protocol.HTTP_1_0) continue; // No HTTP/1.0 for ALPN. + result.writeByte(protocol.toString().length()); + result.writeUtf8(protocol.toString()); + } + return result.readByteArray(); + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Protocol.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Protocol.java new file mode 100644 index 000000000..0c9244607 --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Protocol.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2014 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal; + +import java.io.IOException; + +/** + * Protocols that OkHttp implements for <a + * href="http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg">ALPN</a> + * selection. + * + * <h3>Protocol vs Scheme</h3> + * Despite its name, {@link java.net.URL#getProtocol()} returns the + * {@linkplain java.net.URI#getScheme() scheme} (http, https, etc.) of the URL, not + * the protocol (http/1.1, spdy/3.1, etc.). OkHttp uses the word <i>protocol</i> + * to identify how HTTP messages are framed. + */ +public enum Protocol { + /** + * An obsolete plaintext framing that does not use persistent sockets by + * default. + */ + HTTP_1_0("http/1.0"), + + /** + * A plaintext framing that includes persistent connections. + * + * <p>This version of OkHttp implements <a + * href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>, and tracks + * revisions to that spec. + */ + HTTP_1_1("http/1.1"), + + /** + * Chromium's binary-framed protocol that includes header compression, + * multiplexing multiple requests on the same socket, and server-push. + * HTTP/1.1 semantics are layered on SPDY/3. + * + * <p>This version of OkHttp implements SPDY 3 <a + * href="http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1">draft + * 3.1</a>. Future releases of OkHttp may use this identifier for a newer draft + * of the SPDY spec. + */ + SPDY_3("spdy/3.1"), + + /** + * The IETF's binary-framed protocol that includes header compression, + * multiplexing multiple requests on the same socket, and server-push. + * HTTP/1.1 semantics are layered on HTTP/2. + * + * <p>HTTP/2 requires deployments of HTTP/2 that use TLS 1.2 support + * {@linkplain CipherSuite#TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256} + * , present in Java 8+ and Android 5+. Servers that enforce this may send an + * exception message including the string {@code INADEQUATE_SECURITY}. + */ + HTTP_2("h2"); + + private final String protocol; + + Protocol(String protocol) { + this.protocol = protocol; + } + + /** + * Returns the protocol identified by {@code protocol}. + * @throws IOException if {@code protocol} is unknown. + */ + public static Protocol get(String protocol) throws IOException { + // Unroll the loop over values() to save an allocation. + if (protocol.equals(HTTP_1_0.protocol)) return HTTP_1_0; + if (protocol.equals(HTTP_1_1.protocol)) return HTTP_1_1; + if (protocol.equals(HTTP_2.protocol)) return HTTP_2; + if (protocol.equals(SPDY_3.protocol)) return SPDY_3; + throw new IOException("Unexpected protocol: " + protocol); + } + + /** + * Returns the string used to identify this protocol for ALPN, like + * "http/1.1", "spdy/3.1" or "h2". + */ + @Override public String toString() { + return protocol; + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/TlsVersion.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/TlsVersion.java new file mode 100644 index 000000000..548f4acbc --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/TlsVersion.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal; + +import javax.net.ssl.SSLSocket; + +/** + * Versions of TLS that can be offered when negotiating a secure socket. See + * {@link SSLSocket#setEnabledProtocols}. + */ +public enum TlsVersion { + TLS_1_2("TLSv1.2"), // 2008. + TLS_1_1("TLSv1.1"), // 2006. + TLS_1_0("TLSv1"), // 1999. + SSL_3_0("SSLv3"), // 1996. + ; + + final String javaName; + + private TlsVersion(String javaName) { + this.javaName = javaName; + } + + public static TlsVersion forJavaName(String javaName) { + if ("TLSv1.2".equals(javaName)) { + return TLS_1_2; + } else if ("TLSv1.1".equals(javaName)) { + return TLS_1_1; + } else if ("TLSv1".equals(javaName)) { + return TLS_1_0; + } else if ("SSLv3".equals(javaName)) { + return SSL_3_0; + } + throw new IllegalArgumentException("Unexpected TLS version: " + javaName); + } + + public String javaName() { + return javaName; + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Util.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Util.java new file mode 100644 index 000000000..7501c441d --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Util.java @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Array; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import okio.Buffer; +import okio.ByteString; +import okio.Source; + +/** Junk drawer of utility methods. */ +public final class Util { + public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + + /** A cheap and type-safe constant for the UTF-8 Charset. */ + public static final Charset UTF_8 = Charset.forName("UTF-8"); + + private Util() { + } + + public static void checkOffsetAndCount(long arrayLength, long offset, long count) { + if ((offset | count) < 0 || offset > arrayLength || arrayLength - offset < count) { + throw new ArrayIndexOutOfBoundsException(); + } + } + + /** Returns true if two possibly-null objects are equal. */ + public static boolean equal(Object a, Object b) { + return a == b || (a != null && a.equals(b)); + } + + /** + * Closes {@code closeable}, ignoring any checked exceptions. Does nothing + * if {@code closeable} is null. + */ + public static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } + + /** + * Closes {@code socket}, ignoring any checked exceptions. Does nothing if + * {@code socket} is null. + */ + public static void closeQuietly(Socket socket) { + if (socket != null) { + try { + socket.close(); + } catch (AssertionError e) { + if (!isAndroidGetsocknameError(e)) throw e; + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } + + /** + * Closes {@code serverSocket}, ignoring any checked exceptions. Does nothing if + * {@code serverSocket} is null. + */ + public static void closeQuietly(ServerSocket serverSocket) { + if (serverSocket != null) { + try { + serverSocket.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } + + /** + * Closes {@code a} and {@code b}. If either close fails, this completes + * the other close and rethrows the first encountered exception. + */ + public static void closeAll(Closeable a, Closeable b) throws IOException { + Throwable thrown = null; + try { + a.close(); + } catch (Throwable e) { + thrown = e; + } + try { + b.close(); + } catch (Throwable e) { + if (thrown == null) thrown = e; + } + if (thrown == null) return; + if (thrown instanceof IOException) throw (IOException) thrown; + if (thrown instanceof RuntimeException) throw (RuntimeException) thrown; + if (thrown instanceof Error) throw (Error) thrown; + throw new AssertionError(thrown); + } + + /** + * Attempts to exhaust {@code source}, returning true if successful. This is useful when reading + * a complete source is helpful, such as when doing so completes a cache body or frees a socket + * connection for reuse. + */ + public static boolean discard(Source source, int timeout, TimeUnit timeUnit) { + try { + return skipAll(source, timeout, timeUnit); + } catch (IOException e) { + return false; + } + } + + /** + * Reads until {@code in} is exhausted or the deadline has been reached. This is careful to not + * extend the deadline if one exists already. + */ + public static boolean skipAll(Source source, int duration, TimeUnit timeUnit) throws IOException { + long now = System.nanoTime(); + long originalDuration = source.timeout().hasDeadline() + ? source.timeout().deadlineNanoTime() - now + : Long.MAX_VALUE; + source.timeout().deadlineNanoTime(now + Math.min(originalDuration, timeUnit.toNanos(duration))); + try { + Buffer skipBuffer = new Buffer(); + while (source.read(skipBuffer, 2048) != -1) { + skipBuffer.clear(); + } + return true; // Success! The source has been exhausted. + } catch (InterruptedIOException e) { + return false; // We ran out of time before exhausting the source. + } finally { + if (originalDuration == Long.MAX_VALUE) { + source.timeout().clearDeadline(); + } else { + source.timeout().deadlineNanoTime(now + originalDuration); + } + } + } + + /** Returns a 32 character string containing an MD5 hash of {@code s}. */ + public static String md5Hex(String s) { + try { + MessageDigest messageDigest = MessageDigest.getInstance("MD5"); + byte[] md5bytes = messageDigest.digest(s.getBytes("UTF-8")); + return ByteString.of(md5bytes).hex(); + } catch (NoSuchAlgorithmException e) { + throw new AssertionError(e); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); + } + } + + /** Returns a Base 64-encoded string containing a SHA-1 hash of {@code s}. */ + public static String shaBase64(String s) { + try { + MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); + byte[] sha1Bytes = messageDigest.digest(s.getBytes("UTF-8")); + return ByteString.of(sha1Bytes).base64(); + } catch (NoSuchAlgorithmException e) { + throw new AssertionError(e); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); + } + } + + /** Returns a SHA-1 hash of {@code s}. */ + public static ByteString sha1(ByteString s) { + try { + MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); + byte[] sha1Bytes = messageDigest.digest(s.toByteArray()); + return ByteString.of(sha1Bytes); + } catch (NoSuchAlgorithmException e) { + throw new AssertionError(e); + } + } + + /** Returns an immutable copy of {@code list}. */ + public static <T> List<T> immutableList(List<T> list) { + return Collections.unmodifiableList(new ArrayList<T>(list)); + } + + /** Returns an immutable list containing {@code elements}. */ + public static <T> List<T> immutableList(T... elements) { + return Collections.unmodifiableList(Arrays.asList(elements.clone())); + } + + /** Returns an immutable copy of {@code map}. */ + public static <K, V> Map<K, V> immutableMap(Map<K, V> map) { + return Collections.unmodifiableMap(new LinkedHashMap<K, V>(map)); + } + + public static ThreadFactory threadFactory(final String name, final boolean daemon) { + return new ThreadFactory() { + @Override public Thread newThread(Runnable runnable) { + Thread result = new Thread(runnable, name); + result.setDaemon(daemon); + return result; + } + }; + } + + /** + * Returns an array containing containing only elements found in {@code first} and also in + * {@code second}. The returned elements are in the same order as in {@code first}. + */ + @SuppressWarnings("unchecked") + public static <T> T[] intersect(Class<T> arrayType, T[] first, T[] second) { + List<T> result = intersect(first, second); + return result.toArray((T[]) Array.newInstance(arrayType, result.size())); + } + + /** + * Returns a list containing containing only elements found in {@code first} and also in + * {@code second}. The returned elements are in the same order as in {@code first}. + */ + private static <T> List<T> intersect(T[] first, T[] second) { + List<T> result = new ArrayList<T>(); + for (T a : first) { + for (T b : second) { + if (a.equals(b)) { + result.add(b); + break; + } + } + } + return result; + } + + /** Returns {@code s} with control characters and non-ASCII characters replaced with '?'. */ + public static String toHumanReadableAscii(String s) { + for (int i = 0, length = s.length(), c; i < length; i += Character.charCount(c)) { + c = s.codePointAt(i); + if (c > '\u001f' && c < '\u007f') continue; + + Buffer buffer = new Buffer(); + buffer.writeUtf8(s, 0, i); + for (int j = i; j < length; j += Character.charCount(c)) { + c = s.codePointAt(j); + buffer.writeUtf8CodePoint(c > '\u001f' && c < '\u007f' ? c : '?'); + } + return buffer.readUtf8(); + } + return s; + } + + /** + * Returns true if {@code e} is due to a firmware bug fixed after Android 4.2.2. + * https://code.google.com/p/android/issues/detail?id=54072 + */ + public static boolean isAndroidGetsocknameError(AssertionError e) { + return e.getCause() != null && e.getMessage() != null + && e.getMessage().contains("getsockname failed"); + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/ErrorCode.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/ErrorCode.java new file mode 100644 index 000000000..38a545930 --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/ErrorCode.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2013 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal.framed; + +// http://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-7 +public enum ErrorCode { + /** Not an error! For SPDY stream resets, prefer null over NO_ERROR. */ + NO_ERROR(0, -1, 0), + + PROTOCOL_ERROR(1, 1, 1), + + /** A subtype of PROTOCOL_ERROR used by SPDY. */ + INVALID_STREAM(1, 2, -1), + + /** A subtype of PROTOCOL_ERROR used by SPDY. */ + UNSUPPORTED_VERSION(1, 4, -1), + + /** A subtype of PROTOCOL_ERROR used by SPDY. */ + STREAM_IN_USE(1, 8, -1), + + /** A subtype of PROTOCOL_ERROR used by SPDY. */ + STREAM_ALREADY_CLOSED(1, 9, -1), + + INTERNAL_ERROR(2, 6, 2), + + FLOW_CONTROL_ERROR(3, 7, -1), + + STREAM_CLOSED(5, -1, -1), + + FRAME_TOO_LARGE(6, 11, -1), + + REFUSED_STREAM(7, 3, -1), + + CANCEL(8, 5, -1), + + COMPRESSION_ERROR(9, -1, -1), + + CONNECT_ERROR(10, -1, -1), + + ENHANCE_YOUR_CALM(11, -1, -1), + + INADEQUATE_SECURITY(12, -1, -1), + + HTTP_1_1_REQUIRED(13, -1, -1), + + INVALID_CREDENTIALS(-1, 10, -1); + + public final int httpCode; + public final int spdyRstCode; + public final int spdyGoAwayCode; + + private ErrorCode(int httpCode, int spdyRstCode, int spdyGoAwayCode) { + this.httpCode = httpCode; + this.spdyRstCode = spdyRstCode; + this.spdyGoAwayCode = spdyGoAwayCode; + } + + public static ErrorCode fromSpdy3Rst(int code) { + for (ErrorCode errorCode : ErrorCode.values()) { + if (errorCode.spdyRstCode == code) return errorCode; + } + return null; + } + + public static ErrorCode fromHttp2(int code) { + for (ErrorCode errorCode : ErrorCode.values()) { + if (errorCode.httpCode == code) return errorCode; + } + return null; + } + + public static ErrorCode fromSpdyGoAway(int code) { + for (ErrorCode errorCode : ErrorCode.values()) { + if (errorCode.spdyGoAwayCode == code) return errorCode; + } + return null; + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/FrameReader.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/FrameReader.java new file mode 100644 index 000000000..20c50f7cc --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/FrameReader.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal.framed; + +import java.io.Closeable; +import java.io.IOException; +import java.util.List; + +import okio.BufferedSource; +import okio.ByteString; + +/** Reads transport frames for SPDY/3 or HTTP/2. */ +public interface FrameReader extends Closeable { + void readConnectionPreface() throws IOException; + boolean nextFrame(Handler handler) throws IOException; + + interface Handler { + void data(boolean inFinished, int streamId, BufferedSource source, int length) + throws IOException; + + /** + * Create or update incoming headers, creating the corresponding streams + * if necessary. Frames that trigger this are SPDY SYN_STREAM, HEADERS, and + * SYN_REPLY, and HTTP/2 HEADERS and PUSH_PROMISE. + * + * @param outFinished true if the receiver should not send further frames. + * @param inFinished true if the sender will not send further frames. + * @param streamId the stream owning these headers. + * @param associatedStreamId the stream that triggered the sender to create + * this stream. + */ + void headers(boolean outFinished, boolean inFinished, int streamId, int associatedStreamId, + List<io.grpc.okhttp.internal.framed.Header> headerBlock, HeadersMode headersMode); + void rstStream(int streamId, io.grpc.okhttp.internal.framed.ErrorCode errorCode); + void settings(boolean clearPrevious, io.grpc.okhttp.internal.framed.Settings settings); + + /** HTTP/2 only. */ + void ackSettings(); + + /** + * Read a connection-level ping from the peer. {@code ack} indicates this + * is a reply. Payload parameters are different between SPDY/3 and HTTP/2. + * <p> + * In SPDY/3, only the first {@code payload1} parameter is set. If the + * reader is a client, it is an unsigned even number. Likewise, a server + * will receive an odd number. + * <p> + * In HTTP/2, both {@code payload1} and {@code payload2} parameters are + * set. The data is opaque binary, and there are no rules on the content. + */ + void ping(boolean ack, int payload1, int payload2); + + /** + * The peer tells us to stop creating streams. It is safe to replay + * streams with {@code ID > lastGoodStreamId} on a new connection. In- + * flight streams with {@code ID <= lastGoodStreamId} can only be replayed + * on a new connection if they are idempotent. + * + * @param lastGoodStreamId the last stream ID the peer processed before + * sending this message. If {@code lastGoodStreamId} is zero, the peer + * processed no frames. + * @param errorCode reason for closing the connection. + * @param debugData only valid for HTTP/2; opaque debug data to send. + */ + void goAway(int lastGoodStreamId, io.grpc.okhttp.internal.framed.ErrorCode errorCode, ByteString debugData); + + /** + * Notifies that an additional {@code windowSizeIncrement} bytes can be + * sent on {@code streamId}, or the connection if {@code streamId} is zero. + */ + void windowUpdate(int streamId, long windowSizeIncrement); + + /** + * Called when reading a headers or priority frame. This may be used to + * change the stream's weight from the default (16) to a new value. + * + * @param streamId stream which has a priority change. + * @param streamDependency the stream ID this stream is dependent on. + * @param weight relative proportion of priority in [1..256]. + * @param exclusive inserts this stream ID as the sole child of + * {@code streamDependency}. + */ + void priority(int streamId, int streamDependency, int weight, boolean exclusive); + + /** + * HTTP/2 only. Receive a push promise header block. + * <p> + * A push promise contains all the headers that pertain to a server-initiated + * request, and a {@code promisedStreamId} to which response frames will be + * delivered. Push promise frames are sent as a part of the response to + * {@code streamId}. + * + * @param streamId client-initiated stream ID. Must be an odd number. + * @param promisedStreamId server-initiated stream ID. Must be an even + * number. + * @param requestHeaders minimally includes {@code :method}, {@code :scheme}, + * {@code :authority}, and (@code :path}. + */ + void pushPromise(int streamId, int promisedStreamId, List<io.grpc.okhttp.internal.framed.Header> requestHeaders) + throws IOException; + + /** + * HTTP/2 only. Expresses that resources for the connection or a client- + * initiated stream are available from a different network location or + * protocol configuration. + * + * <p>See <a href="http://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-01">alt-svc</a> + * + * @param streamId when a client-initiated stream ID (odd number), the + * origin of this alternate service is the origin of the stream. When + * zero, the origin is specified in the {@code origin} parameter. + * @param origin when present, the + * <a href="http://tools.ietf.org/html/rfc6454">origin</a> is typically + * represented as a combination of scheme, host and port. When empty, + * the origin is that of the {@code streamId}. + * @param protocol an ALPN protocol, such as {@code h2}. + * @param host an IP address or hostname. + * @param port the IP port associated with the service. + * @param maxAge time in seconds that this alternative is considered fresh. + */ + void alternateService(int streamId, String origin, ByteString protocol, String host, int port, + long maxAge); + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/FrameWriter.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/FrameWriter.java new file mode 100644 index 000000000..333e06c86 --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/FrameWriter.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal.framed; + +import java.io.Closeable; +import java.io.IOException; +import java.util.List; + +import okio.Buffer; + +/** Writes transport frames for SPDY/3 or HTTP/2. */ +public interface FrameWriter extends Closeable { + /** HTTP/2 only. */ + void connectionPreface() throws IOException; + /** Informs the peer that we've applied its latest settings. */ + void ackSettings(Settings peerSettings) throws IOException; + + /** + * HTTP/2 only. Send a push promise header block. + * <p> + * A push promise contains all the headers that pertain to a server-initiated + * request, and a {@code promisedStreamId} to which response frames will be + * delivered. Push promise frames are sent as a part of the response to + * {@code streamId}. The {@code promisedStreamId} has a priority of one + * greater than {@code streamId}. + * + * @param streamId client-initiated stream ID. Must be an odd number. + * @param promisedStreamId server-initiated stream ID. Must be an even + * number. + * @param requestHeaders minimally includes {@code :method}, {@code :scheme}, + * {@code :authority}, and (@code :path}. + */ + void pushPromise(int streamId, int promisedStreamId, List<Header> requestHeaders) + throws IOException; + + /** SPDY/3 only. */ + void flush() throws IOException; + void synStream(boolean outFinished, boolean inFinished, int streamId, int associatedStreamId, + List<Header> headerBlock) throws IOException; + void synReply(boolean outFinished, int streamId, List<Header> headerBlock) + throws IOException; + void headers(int streamId, List<Header> headerBlock) throws IOException; + void rstStream(int streamId, ErrorCode errorCode) throws IOException; + + /** The maximum size of bytes that may be sent in a single call to {@link #data}. */ + int maxDataLength(); + + /** + * {@code source.length} may be longer than the max length of the variant's data frame. + * Implementations must send multiple frames as necessary. + * + * @param source the buffer to draw bytes from. May be null if byteCount is 0. + * @param byteCount must be between 0 and the minimum of {code source.length} + * and {@link #maxDataLength}. + */ + void data(boolean outFinished, int streamId, Buffer source, int byteCount) throws IOException; + + /** Write okhttp's settings to the peer. */ + void settings(Settings okHttpSettings) throws IOException; + + /** + * Send a connection-level ping to the peer. {@code ack} indicates this is + * a reply. Payload parameters are different between SPDY/3 and HTTP/2. + * <p> + * In SPDY/3, only the first {@code payload1} parameter is sent. If the + * sender is a client, it is an unsigned odd number. Likewise, a server + * will send an even number. + * <p> + * In HTTP/2, both {@code payload1} and {@code payload2} parameters are + * sent. The data is opaque binary, and there are no rules on the content. + */ + void ping(boolean ack, int payload1, int payload2) throws IOException; + + /** + * Tell the peer to stop creating streams and that we last processed + * {@code lastGoodStreamId}, or zero if no streams were processed. + * + * @param lastGoodStreamId the last stream ID processed, or zero if no + * streams were processed. + * @param errorCode reason for closing the connection. + * @param debugData only valid for HTTP/2; opaque debug data to send. + */ + void goAway(int lastGoodStreamId, ErrorCode errorCode, byte[] debugData) throws IOException; + + /** + * Inform peer that an additional {@code windowSizeIncrement} bytes can be + * sent on {@code streamId}, or the connection if {@code streamId} is zero. + */ + void windowUpdate(int streamId, long windowSizeIncrement) throws IOException; +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Header.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Header.java new file mode 100644 index 000000000..00081d489 --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Header.java @@ -0,0 +1,60 @@ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal.framed; + +import okio.ByteString; + +/** HTTP header: the name is an ASCII string, but the value can be UTF-8. */ +public final class Header { + // Special header names defined in the SPDY and HTTP/2 specs. + public static final ByteString RESPONSE_STATUS = ByteString.encodeUtf8(":status"); + public static final ByteString TARGET_METHOD = ByteString.encodeUtf8(":method"); + public static final ByteString TARGET_PATH = ByteString.encodeUtf8(":path"); + public static final ByteString TARGET_SCHEME = ByteString.encodeUtf8(":scheme"); + public static final ByteString TARGET_AUTHORITY = ByteString.encodeUtf8(":authority"); // HTTP/2 + public static final ByteString TARGET_HOST = ByteString.encodeUtf8(":host"); // spdy/3 + public static final ByteString VERSION = ByteString.encodeUtf8(":version"); // spdy/3 + + /** Name in case-insensitive ASCII encoding. */ + public final ByteString name; + /** Value in UTF-8 encoding. */ + public final ByteString value; + final int hpackSize; + + // TODO: search for toLowerCase and consider moving logic here. + public Header(String name, String value) { + this(ByteString.encodeUtf8(name), ByteString.encodeUtf8(value)); + } + + public Header(ByteString name, String value) { + this(name, ByteString.encodeUtf8(value)); + } + + public Header(ByteString name, ByteString value) { + this.name = name; + this.value = value; + this.hpackSize = 32 + name.size() + value.size(); + } + + @Override public boolean equals(Object other) { + if (other instanceof Header) { + Header that = (Header) other; + return this.name.equals(that.name) + && this.value.equals(that.value); + } + return false; + } + + @Override public int hashCode() { + int result = 17; + result = 31 * result + name.hashCode(); + result = 31 * result + value.hashCode(); + return result; + } + + @Override public String toString() { + return String.format("%s: %s", name.utf8(), value.utf8()); + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/HeadersMode.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/HeadersMode.java new file mode 100644 index 000000000..3826252f4 --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/HeadersMode.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal.framed; + +public enum HeadersMode { + SPDY_SYN_STREAM, + SPDY_REPLY, + SPDY_HEADERS, + HTTP_20_HEADERS; + + /** Returns true if it is an error these headers to create a new stream. */ + public boolean failIfStreamAbsent() { + return this == SPDY_REPLY || this == SPDY_HEADERS; + } + + /** Returns true if it is an error these headers to update an existing stream. */ + public boolean failIfStreamPresent() { + return this == SPDY_SYN_STREAM; + } + + /** + * Returns true if it is an error these headers to be the initial headers of a + * response. + */ + public boolean failIfHeadersAbsent() { + return this == SPDY_HEADERS; + } + + /** + * Returns true if it is an error these headers to be update existing headers + * of a response. + */ + public boolean failIfHeadersPresent() { + return this == SPDY_REPLY; + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Hpack.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Hpack.java new file mode 100644 index 000000000..940735abe --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Hpack.java @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2013 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal.framed; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import okio.Buffer; +import okio.BufferedSource; +import okio.ByteString; +import okio.Okio; +import okio.Source; + +/** + * Read and write HPACK v10. + * + * http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12 + * + * This implementation uses an array for the dynamic table and a list for + * indexed entries. Dynamic entries are added to the array, starting in the + * last position moving forward. When the array fills, it is doubled. + */ +final class Hpack { + private static final int PREFIX_4_BITS = 0x0f; + private static final int PREFIX_5_BITS = 0x1f; + private static final int PREFIX_6_BITS = 0x3f; + private static final int PREFIX_7_BITS = 0x7f; + + private static final io.grpc.okhttp.internal.framed.Header[] STATIC_HEADER_TABLE = new io.grpc.okhttp.internal.framed.Header[] { + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.TARGET_AUTHORITY, ""), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.TARGET_METHOD, "GET"), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.TARGET_METHOD, "POST"), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.TARGET_PATH, "/"), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.TARGET_PATH, "/index.html"), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.TARGET_SCHEME, "http"), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.TARGET_SCHEME, "https"), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.RESPONSE_STATUS, "200"), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.RESPONSE_STATUS, "204"), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.RESPONSE_STATUS, "206"), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.RESPONSE_STATUS, "304"), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.RESPONSE_STATUS, "400"), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.RESPONSE_STATUS, "404"), + new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.RESPONSE_STATUS, "500"), + new io.grpc.okhttp.internal.framed.Header("accept-charset", ""), + new io.grpc.okhttp.internal.framed.Header("accept-encoding", "gzip, deflate"), + new io.grpc.okhttp.internal.framed.Header("accept-language", ""), + new io.grpc.okhttp.internal.framed.Header("accept-ranges", ""), + new io.grpc.okhttp.internal.framed.Header("accept", ""), + new io.grpc.okhttp.internal.framed.Header("access-control-allow-origin", ""), + new io.grpc.okhttp.internal.framed.Header("age", ""), + new io.grpc.okhttp.internal.framed.Header("allow", ""), + new io.grpc.okhttp.internal.framed.Header("authorization", ""), + new io.grpc.okhttp.internal.framed.Header("cache-control", ""), + new io.grpc.okhttp.internal.framed.Header("content-disposition", ""), + new io.grpc.okhttp.internal.framed.Header("content-encoding", ""), + new io.grpc.okhttp.internal.framed.Header("content-language", ""), + new io.grpc.okhttp.internal.framed.Header("content-length", ""), + new io.grpc.okhttp.internal.framed.Header("content-location", ""), + new io.grpc.okhttp.internal.framed.Header("content-range", ""), + new io.grpc.okhttp.internal.framed.Header("content-type", ""), + new io.grpc.okhttp.internal.framed.Header("cookie", ""), + new io.grpc.okhttp.internal.framed.Header("date", ""), + new io.grpc.okhttp.internal.framed.Header("etag", ""), + new io.grpc.okhttp.internal.framed.Header("expect", ""), + new io.grpc.okhttp.internal.framed.Header("expires", ""), + new io.grpc.okhttp.internal.framed.Header("from", ""), + new io.grpc.okhttp.internal.framed.Header("host", ""), + new io.grpc.okhttp.internal.framed.Header("if-match", ""), + new io.grpc.okhttp.internal.framed.Header("if-modified-since", ""), + new io.grpc.okhttp.internal.framed.Header("if-none-match", ""), + new io.grpc.okhttp.internal.framed.Header("if-range", ""), + new io.grpc.okhttp.internal.framed.Header("if-unmodified-since", ""), + new io.grpc.okhttp.internal.framed.Header("last-modified", ""), + new io.grpc.okhttp.internal.framed.Header("link", ""), + new io.grpc.okhttp.internal.framed.Header("location", ""), + new io.grpc.okhttp.internal.framed.Header("max-forwards", ""), + new io.grpc.okhttp.internal.framed.Header("proxy-authenticate", ""), + new io.grpc.okhttp.internal.framed.Header("proxy-authorization", ""), + new io.grpc.okhttp.internal.framed.Header("range", ""), + new io.grpc.okhttp.internal.framed.Header("referer", ""), + new io.grpc.okhttp.internal.framed.Header("refresh", ""), + new io.grpc.okhttp.internal.framed.Header("retry-after", ""), + new io.grpc.okhttp.internal.framed.Header("server", ""), + new io.grpc.okhttp.internal.framed.Header("set-cookie", ""), + new io.grpc.okhttp.internal.framed.Header("strict-transport-security", ""), + new io.grpc.okhttp.internal.framed.Header("transfer-encoding", ""), + new io.grpc.okhttp.internal.framed.Header("user-agent", ""), + new io.grpc.okhttp.internal.framed.Header("vary", ""), + new io.grpc.okhttp.internal.framed.Header("via", ""), + new io.grpc.okhttp.internal.framed.Header("www-authenticate", "") + }; + + private Hpack() { + } + + // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-3.1 + static final class Reader { + + private final List<io.grpc.okhttp.internal.framed.Header> headerList = new ArrayList<io.grpc.okhttp.internal.framed.Header>(); + private final BufferedSource source; + + private int headerTableSizeSetting; + private int maxDynamicTableByteCount; + // Visible for testing. + io.grpc.okhttp.internal.framed.Header[] dynamicTable = new io.grpc.okhttp.internal.framed.Header[8]; + // Array is populated back to front, so new entries always have lowest index. + int nextHeaderIndex = dynamicTable.length - 1; + int headerCount = 0; + int dynamicTableByteCount = 0; + + Reader(int headerTableSizeSetting, Source source) { + this.headerTableSizeSetting = headerTableSizeSetting; + this.maxDynamicTableByteCount = headerTableSizeSetting; + this.source = Okio.buffer(source); + } + + int maxDynamicTableByteCount() { + return maxDynamicTableByteCount; + } + + /** + * Called by the reader when the peer sent {@link Settings#HEADER_TABLE_SIZE}. + * While this establishes the maximum dynamic table size, the + * {@link #maxDynamicTableByteCount} set during processing may limit the + * table size to a smaller amount. + * <p> Evicts entries or clears the table as needed. + */ + void headerTableSizeSetting(int headerTableSizeSetting) { + this.headerTableSizeSetting = headerTableSizeSetting; + this.maxDynamicTableByteCount = headerTableSizeSetting; + adjustDynamicTableByteCount(); + } + + private void adjustDynamicTableByteCount() { + if (maxDynamicTableByteCount < dynamicTableByteCount) { + if (maxDynamicTableByteCount == 0) { + clearDynamicTable(); + } else { + evictToRecoverBytes(dynamicTableByteCount - maxDynamicTableByteCount); + } + } + } + + private void clearDynamicTable() { + headerList.clear(); + Arrays.fill(dynamicTable, null); + nextHeaderIndex = dynamicTable.length - 1; + headerCount = 0; + dynamicTableByteCount = 0; + } + + /** Returns the count of entries evicted. */ + private int evictToRecoverBytes(int bytesToRecover) { + int entriesToEvict = 0; + if (bytesToRecover > 0) { + // determine how many headers need to be evicted. + for (int j = dynamicTable.length - 1; j >= nextHeaderIndex && bytesToRecover > 0; j--) { + bytesToRecover -= dynamicTable[j].hpackSize; + dynamicTableByteCount -= dynamicTable[j].hpackSize; + headerCount--; + entriesToEvict++; + } + System.arraycopy(dynamicTable, nextHeaderIndex + 1, dynamicTable, + nextHeaderIndex + 1 + entriesToEvict, headerCount); + nextHeaderIndex += entriesToEvict; + } + return entriesToEvict; + } + + /** + * Read {@code byteCount} bytes of headers from the source stream. This + * implementation does not propagate the never indexed flag of a header. + */ + void readHeaders() throws IOException { + while (!source.exhausted()) { + int b = source.readByte() & 0xff; + if (b == 0x80) { // 10000000 + throw new IOException("index == 0"); + } else if ((b & 0x80) == 0x80) { // 1NNNNNNN + int index = readInt(b, PREFIX_7_BITS); + readIndexedHeader(index - 1); + } else if (b == 0x40) { // 01000000 + readLiteralHeaderWithIncrementalIndexingNewName(); + } else if ((b & 0x40) == 0x40) { // 01NNNNNN + int index = readInt(b, PREFIX_6_BITS); + readLiteralHeaderWithIncrementalIndexingIndexedName(index - 1); + } else if ((b & 0x20) == 0x20) { // 001NNNNN + maxDynamicTableByteCount = readInt(b, PREFIX_5_BITS); + if (maxDynamicTableByteCount < 0 + || maxDynamicTableByteCount > headerTableSizeSetting) { + throw new IOException("Invalid dynamic table size update " + maxDynamicTableByteCount); + } + adjustDynamicTableByteCount(); + } else if (b == 0x10 || b == 0) { // 000?0000 - Ignore never indexed bit. + readLiteralHeaderWithoutIndexingNewName(); + } else { // 000?NNNN - Ignore never indexed bit. + int index = readInt(b, PREFIX_4_BITS); + readLiteralHeaderWithoutIndexingIndexedName(index - 1); + } + } + } + + public List<io.grpc.okhttp.internal.framed.Header> getAndResetHeaderList() { + List<io.grpc.okhttp.internal.framed.Header> result = new ArrayList<io.grpc.okhttp.internal.framed.Header>(headerList); + headerList.clear(); + return result; + } + + private void readIndexedHeader(int index) throws IOException { + if (isStaticHeader(index)) { + io.grpc.okhttp.internal.framed.Header staticEntry = STATIC_HEADER_TABLE[index]; + headerList.add(staticEntry); + } else { + int dynamicTableIndex = dynamicTableIndex(index - STATIC_HEADER_TABLE.length); + if (dynamicTableIndex < 0 || dynamicTableIndex > dynamicTable.length - 1) { + throw new IOException("Header index too large " + (index + 1)); + } + headerList.add(dynamicTable[dynamicTableIndex]); + } + } + + // referencedHeaders is relative to nextHeaderIndex + 1. + private int dynamicTableIndex(int index) { + return nextHeaderIndex + 1 + index; + } + + private void readLiteralHeaderWithoutIndexingIndexedName(int index) throws IOException { + ByteString name = getName(index); + ByteString value = readByteString(); + headerList.add(new io.grpc.okhttp.internal.framed.Header(name, value)); + } + + private void readLiteralHeaderWithoutIndexingNewName() throws IOException { + ByteString name = checkLowercase(readByteString()); + ByteString value = readByteString(); + headerList.add(new io.grpc.okhttp.internal.framed.Header(name, value)); + } + + private void readLiteralHeaderWithIncrementalIndexingIndexedName(int nameIndex) + throws IOException { + ByteString name = getName(nameIndex); + ByteString value = readByteString(); + insertIntoDynamicTable(-1, new io.grpc.okhttp.internal.framed.Header(name, value)); + } + + private void readLiteralHeaderWithIncrementalIndexingNewName() throws IOException { + ByteString name = checkLowercase(readByteString()); + ByteString value = readByteString(); + insertIntoDynamicTable(-1, new io.grpc.okhttp.internal.framed.Header(name, value)); + } + + private ByteString getName(int index) { + if (isStaticHeader(index)) { + return STATIC_HEADER_TABLE[index].name; + } else { + return dynamicTable[dynamicTableIndex(index - STATIC_HEADER_TABLE.length)].name; + } + } + + private boolean isStaticHeader(int index) { + return index >= 0 && index <= STATIC_HEADER_TABLE.length - 1; + } + + /** index == -1 when new. */ + private void insertIntoDynamicTable(int index, io.grpc.okhttp.internal.framed.Header entry) { + headerList.add(entry); + + int delta = entry.hpackSize; + if (index != -1) { // Index -1 == new header. + delta -= dynamicTable[dynamicTableIndex(index)].hpackSize; + } + + // if the new or replacement header is too big, drop all entries. + if (delta > maxDynamicTableByteCount) { + clearDynamicTable(); + return; + } + + // Evict headers to the required length. + int bytesToRecover = (dynamicTableByteCount + delta) - maxDynamicTableByteCount; + int entriesEvicted = evictToRecoverBytes(bytesToRecover); + + if (index == -1) { // Adding a value to the dynamic table. + if (headerCount + 1 > dynamicTable.length) { // Need to grow the dynamic table. + io.grpc.okhttp.internal.framed.Header[] doubled = new io.grpc.okhttp.internal.framed.Header[dynamicTable.length * 2]; + System.arraycopy(dynamicTable, 0, doubled, dynamicTable.length, dynamicTable.length); + nextHeaderIndex = dynamicTable.length - 1; + dynamicTable = doubled; + } + index = nextHeaderIndex--; + dynamicTable[index] = entry; + headerCount++; + } else { // Replace value at same position. + index += dynamicTableIndex(index) + entriesEvicted; + dynamicTable[index] = entry; + } + dynamicTableByteCount += delta; + } + + private int readByte() throws IOException { + return source.readByte() & 0xff; + } + + int readInt(int firstByte, int prefixMask) throws IOException { + int prefix = firstByte & prefixMask; + if (prefix < prefixMask) { + return prefix; // This was a single byte value. + } + + // This is a multibyte value. Read 7 bits at a time. + int result = prefixMask; + int shift = 0; + while (true) { + int b = readByte(); + if ((b & 0x80) != 0) { // Equivalent to (b >= 128) since b is in [0..255]. + result += (b & 0x7f) << shift; + shift += 7; + } else { + result += b << shift; // Last byte. + break; + } + } + return result; + } + + /** Reads a potentially Huffman encoded byte string. */ + ByteString readByteString() throws IOException { + int firstByte = readByte(); + boolean huffmanDecode = (firstByte & 0x80) == 0x80; // 1NNNNNNN + int length = readInt(firstByte, PREFIX_7_BITS); + + if (huffmanDecode) { + return ByteString.of(io.grpc.okhttp.internal.framed.Huffman.get().decode(source.readByteArray(length))); + } else { + return source.readByteString(length); + } + } + } + + private static final Map<ByteString, Integer> NAME_TO_FIRST_INDEX = nameToFirstIndex(); + + private static Map<ByteString, Integer> nameToFirstIndex() { + Map<ByteString, Integer> result = + new LinkedHashMap<ByteString, Integer>(STATIC_HEADER_TABLE.length); + for (int i = 0; i < STATIC_HEADER_TABLE.length; i++) { + if (!result.containsKey(STATIC_HEADER_TABLE[i].name)) { + result.put(STATIC_HEADER_TABLE[i].name, i); + } + } + return Collections.unmodifiableMap(result); + } + + static final class Writer { + private final Buffer out; + + Writer(Buffer out) { + this.out = out; + } + + /** This does not use "never indexed" semantics for sensitive headers. */ + // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-6.2.3 + void writeHeaders(List<io.grpc.okhttp.internal.framed.Header> headerBlock) throws IOException { + // TODO: implement index tracking + for (int i = 0, size = headerBlock.size(); i < size; i++) { + ByteString name = headerBlock.get(i).name.toAsciiLowercase(); + Integer staticIndex = NAME_TO_FIRST_INDEX.get(name); + if (staticIndex != null) { + // Literal Header Field without Indexing - Indexed Name. + writeInt(staticIndex + 1, PREFIX_4_BITS, 0); + writeByteString(headerBlock.get(i).value); + } else { + out.writeByte(0x00); // Literal Header without Indexing - New Name. + writeByteString(name); + writeByteString(headerBlock.get(i).value); + } + } + } + + // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-4.1.1 + void writeInt(int value, int prefixMask, int bits) throws IOException { + // Write the raw value for a single byte value. + if (value < prefixMask) { + out.writeByte(bits | value); + return; + } + + // Write the mask to start a multibyte value. + out.writeByte(bits | prefixMask); + value -= prefixMask; + + // Write 7 bits at a time 'til we're done. + while (value >= 0x80) { + int b = value & 0x7f; + out.writeByte(b | 0x80); + value >>>= 7; + } + out.writeByte(value); + } + + void writeByteString(ByteString data) throws IOException { + writeInt(data.size(), PREFIX_7_BITS, 0); + out.write(data); + } + } + + /** + * An HTTP/2 response cannot contain uppercase header characters and must + * be treated as malformed. + */ + private static ByteString checkLowercase(ByteString name) throws IOException { + for (int i = 0, length = name.size(); i < length; i++) { + byte c = name.getByte(i); + if (c >= 'A' && c <= 'Z') { + throw new IOException("PROTOCOL_ERROR response malformed: mixed case name: " + name.utf8()); + } + } + return name; + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Http2.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Http2.java new file mode 100644 index 000000000..0ad535fab --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Http2.java @@ -0,0 +1,776 @@ +/* + * Copyright (C) 2013 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal.framed; + +import io.grpc.okhttp.internal.Protocol; +import java.io.IOException; +import java.util.List; +import java.util.logging.Logger; + +import okio.Buffer; +import okio.BufferedSink; +import okio.BufferedSource; +import okio.ByteString; +import okio.Source; +import okio.Timeout; + +import static io.grpc.okhttp.internal.framed.Http2.FrameLogger.formatHeader; +import static java.lang.String.format; +import static java.util.logging.Level.FINE; +import static okio.ByteString.EMPTY; + +/** + * Read and write HTTP/2 frames. + * <p> + * This implementation assumes we do not send an increased + * {@link io.grpc.okhttp.internal.framed.Settings#getMaxFrameSize frame size setting} to the peer. Hence, we + * expect all frames to have a max length of {@link #INITIAL_MAX_FRAME_SIZE}. + * <p>http://tools.ietf.org/html/draft-ietf-httpbis-http2-17 + */ +public final class Http2 implements Variant { + private static final Logger logger = Logger.getLogger(FrameLogger.class.getName()); + + @Override public Protocol getProtocol() { + return Protocol.HTTP_2; + } + + private static final ByteString CONNECTION_PREFACE + = ByteString.encodeUtf8("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"); + + /** The initial max frame size, applied independently writing to, or reading from the peer. */ + static final int INITIAL_MAX_FRAME_SIZE = 0x4000; // 16384 + + static final byte TYPE_DATA = 0x0; + static final byte TYPE_HEADERS = 0x1; + static final byte TYPE_PRIORITY = 0x2; + static final byte TYPE_RST_STREAM = 0x3; + static final byte TYPE_SETTINGS = 0x4; + static final byte TYPE_PUSH_PROMISE = 0x5; + static final byte TYPE_PING = 0x6; + static final byte TYPE_GOAWAY = 0x7; + static final byte TYPE_WINDOW_UPDATE = 0x8; + static final byte TYPE_CONTINUATION = 0x9; + + static final byte FLAG_NONE = 0x0; + static final byte FLAG_ACK = 0x1; // Used for settings and ping. + static final byte FLAG_END_STREAM = 0x1; // Used for headers and data. + static final byte FLAG_END_HEADERS = 0x4; // Used for headers and continuation. + static final byte FLAG_END_PUSH_PROMISE = 0x4; + static final byte FLAG_PADDED = 0x8; // Used for headers and data. + static final byte FLAG_PRIORITY = 0x20; // Used for headers. + static final byte FLAG_COMPRESSED = 0x20; // Used for data. + + /** + * Creates a frame reader with max header table size of 4096 and data frame + * compression disabled. + */ + @Override public FrameReader newReader(BufferedSource source, boolean client) { + return new Reader(source, 4096, client); + } + + @Override public io.grpc.okhttp.internal.framed.FrameWriter newWriter(BufferedSink sink, boolean client) { + return new Writer(sink, client); + } + + static final class Reader implements FrameReader { + private final BufferedSource source; + private final ContinuationSource continuation; + private final boolean client; + + // Visible for testing. + final Hpack.Reader hpackReader; + + Reader(BufferedSource source, int headerTableSize, boolean client) { + this.source = source; + this.client = client; + this.continuation = new ContinuationSource(this.source); + this.hpackReader = new Hpack.Reader(headerTableSize, continuation); + } + + @Override public void readConnectionPreface() throws IOException { + if (client) return; // Nothing to read; servers doesn't send a connection preface! + ByteString connectionPreface = source.readByteString(CONNECTION_PREFACE.size()); + if (logger.isLoggable(FINE)) logger.fine(format("<< CONNECTION %s", connectionPreface.hex())); + if (!CONNECTION_PREFACE.equals(connectionPreface)) { + throw ioException("Expected a connection header but was %s", connectionPreface.utf8()); + } + } + + @Override public boolean nextFrame(Handler handler) throws IOException { + try { + source.require(9); // Frame header size + } catch (IOException e) { + return false; // This might be a normal socket close. + } + + /* 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Length (24) | + * +---------------+---------------+---------------+ + * | Type (8) | Flags (8) | + * +-+-+-----------+---------------+-------------------------------+ + * |R| Stream Identifier (31) | + * +=+=============================================================+ + * | Frame Payload (0...) ... + * +---------------------------------------------------------------+ + */ + int length = readMedium(source); + if (length < 0 || length > INITIAL_MAX_FRAME_SIZE) { + throw ioException("FRAME_SIZE_ERROR: %s", length); + } + byte type = (byte) (source.readByte() & 0xff); + byte flags = (byte) (source.readByte() & 0xff); + int streamId = (source.readInt() & 0x7fffffff); // Ignore reserved bit. + if (logger.isLoggable(FINE)) logger.fine(formatHeader(true, streamId, length, type, flags)); + + switch (type) { + case TYPE_DATA: + readData(handler, length, flags, streamId); + break; + + case TYPE_HEADERS: + readHeaders(handler, length, flags, streamId); + break; + + case TYPE_PRIORITY: + readPriority(handler, length, flags, streamId); + break; + + case TYPE_RST_STREAM: + readRstStream(handler, length, flags, streamId); + break; + + case TYPE_SETTINGS: + readSettings(handler, length, flags, streamId); + break; + + case TYPE_PUSH_PROMISE: + readPushPromise(handler, length, flags, streamId); + break; + + case TYPE_PING: + readPing(handler, length, flags, streamId); + break; + + case TYPE_GOAWAY: + readGoAway(handler, length, flags, streamId); + break; + + case TYPE_WINDOW_UPDATE: + readWindowUpdate(handler, length, flags, streamId); + break; + + default: + // Implementations MUST discard frames that have unknown or unsupported types. + source.skip(length); + } + return true; + } + + private void readHeaders(Handler handler, int length, byte flags, int streamId) + throws IOException { + if (streamId == 0) throw ioException("PROTOCOL_ERROR: TYPE_HEADERS streamId == 0"); + + boolean endStream = (flags & FLAG_END_STREAM) != 0; + + short padding = (flags & FLAG_PADDED) != 0 ? (short) (source.readByte() & 0xff) : 0; + + if ((flags & FLAG_PRIORITY) != 0) { + readPriority(handler, streamId); + length -= 5; // account for above read. + } + + length = lengthWithoutPadding(length, flags, padding); + + List<Header> headerBlock = readHeaderBlock(length, padding, flags, streamId); + + handler.headers(false, endStream, streamId, -1, headerBlock, HeadersMode.HTTP_20_HEADERS); + } + + private List<Header> readHeaderBlock(int length, short padding, byte flags, int streamId) + throws IOException { + continuation.length = continuation.left = length; + continuation.padding = padding; + continuation.flags = flags; + continuation.streamId = streamId; + + // TODO: Concat multi-value headers with 0x0, except COOKIE, which uses 0x3B, 0x20. + // http://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-8.1.2.5 + hpackReader.readHeaders(); + return hpackReader.getAndResetHeaderList(); + } + + private void readData(Handler handler, int length, byte flags, int streamId) + throws IOException { + // TODO: checkState open or half-closed (local) or raise STREAM_CLOSED + boolean inFinished = (flags & FLAG_END_STREAM) != 0; + boolean gzipped = (flags & FLAG_COMPRESSED) != 0; + if (gzipped) { + throw ioException("PROTOCOL_ERROR: FLAG_COMPRESSED without SETTINGS_COMPRESS_DATA"); + } + + short padding = (flags & FLAG_PADDED) != 0 ? (short) (source.readByte() & 0xff) : 0; + length = lengthWithoutPadding(length, flags, padding); + + handler.data(inFinished, streamId, source, length); + source.skip(padding); + } + + private void readPriority(Handler handler, int length, byte flags, int streamId) + throws IOException { + if (length != 5) throw ioException("TYPE_PRIORITY length: %d != 5", length); + if (streamId == 0) throw ioException("TYPE_PRIORITY streamId == 0"); + readPriority(handler, streamId); + } + + private void readPriority(Handler handler, int streamId) throws IOException { + int w1 = source.readInt(); + boolean exclusive = (w1 & 0x80000000) != 0; + int streamDependency = (w1 & 0x7fffffff); + int weight = (source.readByte() & 0xff) + 1; + handler.priority(streamId, streamDependency, weight, exclusive); + } + + private void readRstStream(Handler handler, int length, byte flags, int streamId) + throws IOException { + if (length != 4) throw ioException("TYPE_RST_STREAM length: %d != 4", length); + if (streamId == 0) throw ioException("TYPE_RST_STREAM streamId == 0"); + int errorCodeInt = source.readInt(); + io.grpc.okhttp.internal.framed.ErrorCode errorCode = io.grpc.okhttp.internal.framed.ErrorCode.fromHttp2(errorCodeInt); + if (errorCode == null) { + throw ioException("TYPE_RST_STREAM unexpected error code: %d", errorCodeInt); + } + handler.rstStream(streamId, errorCode); + } + + private void readSettings(Handler handler, int length, byte flags, int streamId) + throws IOException { + if (streamId != 0) throw ioException("TYPE_SETTINGS streamId != 0"); + if ((flags & FLAG_ACK) != 0) { + if (length != 0) throw ioException("FRAME_SIZE_ERROR ack frame should be empty!"); + handler.ackSettings(); + return; + } + + if (length % 6 != 0) throw ioException("TYPE_SETTINGS length %% 6 != 0: %s", length); + io.grpc.okhttp.internal.framed.Settings settings = new io.grpc.okhttp.internal.framed.Settings(); + for (int i = 0; i < length; i += 6) { + short id = source.readShort(); + int value = source.readInt(); + + switch (id) { + case 1: // SETTINGS_HEADER_TABLE_SIZE + break; + case 2: // SETTINGS_ENABLE_PUSH + if (value != 0 && value != 1) { + throw ioException("PROTOCOL_ERROR SETTINGS_ENABLE_PUSH != 0 or 1"); + } + break; + case 3: // SETTINGS_MAX_CONCURRENT_STREAMS + id = 4; // Renumbered in draft 10. + break; + case 4: // SETTINGS_INITIAL_WINDOW_SIZE + id = 7; // Renumbered in draft 10. + if (value < 0) { + throw ioException("PROTOCOL_ERROR SETTINGS_INITIAL_WINDOW_SIZE > 2^31 - 1"); + } + break; + case 5: // SETTINGS_MAX_FRAME_SIZE + if (value < INITIAL_MAX_FRAME_SIZE || value > 16777215) { + throw ioException("PROTOCOL_ERROR SETTINGS_MAX_FRAME_SIZE: %s", value); + } + break; + case 6: // SETTINGS_MAX_HEADER_LIST_SIZE + break; // Advisory only, so ignored. + default: + throw ioException("PROTOCOL_ERROR invalid settings id: %s", id); + } + settings.set(id, 0, value); + } + handler.settings(false, settings); + if (settings.getHeaderTableSize() >= 0) { + hpackReader.headerTableSizeSetting(settings.getHeaderTableSize()); + } + } + + private void readPushPromise(Handler handler, int length, byte flags, int streamId) + throws IOException { + if (streamId == 0) { + throw ioException("PROTOCOL_ERROR: TYPE_PUSH_PROMISE streamId == 0"); + } + short padding = (flags & FLAG_PADDED) != 0 ? (short) (source.readByte() & 0xff) : 0; + int promisedStreamId = source.readInt() & 0x7fffffff; + length -= 4; // account for above read. + length = lengthWithoutPadding(length, flags, padding); + List<Header> headerBlock = readHeaderBlock(length, padding, flags, streamId); + handler.pushPromise(streamId, promisedStreamId, headerBlock); + } + + private void readPing(Handler handler, int length, byte flags, int streamId) + throws IOException { + if (length != 8) throw ioException("TYPE_PING length != 8: %s", length); + if (streamId != 0) throw ioException("TYPE_PING streamId != 0"); + int payload1 = source.readInt(); + int payload2 = source.readInt(); + boolean ack = (flags & FLAG_ACK) != 0; + handler.ping(ack, payload1, payload2); + } + + private void readGoAway(Handler handler, int length, byte flags, int streamId) + throws IOException { + if (length < 8) throw ioException("TYPE_GOAWAY length < 8: %s", length); + if (streamId != 0) throw ioException("TYPE_GOAWAY streamId != 0"); + int lastStreamId = source.readInt(); + int errorCodeInt = source.readInt(); + int opaqueDataLength = length - 8; + io.grpc.okhttp.internal.framed.ErrorCode errorCode = io.grpc.okhttp.internal.framed.ErrorCode.fromHttp2(errorCodeInt); + if (errorCode == null) { + throw ioException("TYPE_GOAWAY unexpected error code: %d", errorCodeInt); + } + ByteString debugData = EMPTY; + if (opaqueDataLength > 0) { // Must read debug data in order to not corrupt the connection. + debugData = source.readByteString(opaqueDataLength); + } + handler.goAway(lastStreamId, errorCode, debugData); + } + + private void readWindowUpdate(Handler handler, int length, byte flags, int streamId) + throws IOException { + if (length != 4) throw ioException("TYPE_WINDOW_UPDATE length !=4: %s", length); + long increment = (source.readInt() & 0x7fffffffL); + if (increment == 0) throw ioException("windowSizeIncrement was 0", increment); + handler.windowUpdate(streamId, increment); + } + + @Override public void close() throws IOException { + source.close(); + } + } + + static final class Writer implements io.grpc.okhttp.internal.framed.FrameWriter { + private final BufferedSink sink; + private final boolean client; + private final Buffer hpackBuffer; + private final Hpack.Writer hpackWriter; + private int maxFrameSize; + private boolean closed; + + Writer(BufferedSink sink, boolean client) { + this.sink = sink; + this.client = client; + this.hpackBuffer = new Buffer(); + this.hpackWriter = new Hpack.Writer(hpackBuffer); + this.maxFrameSize = INITIAL_MAX_FRAME_SIZE; + } + + @Override public synchronized void flush() throws IOException { + if (closed) throw new IOException("closed"); + sink.flush(); + } + + @Override public synchronized void ackSettings(io.grpc.okhttp.internal.framed.Settings peerSettings) throws IOException { + if (closed) throw new IOException("closed"); + this.maxFrameSize = peerSettings.getMaxFrameSize(maxFrameSize); + int length = 0; + byte type = TYPE_SETTINGS; + byte flags = FLAG_ACK; + int streamId = 0; + frameHeader(streamId, length, type, flags); + sink.flush(); + } + + @Override public synchronized void connectionPreface() throws IOException { + if (closed) throw new IOException("closed"); + if (!client) return; // Nothing to write; servers don't send connection headers! + if (logger.isLoggable(FINE)) { + logger.fine(format(">> CONNECTION %s", CONNECTION_PREFACE.hex())); + } + sink.write(CONNECTION_PREFACE.toByteArray()); + sink.flush(); + } + + @Override public synchronized void synStream(boolean outFinished, boolean inFinished, + int streamId, int associatedStreamId, List<Header> headerBlock) + throws IOException { + if (inFinished) throw new UnsupportedOperationException(); + if (closed) throw new IOException("closed"); + headers(outFinished, streamId, headerBlock); + } + + @Override public synchronized void synReply(boolean outFinished, int streamId, + List<Header> headerBlock) throws IOException { + if (closed) throw new IOException("closed"); + headers(outFinished, streamId, headerBlock); + } + + @Override public synchronized void headers(int streamId, List<Header> headerBlock) + throws IOException { + if (closed) throw new IOException("closed"); + headers(false, streamId, headerBlock); + } + + @Override public synchronized void pushPromise(int streamId, int promisedStreamId, + List<Header> requestHeaders) throws IOException { + if (closed) throw new IOException("closed"); + hpackWriter.writeHeaders(requestHeaders); + + long byteCount = hpackBuffer.size(); + int length = (int) Math.min(maxFrameSize - 4, byteCount); + byte type = TYPE_PUSH_PROMISE; + byte flags = byteCount == length ? FLAG_END_HEADERS : 0; + frameHeader(streamId, length + 4, type, flags); + sink.writeInt(promisedStreamId & 0x7fffffff); + sink.write(hpackBuffer, length); + + if (byteCount > length) writeContinuationFrames(streamId, byteCount - length); + } + + void headers(boolean outFinished, int streamId, List<Header> headerBlock) throws IOException { + if (closed) throw new IOException("closed"); + hpackWriter.writeHeaders(headerBlock); + + long byteCount = hpackBuffer.size(); + int length = (int) Math.min(maxFrameSize, byteCount); + byte type = TYPE_HEADERS; + byte flags = byteCount == length ? FLAG_END_HEADERS : 0; + if (outFinished) flags |= FLAG_END_STREAM; + frameHeader(streamId, length, type, flags); + sink.write(hpackBuffer, length); + + if (byteCount > length) writeContinuationFrames(streamId, byteCount - length); + } + + private void writeContinuationFrames(int streamId, long byteCount) throws IOException { + while (byteCount > 0) { + int length = (int) Math.min(maxFrameSize, byteCount); + byteCount -= length; + frameHeader(streamId, length, TYPE_CONTINUATION, byteCount == 0 ? FLAG_END_HEADERS : 0); + sink.write(hpackBuffer, length); + } + } + + @Override public synchronized void rstStream(int streamId, io.grpc.okhttp.internal.framed.ErrorCode errorCode) + throws IOException { + if (closed) throw new IOException("closed"); + if (errorCode.httpCode == -1) throw new IllegalArgumentException(); + + int length = 4; + byte type = TYPE_RST_STREAM; + byte flags = FLAG_NONE; + frameHeader(streamId, length, type, flags); + sink.writeInt(errorCode.httpCode); + sink.flush(); + } + + @Override public int maxDataLength() { + return maxFrameSize; + } + + @Override public synchronized void data(boolean outFinished, int streamId, Buffer source, + int byteCount) throws IOException { + if (closed) throw new IOException("closed"); + byte flags = FLAG_NONE; + if (outFinished) flags |= FLAG_END_STREAM; + dataFrame(streamId, flags, source, byteCount); + } + + void dataFrame(int streamId, byte flags, Buffer buffer, int byteCount) throws IOException { + byte type = TYPE_DATA; + frameHeader(streamId, byteCount, type, flags); + if (byteCount > 0) { + sink.write(buffer, byteCount); + } + } + + @Override public synchronized void settings(io.grpc.okhttp.internal.framed.Settings settings) throws IOException { + if (closed) throw new IOException("closed"); + int length = settings.size() * 6; + byte type = TYPE_SETTINGS; + byte flags = FLAG_NONE; + int streamId = 0; + frameHeader(streamId, length, type, flags); + for (int i = 0; i < io.grpc.okhttp.internal.framed.Settings.COUNT; i++) { + if (!settings.isSet(i)) continue; + int id = i; + if (id == 4) id = 3; // SETTINGS_MAX_CONCURRENT_STREAMS renumbered. + else if (id == 7) id = 4; // SETTINGS_INITIAL_WINDOW_SIZE renumbered. + sink.writeShort(id); + sink.writeInt(settings.get(i)); + } + sink.flush(); + } + + @Override public synchronized void ping(boolean ack, int payload1, int payload2) + throws IOException { + if (closed) throw new IOException("closed"); + int length = 8; + byte type = TYPE_PING; + byte flags = ack ? FLAG_ACK : FLAG_NONE; + int streamId = 0; + frameHeader(streamId, length, type, flags); + sink.writeInt(payload1); + sink.writeInt(payload2); + sink.flush(); + } + + @Override public synchronized void goAway(int lastGoodStreamId, io.grpc.okhttp.internal.framed.ErrorCode errorCode, + byte[] debugData) throws IOException { + if (closed) throw new IOException("closed"); + if (errorCode.httpCode == -1) throw illegalArgument("errorCode.httpCode == -1"); + int length = 8 + debugData.length; + byte type = TYPE_GOAWAY; + byte flags = FLAG_NONE; + int streamId = 0; + frameHeader(streamId, length, type, flags); + sink.writeInt(lastGoodStreamId); + sink.writeInt(errorCode.httpCode); + if (debugData.length > 0) { + sink.write(debugData); + } + sink.flush(); + } + + @Override public synchronized void windowUpdate(int streamId, long windowSizeIncrement) + throws IOException { + if (closed) throw new IOException("closed"); + if (windowSizeIncrement == 0 || windowSizeIncrement > 0x7fffffffL) { + throw illegalArgument("windowSizeIncrement == 0 || windowSizeIncrement > 0x7fffffffL: %s", + windowSizeIncrement); + } + int length = 4; + byte type = TYPE_WINDOW_UPDATE; + byte flags = FLAG_NONE; + frameHeader(streamId, length, type, flags); + sink.writeInt((int) windowSizeIncrement); + sink.flush(); + } + + @Override public synchronized void close() throws IOException { + closed = true; + sink.close(); + } + + void frameHeader(int streamId, int length, byte type, byte flags) throws IOException { + if (logger.isLoggable(FINE)) logger.fine(formatHeader(false, streamId, length, type, flags)); + if (length > maxFrameSize) { + throw illegalArgument("FRAME_SIZE_ERROR length > %d: %d", maxFrameSize, length); + } + if ((streamId & 0x80000000) != 0) throw illegalArgument("reserved bit set: %s", streamId); + writeMedium(sink, length); + sink.writeByte(type & 0xff); + sink.writeByte(flags & 0xff); + sink.writeInt(streamId & 0x7fffffff); + } + } + + private static IllegalArgumentException illegalArgument(String message, Object... args) { + throw new IllegalArgumentException(format(message, args)); + } + + private static IOException ioException(String message, Object... args) throws IOException { + throw new IOException(format(message, args)); + } + + /** + * Decompression of the header block occurs above the framing layer. This + * class lazily reads continuation frames as they are needed by {@link + * Hpack.Reader#readHeaders()}. + */ + static final class ContinuationSource implements Source { + private final BufferedSource source; + + int length; + byte flags; + int streamId; + + int left; + short padding; + + public ContinuationSource(BufferedSource source) { + this.source = source; + } + + @Override public long read(Buffer sink, long byteCount) throws IOException { + while (left == 0) { + source.skip(padding); + padding = 0; + if ((flags & FLAG_END_HEADERS) != 0) return -1; + readContinuationHeader(); + // TODO: test case for empty continuation header? + } + + long read = source.read(sink, Math.min(byteCount, left)); + if (read == -1) return -1; + left -= read; + return read; + } + + @Override public Timeout timeout() { + return source.timeout(); + } + + @Override public void close() throws IOException { + } + + private void readContinuationHeader() throws IOException { + int previousStreamId = streamId; + + length = left = readMedium(source); + byte type = (byte) (source.readByte() & 0xff); + flags = (byte) (source.readByte() & 0xff); + if (logger.isLoggable(FINE)) logger.fine(formatHeader(true, streamId, length, type, flags)); + streamId = (source.readInt() & 0x7fffffff); + if (type != TYPE_CONTINUATION) throw ioException("%s != TYPE_CONTINUATION", type); + if (streamId != previousStreamId) throw ioException("TYPE_CONTINUATION streamId changed"); + } + } + + private static int lengthWithoutPadding(int length, byte flags, short padding) + throws IOException { + if ((flags & FLAG_PADDED) != 0) length--; // Account for reading the padding length. + if (padding > length) { + throw ioException("PROTOCOL_ERROR padding %s > remaining length %s", padding, length); + } + return (short) (length - padding); + } + + /** + * Logs a human-readable representation of HTTP/2 frame headers. + * + * <p>The format is: + * + * <pre> + * direction streamID length type flags + * </pre> + * Where direction is {@code <<} for inbound and {@code >>} for outbound. + * + * <p> For example, the following would indicate a HEAD request sent from + * the client. + * <pre> + * {@code + * << 0x0000000f 12 HEADERS END_HEADERS|END_STREAM + * } + * </pre> + */ + static final class FrameLogger { + + static String formatHeader(boolean inbound, int streamId, int length, byte type, byte flags) { + String formattedType = type < TYPES.length ? TYPES[type] : format("0x%02x", type); + String formattedFlags = formatFlags(type, flags); + return format("%s 0x%08x %5d %-13s %s", inbound ? "<<" : ">>", streamId, length, + formattedType, formattedFlags); + } + + /** + * Looks up valid string representing flags from the table. Invalid + * combinations are represented in binary. + */ + // Visible for testing. + static String formatFlags(byte type, byte flags) { + if (flags == 0) return ""; + switch (type) { // Special case types that have 0 or 1 flag. + case TYPE_SETTINGS: + case TYPE_PING: + return flags == FLAG_ACK ? "ACK" : BINARY[flags]; + case TYPE_PRIORITY: + case TYPE_RST_STREAM: + case TYPE_GOAWAY: + case TYPE_WINDOW_UPDATE: + return BINARY[flags]; + } + String result = flags < FLAGS.length ? FLAGS[flags] : BINARY[flags]; + // Special case types that have overlap flag values. + if (type == TYPE_PUSH_PROMISE && (flags & FLAG_END_PUSH_PROMISE) != 0) { + return result.replace("HEADERS", "PUSH_PROMISE"); // TODO: Avoid allocation. + } else if (type == TYPE_DATA && (flags & FLAG_COMPRESSED) != 0) { + return result.replace("PRIORITY", "COMPRESSED"); // TODO: Avoid allocation. + } + return result; + } + + /** Lookup table for valid frame types. */ + private static final String[] TYPES = new String[] { + "DATA", + "HEADERS", + "PRIORITY", + "RST_STREAM", + "SETTINGS", + "PUSH_PROMISE", + "PING", + "GOAWAY", + "WINDOW_UPDATE", + "CONTINUATION" + }; + + /** + * Lookup table for valid flags for DATA, HEADERS, CONTINUATION. Invalid + * combinations are represented in binary. + */ + private static final String[] FLAGS = new String[0x40]; // Highest bit flag is 0x20. + private static final String[] BINARY = new String[256]; + + static { + for (int i = 0; i < BINARY.length; i++) { + BINARY[i] = format("%8s", Integer.toBinaryString(i)).replace(' ', '0'); + } + + FLAGS[FLAG_NONE] = ""; + FLAGS[FLAG_END_STREAM] = "END_STREAM"; + + int[] prefixFlags = new int[] {FLAG_END_STREAM}; + + FLAGS[FLAG_PADDED] = "PADDED"; + for (int prefixFlag : prefixFlags) { + FLAGS[prefixFlag | FLAG_PADDED] = FLAGS[prefixFlag] + "|PADDED"; + } + + FLAGS[FLAG_END_HEADERS] = "END_HEADERS"; // Same as END_PUSH_PROMISE. + FLAGS[FLAG_PRIORITY] = "PRIORITY"; // Same as FLAG_COMPRESSED. + FLAGS[FLAG_END_HEADERS | FLAG_PRIORITY] = "END_HEADERS|PRIORITY"; // Only valid on HEADERS. + int[] frameFlags = + new int[] {FLAG_END_HEADERS, FLAG_PRIORITY, FLAG_END_HEADERS | FLAG_PRIORITY}; + + for (int frameFlag : frameFlags) { + for (int prefixFlag : prefixFlags) { + FLAGS[prefixFlag | frameFlag] = FLAGS[prefixFlag] + '|' + FLAGS[frameFlag]; + FLAGS[prefixFlag | frameFlag | FLAG_PADDED] = + FLAGS[prefixFlag] + '|' + FLAGS[frameFlag] + "|PADDED"; + } + } + + for (int i = 0; i < FLAGS.length; i++) { // Fill in holes with binary representation. + if (FLAGS[i] == null) FLAGS[i] = BINARY[i]; + } + } + } + + private static int readMedium(BufferedSource source) throws IOException { + return (source.readByte() & 0xff) << 16 + | (source.readByte() & 0xff) << 8 + | (source.readByte() & 0xff); + } + + private static void writeMedium(BufferedSink sink, int i) throws IOException { + sink.writeByte((i >>> 16) & 0xff); + sink.writeByte((i >>> 8) & 0xff); + sink.writeByte(i & 0xff); + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Huffman.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Huffman.java new file mode 100644 index 000000000..11370ddbb --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Huffman.java @@ -0,0 +1,229 @@ +/* + * Copyright 2013 Twitter, 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal.framed; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * This class was originally composed from the following classes in + * <a href="https://github.com/twitter/hpack">Twitter Hpack</a>. + * <ul> + * <li>{@code com.twitter.hpack.HuffmanEncoder}</li> + * <li>{@code com.twitter.hpack.HuffmanDecoder}</li> + * <li>{@code com.twitter.hpack.HpackUtil}</li> + * </ul> + */ +class Huffman { + + // Appendix C: Huffman Codes + // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#appendix-B + private static final int[] CODES = { + 0x1ff8, 0x7fffd8, 0xfffffe2, 0xfffffe3, 0xfffffe4, 0xfffffe5, 0xfffffe6, 0xfffffe7, 0xfffffe8, + 0xffffea, 0x3ffffffc, 0xfffffe9, 0xfffffea, 0x3ffffffd, 0xfffffeb, 0xfffffec, 0xfffffed, + 0xfffffee, 0xfffffef, 0xffffff0, 0xffffff1, 0xffffff2, 0x3ffffffe, 0xffffff3, 0xffffff4, + 0xffffff5, 0xffffff6, 0xffffff7, 0xffffff8, 0xffffff9, 0xffffffa, 0xffffffb, 0x14, 0x3f8, + 0x3f9, 0xffa, 0x1ff9, 0x15, 0xf8, 0x7fa, 0x3fa, 0x3fb, 0xf9, 0x7fb, 0xfa, 0x16, 0x17, 0x18, + 0x0, 0x1, 0x2, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x5c, 0xfb, 0x7ffc, 0x20, 0xffb, + 0x3fc, 0x1ffa, 0x21, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0xfc, 0x73, 0xfd, 0x1ffb, 0x7fff0, + 0x1ffc, 0x3ffc, 0x22, 0x7ffd, 0x3, 0x23, 0x4, 0x24, 0x5, 0x25, 0x26, 0x27, 0x6, 0x74, 0x75, + 0x28, 0x29, 0x2a, 0x7, 0x2b, 0x76, 0x2c, 0x8, 0x9, 0x2d, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7ffe, + 0x7fc, 0x3ffd, 0x1ffd, 0xffffffc, 0xfffe6, 0x3fffd2, 0xfffe7, 0xfffe8, 0x3fffd3, 0x3fffd4, + 0x3fffd5, 0x7fffd9, 0x3fffd6, 0x7fffda, 0x7fffdb, 0x7fffdc, 0x7fffdd, 0x7fffde, 0xffffeb, + 0x7fffdf, 0xffffec, 0xffffed, 0x3fffd7, 0x7fffe0, 0xffffee, 0x7fffe1, 0x7fffe2, 0x7fffe3, + 0x7fffe4, 0x1fffdc, 0x3fffd8, 0x7fffe5, 0x3fffd9, 0x7fffe6, 0x7fffe7, 0xffffef, 0x3fffda, + 0x1fffdd, 0xfffe9, 0x3fffdb, 0x3fffdc, 0x7fffe8, 0x7fffe9, 0x1fffde, 0x7fffea, 0x3fffdd, + 0x3fffde, 0xfffff0, 0x1fffdf, 0x3fffdf, 0x7fffeb, 0x7fffec, 0x1fffe0, 0x1fffe1, 0x3fffe0, + 0x1fffe2, 0x7fffed, 0x3fffe1, 0x7fffee, 0x7fffef, 0xfffea, 0x3fffe2, 0x3fffe3, 0x3fffe4, + 0x7ffff0, 0x3fffe5, 0x3fffe6, 0x7ffff1, 0x3ffffe0, 0x3ffffe1, 0xfffeb, 0x7fff1, 0x3fffe7, + 0x7ffff2, 0x3fffe8, 0x1ffffec, 0x3ffffe2, 0x3ffffe3, 0x3ffffe4, 0x7ffffde, 0x7ffffdf, + 0x3ffffe5, 0xfffff1, 0x1ffffed, 0x7fff2, 0x1fffe3, 0x3ffffe6, 0x7ffffe0, 0x7ffffe1, 0x3ffffe7, + 0x7ffffe2, 0xfffff2, 0x1fffe4, 0x1fffe5, 0x3ffffe8, 0x3ffffe9, 0xffffffd, 0x7ffffe3, + 0x7ffffe4, 0x7ffffe5, 0xfffec, 0xfffff3, 0xfffed, 0x1fffe6, 0x3fffe9, 0x1fffe7, 0x1fffe8, + 0x7ffff3, 0x3fffea, 0x3fffeb, 0x1ffffee, 0x1ffffef, 0xfffff4, 0xfffff5, 0x3ffffea, 0x7ffff4, + 0x3ffffeb, 0x7ffffe6, 0x3ffffec, 0x3ffffed, 0x7ffffe7, 0x7ffffe8, 0x7ffffe9, 0x7ffffea, + 0x7ffffeb, 0xffffffe, 0x7ffffec, 0x7ffffed, 0x7ffffee, 0x7ffffef, 0x7fffff0, 0x3ffffee + }; + + private static final byte[] CODE_LENGTHS = { + 13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 30, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6, 5, + 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10, 13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6, 15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, + 6, 6, 5, 6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28, 20, 22, 20, 20, 22, 22, 22, 23, + 22, 23, 23, 23, 23, 23, 24, 23, 24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, + 24, 22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23, 21, 21, 22, 21, 23, 22, + 23, 23, 20, 22, 22, 22, 23, 22, 22, 23, 26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, + 26, 24, 25, 19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27, 20, 24, 20, 21, + 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23, 26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, + 27, 27, 27, 27, 26 + }; + + private static final Huffman INSTANCE = new Huffman(); + + public static Huffman get() { + return INSTANCE; + } + + private final Node root = new Node(); + + private Huffman() { + buildTree(); + } + + void encode(byte[] data, OutputStream out) throws IOException { + long current = 0; + int n = 0; + + for (int i = 0; i < data.length; i++) { + int b = data[i] & 0xFF; + int code = CODES[b]; + int nbits = CODE_LENGTHS[b]; + + current <<= nbits; + current |= code; + n += nbits; + + while (n >= 8) { + n -= 8; + out.write(((int) (current >> n))); + } + } + + if (n > 0) { + current <<= (8 - n); + current |= (0xFF >>> n); + out.write((int) current); + } + } + + int encodedLength(byte[] bytes) { + long len = 0; + + for (int i = 0; i < bytes.length; i++) { + int b = bytes[i] & 0xFF; + len += CODE_LENGTHS[b]; + } + + return (int) ((len + 7) >> 3); + } + + byte[] decode(byte[] buf) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Node node = root; + int current = 0; + int nbits = 0; + for (int i = 0; i < buf.length; i++) { + int b = buf[i] & 0xFF; + current = (current << 8) | b; + nbits += 8; + while (nbits >= 8) { + int c = (current >>> (nbits - 8)) & 0xFF; + node = node.children[c]; + if (node.children == null) { + // terminal node + baos.write(node.symbol); + nbits -= node.terminalBits; + node = root; + } else { + // non-terminal node + nbits -= 8; + } + } + } + + while (nbits > 0) { + int c = (current << (8 - nbits)) & 0xFF; + node = node.children[c]; + if (node.children != null || node.terminalBits > nbits) { + break; + } + baos.write(node.symbol); + nbits -= node.terminalBits; + node = root; + } + + return baos.toByteArray(); + } + + private void buildTree() { + for (int i = 0; i < CODE_LENGTHS.length; i++) { + addCode(i, CODES[i], CODE_LENGTHS[i]); + } + } + + private void addCode(int sym, int code, byte len) { + Node terminal = new Node(sym, len); + + Node current = root; + while (len > 8) { + len -= 8; + int i = ((code >>> len) & 0xFF); + if (current.children == null) { + throw new IllegalStateException("invalid dictionary: prefix not unique"); + } + if (current.children[i] == null) { + current.children[i] = new Node(); + } + current = current.children[i]; + } + + int shift = 8 - len; + int start = (code << shift) & 0xFF; + int end = 1 << shift; + for (int i = start; i < start + end; i++) { + current.children[i] = terminal; + } + } + + private static final class Node { + + // Null if terminal. + private final Node[] children; + + // Terminal nodes have a symbol. + private final int symbol; + + // Number of bits represented in the terminal node. + private final int terminalBits; + + /** Construct an internal node. */ + Node() { + this.children = new Node[256]; + this.symbol = 0; // Not read. + this.terminalBits = 0; // Not read. + } + + /** + * Construct a terminal node. + * + * @param symbol symbol the node represents + * @param bits length of Huffman code in bits + */ + Node(int symbol, int bits) { + this.children = null; + this.symbol = symbol; + int b = bits & 0x07; + this.terminalBits = b == 0 ? 8 : b; + } + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Settings.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Settings.java new file mode 100644 index 000000000..0d0ecce99 --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Settings.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2012 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal.framed; + +import java.util.Arrays; + +/** + * Settings describe characteristics of the sending peer, which are used by the receiving peer. + */ +public final class Settings { + /** + * From the SPDY/3 and HTTP/2 specs, the default initial window size for all + * streams is 64 KiB. (Chrome 25 uses 10 MiB). + */ + static final int DEFAULT_INITIAL_WINDOW_SIZE = 64 * 1024; + + /** Peer request to clear durable settings. */ + static final int FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS = 0x1; + + /** Sent by servers only. The peer requests this setting persisted for future connections. */ + static final int PERSIST_VALUE = 0x1; + /** Sent by clients only. The client is reminding the server of a persisted value. */ + static final int PERSISTED = 0x2; + + /** spdy/3: Sender's estimate of max incoming kbps. */ + static final int UPLOAD_BANDWIDTH = 1; + /** HTTP/2: Size in bytes of the table used to decode the sender's header blocks. */ + static final int HEADER_TABLE_SIZE = 1; + /** spdy/3: Sender's estimate of max outgoing kbps. */ + static final int DOWNLOAD_BANDWIDTH = 2; + /** HTTP/2: The peer must not send a PUSH_PROMISE frame when this is 0. */ + static final int ENABLE_PUSH = 2; + /** spdy/3: Sender's estimate of millis between sending a request and receiving a response. */ + static final int ROUND_TRIP_TIME = 3; + /** Sender's maximum number of concurrent streams. */ + public static final int MAX_CONCURRENT_STREAMS = 4; + /** spdy/3: Current CWND in Packets. */ + static final int CURRENT_CWND = 5; + /** HTTP/2: Size in bytes of the largest frame payload the sender will accept. */ + static final int MAX_FRAME_SIZE = 5; + /** spdy/3: Retransmission rate. Percentage */ + static final int DOWNLOAD_RETRANS_RATE = 6; + /** HTTP/2: Advisory only. Size in bytes of the largest header list the sender will accept. */ + static final int MAX_HEADER_LIST_SIZE = 6; + /** Window size in bytes. */ + public static final int INITIAL_WINDOW_SIZE = 7; + /** spdy/3: Size of the client certificate vector. Unsupported. */ + static final int CLIENT_CERTIFICATE_VECTOR_SIZE = 8; + /** Flow control options. */ + static final int FLOW_CONTROL_OPTIONS = 10; + + /** Total number of settings. */ + static final int COUNT = 10; + + /** If set, flow control is disabled for streams directed to the sender of these settings. */ + static final int FLOW_CONTROL_OPTIONS_DISABLED = 0x1; + + /** Bitfield of which flags that values. */ + private int set; + + /** Bitfield of flags that have {@link #PERSIST_VALUE}. */ + private int persistValue; + + /** Bitfield of flags that have {@link #PERSISTED}. */ + private int persisted; + + /** Flag values. */ + private final int[] values = new int[COUNT]; + + void clear() { + set = persistValue = persisted = 0; + Arrays.fill(values, 0); + } + + public Settings set(int id, int idFlags, int value) { + if (id >= values.length) { + return this; // Discard unknown settings. + } + + int bit = 1 << id; + set |= bit; + if ((idFlags & PERSIST_VALUE) != 0) { + persistValue |= bit; + } else { + persistValue &= ~bit; + } + if ((idFlags & PERSISTED) != 0) { + persisted |= bit; + } else { + persisted &= ~bit; + } + + values[id] = value; + return this; + } + + /** Returns true if a value has been assigned for the setting {@code id}. */ + public boolean isSet(int id) { + int bit = 1 << id; + return (set & bit) != 0; + } + + /** Returns the value for the setting {@code id}, or 0 if unset. */ + public int get(int id) { + return values[id]; + } + + /** Returns the flags for the setting {@code id}, or 0 if unset. */ + int flags(int id) { + int result = 0; + if (isPersisted(id)) result |= Settings.PERSISTED; + if (persistValue(id)) result |= Settings.PERSIST_VALUE; + return result; + } + + /** Returns the number of settings that have values assigned. */ + int size() { + return Integer.bitCount(set); + } + + /** spdy/3 only. */ + int getUploadBandwidth(int defaultValue) { + int bit = 1 << UPLOAD_BANDWIDTH; + return (bit & set) != 0 ? values[UPLOAD_BANDWIDTH] : defaultValue; + } + + /** HTTP/2 only. Returns -1 if unset. */ + int getHeaderTableSize() { + int bit = 1 << HEADER_TABLE_SIZE; + return (bit & set) != 0 ? values[HEADER_TABLE_SIZE] : -1; + } + + /** spdy/3 only. */ + int getDownloadBandwidth(int defaultValue) { + int bit = 1 << DOWNLOAD_BANDWIDTH; + return (bit & set) != 0 ? values[DOWNLOAD_BANDWIDTH] : defaultValue; + } + + /** HTTP/2 only. */ + // TODO: honor this setting in HTTP/2. + boolean getEnablePush(boolean defaultValue) { + int bit = 1 << ENABLE_PUSH; + return ((bit & set) != 0 ? values[ENABLE_PUSH] : defaultValue ? 1 : 0) == 1; + } + + /** spdy/3 only. */ + int getRoundTripTime(int defaultValue) { + int bit = 1 << ROUND_TRIP_TIME; + return (bit & set) != 0 ? values[ROUND_TRIP_TIME] : defaultValue; + } + + // TODO: honor this setting in spdy/3 and HTTP/2. + int getMaxConcurrentStreams(int defaultValue) { + int bit = 1 << MAX_CONCURRENT_STREAMS; + return (bit & set) != 0 ? values[MAX_CONCURRENT_STREAMS] : defaultValue; + } + + /** spdy/3 only. */ + int getCurrentCwnd(int defaultValue) { + int bit = 1 << CURRENT_CWND; + return (bit & set) != 0 ? values[CURRENT_CWND] : defaultValue; + } + + /** HTTP/2 only. */ + int getMaxFrameSize(int defaultValue) { + int bit = 1 << MAX_FRAME_SIZE; + return (bit & set) != 0 ? values[MAX_FRAME_SIZE] : defaultValue; + } + + /** spdy/3 only. */ + int getDownloadRetransRate(int defaultValue) { + int bit = 1 << DOWNLOAD_RETRANS_RATE; + return (bit & set) != 0 ? values[DOWNLOAD_RETRANS_RATE] : defaultValue; + } + + /** HTTP/2 only. */ + int getMaxHeaderListSize(int defaultValue) { + int bit = 1 << MAX_HEADER_LIST_SIZE; + return (bit & set) != 0 ? values[MAX_HEADER_LIST_SIZE] : defaultValue; + } + + int getInitialWindowSize(int defaultValue) { + int bit = 1 << INITIAL_WINDOW_SIZE; + return (bit & set) != 0 ? values[INITIAL_WINDOW_SIZE] : defaultValue; + } + + /** spdy/3 only. */ + int getClientCertificateVectorSize(int defaultValue) { + int bit = 1 << CLIENT_CERTIFICATE_VECTOR_SIZE; + return (bit & set) != 0 ? values[CLIENT_CERTIFICATE_VECTOR_SIZE] : defaultValue; + } + + // TODO: honor this setting in spdy/3 and HTTP/2. + boolean isFlowControlDisabled() { + int bit = 1 << FLOW_CONTROL_OPTIONS; + int value = (bit & set) != 0 ? values[FLOW_CONTROL_OPTIONS] : 0; + return (value & FLOW_CONTROL_OPTIONS_DISABLED) != 0; + } + + /** + * Returns true if this user agent should use this setting in future spdy/3 + * connections to the same host. + */ + boolean persistValue(int id) { + int bit = 1 << id; + return (persistValue & bit) != 0; + } + + /** Returns true if this setting was persisted. */ + boolean isPersisted(int id) { + int bit = 1 << id; + return (persisted & bit) != 0; + } + + /** + * Writes {@code other} into this. If any setting is populated by this and + * {@code other}, the value and flags from {@code other} will be kept. + */ + void merge(Settings other) { + for (int i = 0; i < COUNT; i++) { + if (!other.isSet(i)) continue; + set(i, other.flags(i), other.get(i)); + } + } +} diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Variant.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Variant.java new file mode 100644 index 000000000..2b707081b --- /dev/null +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/framed/Variant.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2013 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. + */ +/* + * Forked from OkHttp 2.5.0 + */ + +package io.grpc.okhttp.internal.framed; + +import io.grpc.okhttp.internal.Protocol; +import okio.BufferedSink; +import okio.BufferedSource; + +/** A version and dialect of the framed socket protocol. */ +public interface Variant { + + /** The protocol as selected using ALPN. */ + Protocol getProtocol(); + + /** + * @param client true if this is the HTTP client's reader, reading frames from a server. + */ + FrameReader newReader(BufferedSource source, boolean client); + + /** + * @param client true if this is the HTTP client's writer, writing frames to a server. + */ + FrameWriter newWriter(BufferedSink sink, boolean client); +} |