From 801197e83981788a2cbb0b627b3ef748c36696ba Mon Sep 17 00:00:00 2001 From: Carter Kozak Date: Wed, 31 Oct 2018 09:35:45 -0400 Subject: [PATCH 01/20] Upgrade Conscrypt to 1.4.0 (was 1.3.0) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4d3ab6ebc1e3..dbdbc9c16df0 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.1.0 0.19 1.15.0 - 1.3.0 + 1.4.0 4.12 From c951e6ed887ad8b9595652f39dad646590b22037 Mon Sep 17 00:00:00 2001 From: Joshua Shanks Date: Wed, 31 Oct 2018 08:31:05 -0700 Subject: [PATCH 02/20] APIs to set date headers --- .../src/test/java/okhttp3/HeadersTest.java | 41 ++++++++++++- okhttp/src/main/java/okhttp3/Headers.java | 20 +++++++ .../okhttp3/recipes/CurrentDateHeader.java | 58 +++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 samples/guide/src/main/java/okhttp3/recipes/CurrentDateHeader.java diff --git a/okhttp-tests/src/test/java/okhttp3/HeadersTest.java b/okhttp-tests/src/test/java/okhttp3/HeadersTest.java index ee136e449d90..d5a9e330fdae 100644 --- a/okhttp-tests/src/test/java/okhttp3/HeadersTest.java +++ b/okhttp-tests/src/test/java/okhttp3/HeadersTest.java @@ -16,9 +16,9 @@ package okhttp3; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -811,4 +811,43 @@ public final class HeadersTest { .build() .byteCount()); } + + @Test public void addDate() { + Date expected = new Date(0); + Headers headers = new Headers.Builder() + .add("testDate", expected) + .build(); + assertEquals("Thu, 01 Jan 1970 00:00:00 GMT", headers.get("testDate")); + } + + @Test public void addDateNull() { + try { + new Headers.Builder() + .add("testDate", (Date) null) + .build(); + fail(); + } catch (NullPointerException expected) { + assertEquals("value for name testDate == null", expected.getMessage()); + } + } + + @Test public void setDate() { + Date expected = new Date(1000); + Headers headers = new Headers.Builder() + .add("testDate", new Date(0)) + .set("testDate", expected) + .build(); + assertEquals("Thu, 01 Jan 1970 00:00:01 GMT", headers.get("testDate")); + } + + @Test public void setDateNull() { + try { + new Headers.Builder() + .set("testDate", (Date) null) + .build(); + fail(); + } catch (NullPointerException expected) { + assertEquals("value for name testDate == null", expected.getMessage()); + } + } } diff --git a/okhttp/src/main/java/okhttp3/Headers.java b/okhttp/src/main/java/okhttp3/Headers.java index 73552fbee041..8b662c96ac98 100644 --- a/okhttp/src/main/java/okhttp3/Headers.java +++ b/okhttp/src/main/java/okhttp3/Headers.java @@ -334,6 +334,26 @@ public Builder addAll(Headers headers) { return this; } + /** + * Add a header with the specified name and formatted Date. + * Does validation of header names and values. + */ + public Builder add(String name, Date value) { + if (value == null) throw new NullPointerException("value for name " + name + " == null"); + add(name, HttpDate.format(value)); + return this; + } + + /** + * Set a field with the specified date. If the field is not found, it is added. If the field is + * found, the existing values are replaced. + */ + public Builder set(String name, Date value) { + if (value == null) throw new NullPointerException("value for name " + name + " == null"); + set(name, HttpDate.format(value)); + return this; + } + /** * Add a field with the specified value without any validation. Only appropriate for headers * from the remote peer or cache. diff --git a/samples/guide/src/main/java/okhttp3/recipes/CurrentDateHeader.java b/samples/guide/src/main/java/okhttp3/recipes/CurrentDateHeader.java new file mode 100644 index 000000000000..6c15d700df87 --- /dev/null +++ b/samples/guide/src/main/java/okhttp3/recipes/CurrentDateHeader.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 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. + */ +package okhttp3.recipes; + +import java.io.IOException; +import java.util.Date; +import okhttp3.Headers; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +public final class CurrentDateHeader { + private final OkHttpClient client = new OkHttpClient.Builder() + .addInterceptor(new CurrentDateInterceptor()) + .build(); + + public void run() throws Exception { + Request request = new Request.Builder() + .url("https://publicobject.com/helloworld.txt") + .build(); + + try (Response response = client.newCall(request).execute()) { + System.out.println(response.request().header("Date")); + } + } + + static class CurrentDateInterceptor implements Interceptor { + @Override public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + Headers newHeaders = request.headers() + .newBuilder() + .add("Date", new Date()) + .build(); + Request newRequest = request.newBuilder() + .headers(newHeaders) + .build(); + return chain.proceed(newRequest); + } + } + + public static void main(String... args) throws Exception { + new CurrentDateHeader().run(); + } +} From 59ab235004550cdfb4033872b8736f0e86cef402 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 3 Nov 2018 08:42:42 +0000 Subject: [PATCH 03/20] Allow incomplete url builder toString usage (#4357) The builder can be in a state that build() is not yet valid, but should have a valid toString for debugging purposes. --- .../src/test/java/okhttp3/HttpUrlTest.java | 27 ++++++++------- okhttp/src/main/java/okhttp3/HttpUrl.java | 33 ++++++++++--------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/okhttp-tests/src/test/java/okhttp3/HttpUrlTest.java b/okhttp-tests/src/test/java/okhttp3/HttpUrlTest.java index 2025e13a7e6e..6589d5850c9d 100644 --- a/okhttp-tests/src/test/java/okhttp3/HttpUrlTest.java +++ b/okhttp-tests/src/test/java/okhttp3/HttpUrlTest.java @@ -15,10 +15,8 @@ */ package okhttp3; -import java.net.MalformedURLException; import java.net.URI; import java.net.URL; -import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -772,18 +770,19 @@ HttpUrl parse(String url) { } catch (IllegalStateException expected) { assertEquals("scheme == null", expected.getMessage()); } - try { - new HttpUrl.Builder().scheme("http").toString(); - fail(); - } catch (IllegalStateException expected) { - assertEquals("host == null", expected.getMessage()); - } - try { - new HttpUrl.Builder().host("host").toString(); - fail(); - } catch (IllegalStateException expected) { - assertEquals("scheme == null", expected.getMessage()); - } + } + + @Test public void builderToString() { + assertEquals("https://host.com/path", parse("https://host.com/path").newBuilder().toString()); + } + + @Test public void incompleteBuilderToString() { + assertEquals("https:///path", + new HttpUrl.Builder().scheme("https").encodedPath("/path").toString()); + assertEquals("://host.com/path", + new HttpUrl.Builder().host("host.com").encodedPath("/path").toString()); + assertEquals("://host.com:8080/path", + new HttpUrl.Builder().host("host.com").encodedPath("/path").port(8080).toString()); } @Test public void minimalUrlComposition() throws Exception { diff --git a/okhttp/src/main/java/okhttp3/HttpUrl.java b/okhttp/src/main/java/okhttp3/HttpUrl.java index 5534ac2a26b5..528d1cc46a58 100644 --- a/okhttp/src/main/java/okhttp3/HttpUrl.java +++ b/okhttp/src/main/java/okhttp3/HttpUrl.java @@ -1257,11 +1257,10 @@ public HttpUrl build() { } @Override public String toString() { - if (scheme == null) throw new IllegalStateException("scheme == null"); - if (host == null) throw new IllegalStateException("host == null"); - StringBuilder result = new StringBuilder(); - result.append(scheme); + if (scheme != null) { + result.append(scheme); + } result.append("://"); if (!encodedUsername.isEmpty() || !encodedPassword.isEmpty()) { @@ -1273,19 +1272,23 @@ public HttpUrl build() { result.append('@'); } - if (host.indexOf(':') != -1) { - // Host is an IPv6 address. - result.append('['); - result.append(host); - result.append(']'); - } else { - result.append(host); + if (host != null) { + if (host.indexOf(':') != -1) { + // Host is an IPv6 address. + result.append('['); + result.append(host); + result.append(']'); + } else { + result.append(host); + } } - int effectivePort = effectivePort(); - if (effectivePort != defaultPort(scheme)) { - result.append(':'); - result.append(effectivePort); + if (port != -1 || scheme != null) { + int effectivePort = effectivePort(); + if (scheme == null || effectivePort != defaultPort(scheme)) { + result.append(':'); + result.append(effectivePort); + } } pathSegmentsToString(result, encodedPathSegments); From d313ffcca0d461352adc1ef6468094e230dbc48c Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Sat, 3 Nov 2018 19:40:13 +1100 Subject: [PATCH 04/20] Limit the use of regexes in the RFC 7235 challenge parser. Creating patterns dynamically to do comma-escaping is pretty awkward. This is more code but I have more confidence in it. --- .../src/test/java/okhttp3/HeadersTest.java | 18 +- .../test/java/okhttp3/URLConnectionTest.java | 4 +- okhttp/src/main/java/okhttp3/Response.java | 19 +- .../okhttp3/internal/http/HttpHeaders.java | 284 ++++++++++-------- 4 files changed, 182 insertions(+), 143 deletions(-) diff --git a/okhttp-tests/src/test/java/okhttp3/HeadersTest.java b/okhttp-tests/src/test/java/okhttp3/HeadersTest.java index d5a9e330fdae..fc134f49e502 100644 --- a/okhttp-tests/src/test/java/okhttp3/HeadersTest.java +++ b/okhttp-tests/src/test/java/okhttp3/HeadersTest.java @@ -26,6 +26,7 @@ import okhttp3.internal.http.HttpHeaders; import okhttp3.internal.http2.Header; import okhttp3.internal.http2.Http2Codec; +import org.junit.Ignore; import org.junit.Test; import static java.util.Collections.emptyList; @@ -718,7 +719,9 @@ public final class HeadersTest { .add("WWW-Authenticate", "Digest,,,, Basic ,,,realm=\"my\\\\\\\\\"r\\ealm\"") .build(); - assertEquals(emptyList(), HttpHeaders.parseChallenges(headers, "WWW-Authenticate")); + assertEquals(Arrays.asList( + new Challenge("Digest", Collections.emptyMap())), + HttpHeaders.parseChallenges(headers, "WWW-Authenticate")); } @Test public void unescapedDoubleQuoteInQuotedString() { @@ -726,15 +729,20 @@ public final class HeadersTest { .add("WWW-Authenticate", "Digest,,,, Basic ,,,realm=\"my\"realm\"") .build(); - assertEquals(emptyList(), HttpHeaders.parseChallenges(headers, "WWW-Authenticate")); + assertEquals(Arrays.asList( + new Challenge("Digest", Collections.emptyMap())), + HttpHeaders.parseChallenges(headers, "WWW-Authenticate")); } + @Ignore("TODO(jwilson): reject parameters that use invalid characters") @Test public void doubleQuoteInToken() { Headers headers = new Headers.Builder() .add("WWW-Authenticate", "Digest,,,, Basic ,,,realm=my\"realm") .build(); - assertEquals(emptyList(), HttpHeaders.parseChallenges(headers, "WWW-Authenticate")); + assertEquals(Arrays.asList( + new Challenge("Digest", Collections.emptyMap())), + HttpHeaders.parseChallenges(headers, "WWW-Authenticate")); } @Test public void token68InsteadOfAuthParams() { @@ -752,7 +760,9 @@ public final class HeadersTest { .add("WWW-Authenticate", "Other abc==, realm=myrealm") .build(); - assertEquals(emptyList(), HttpHeaders.parseChallenges(headers, "WWW-Authenticate")); + assertEquals(Arrays.asList( + new Challenge("Other", singletonMap((String) null, "abc=="))), + HttpHeaders.parseChallenges(headers, "WWW-Authenticate")); } @Test public void repeatedAuthParamKey() { diff --git a/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java b/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java index da0595de073c..452949039642 100644 --- a/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java +++ b/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java @@ -3198,7 +3198,7 @@ private void reusedConnectionFailsWithPost(TransferKind transferKind, int reques assertEquals(Proxy.NO_PROXY, authenticator.onlyRoute().proxy()); Response response = authenticator.onlyResponse(); assertEquals("/private", response.request().url().url().getPath()); - assertEquals(Arrays.asList(new Challenge("Basic", singletonMap("realm", "protected area"))), response.challenges()); + assertEquals(Arrays.asList(new Challenge("Basic", "protected area")), response.challenges()); } @Test public void customTokenAuthenticator() throws Exception { @@ -3219,7 +3219,7 @@ private void reusedConnectionFailsWithPost(TransferKind transferKind, int reques Response response = authenticator.onlyResponse(); assertEquals("/private", response.request().url().url().getPath()); - assertEquals(Arrays.asList(new Challenge("Bearer", singletonMap("realm", "oauthed"))), response.challenges()); + assertEquals(Arrays.asList(new Challenge("Bearer", "oauthed")), response.challenges()); } @Test public void authenticateCallsTrackedAsRedirects() throws Exception { diff --git a/okhttp/src/main/java/okhttp3/Response.java b/okhttp/src/main/java/okhttp3/Response.java index 9c4951e6a12e..b9ec3993806c 100644 --- a/okhttp/src/main/java/okhttp3/Response.java +++ b/okhttp/src/main/java/okhttp3/Response.java @@ -225,16 +225,15 @@ public boolean isRedirect() { } /** - * Returns the RFC 7235 authorization challenges appropriate for this response's code. - * If the response code is 401 unauthorized, this returns the "WWW-Authenticate" challenges. - * If the response code is 407 proxy unauthorized, this returns the "Proxy-Authenticate" - * challenges. Otherwise this returns an empty list of challenges. - *

- * If a challenge uses the {@code token68} variant instead of auth params, - * there is exactly one auth param in the challenge at key {@code null}. - * Invalid headers and challenges are ignored. - * No semantic validation is done, for example that {@code Basic} auth must have a - * {@code realm} auth param, this is up to the caller that interprets these challenges. + * Returns the RFC 7235 authorization challenges appropriate for this response's code. If the + * response code is 401 unauthorized, this returns the "WWW-Authenticate" challenges. If the + * response code is 407 proxy unauthorized, this returns the "Proxy-Authenticate" challenges. + * Otherwise this returns an empty list of challenges. + * + *

If a challenge uses the {@code token68} variant instead of auth params, there is exactly one + * auth param in the challenge at key {@code null}. Invalid headers and challenges are ignored. + * No semantic validation is done, for example that {@code Basic} auth must have a {@code realm} + * auth param, this is up to the caller that interprets these challenges. */ public List challenges() { String responseField; diff --git a/okhttp/src/main/java/okhttp3/internal/http/HttpHeaders.java b/okhttp/src/main/java/okhttp3/internal/http/HttpHeaders.java index 2126645bf386..479fe07a24ff 100644 --- a/okhttp/src/main/java/okhttp3/internal/http/HttpHeaders.java +++ b/okhttp/src/main/java/okhttp3/internal/http/HttpHeaders.java @@ -15,15 +15,15 @@ */ package okhttp3.internal.http; +import java.io.EOFException; 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.Set; import java.util.TreeSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import okhttp3.Challenge; import okhttp3.Cookie; import okhttp3.CookieJar; @@ -31,52 +31,18 @@ import okhttp3.HttpUrl; import okhttp3.Request; import okhttp3.Response; +import okio.Buffer; +import okio.ByteString; import static java.net.HttpURLConnection.HTTP_NOT_MODIFIED; import static java.net.HttpURLConnection.HTTP_NO_CONTENT; -import static java.util.Locale.US; import static okhttp3.internal.Util.equal; import static okhttp3.internal.http.StatusLine.HTTP_CONTINUE; /** Headers and utilities for internal use by OkHttp. */ public final class HttpHeaders { - // regexes according to RFC 7235 - private static final String TOKEN_PATTERN_PART = "[!#$%&'*+.^_`|~\\p{Alnum}-]+"; - private static final String TOKEN68_PATTERN_PART = "[\\p{Alnum}._~+/-]+=*"; - private static final String OWS_PATTERN_PART = "[ \\t]*"; - private static final String QUOTED_PAIR_PATTERN_PART = "\\\\([\\t \\p{Graph}\\x80-\\xFF])"; - private static final String QUOTED_STRING_PATTERN_PART = - "\"(?:[\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|" + QUOTED_PAIR_PATTERN_PART + ")*\""; - private static final String AUTH_PARAM_PATTERN_PART = TOKEN_PATTERN_PART + OWS_PATTERN_PART + '=' - + OWS_PATTERN_PART + "(?:" + TOKEN_PATTERN_PART + '|' + QUOTED_STRING_PATTERN_PART + ')'; - private static final String CHALLENGE_PATTERN_PART = TOKEN_PATTERN_PART + "(?: +(?:" - + TOKEN68_PATTERN_PART + "|(?:,|" + AUTH_PARAM_PATTERN_PART + ")(?:" + OWS_PATTERN_PART - + ",(?:" + OWS_PATTERN_PART + AUTH_PARAM_PATTERN_PART + ")?)*)?)?"; - private static final String AUTHENTICATION_HEADER_VALUE_SPLIT_PATTERN_PART = - "(?:" + OWS_PATTERN_PART + ',' + OWS_PATTERN_PART + ")+"; - - private static final Pattern AUTHENTICATION_HEADER_VALUE_PATTERN = Pattern.compile("^(?:," - + OWS_PATTERN_PART + ")*" + CHALLENGE_PATTERN_PART + "(?:" + OWS_PATTERN_PART + ",(?:" - + OWS_PATTERN_PART + CHALLENGE_PATTERN_PART + ")?)*$"); - private static final Pattern AUTH_SCHEME_PATTERN = - Pattern.compile('^' + TOKEN_PATTERN_PART + '$'); - private static final Pattern AUTH_SCHEME_AND_TOKEN68_PATTERN = - Pattern.compile('^' + TOKEN_PATTERN_PART + " +" + TOKEN68_PATTERN_PART + '$'); - private static final Pattern AUTH_SCHEME_AND_PARAM_PATTERN = - Pattern.compile('^' + TOKEN_PATTERN_PART + " +" + AUTH_PARAM_PATTERN_PART + '$'); - private static final Pattern AUTH_PARAM_PATTERN = - Pattern.compile('^' + AUTH_PARAM_PATTERN_PART + '$'); - private static final Pattern TOKEN_PATTERN = Pattern.compile('^' + TOKEN_PATTERN_PART + '$'); - private static final Pattern QUOTED_PAIR_PATTERN = Pattern.compile(QUOTED_PAIR_PATTERN_PART); - - private static final Pattern AUTHENTICATION_HEADER_VALUE_SPLIT_PATTERN = - Pattern.compile(AUTHENTICATION_HEADER_VALUE_SPLIT_PATTERN_PART); - private static final Pattern WHITESPACE_SPLIT_PATTERN = Pattern.compile(" +"); - private static final Pattern AUTH_PARAM_SPLIT_PATTERN = - Pattern.compile(OWS_PATTERN_PART + '=' + OWS_PATTERN_PART); - private static final Pattern QUOTED_STRING_AUTH_PARAM_AT_END_PATTERN = - Pattern.compile(TOKEN_PATTERN_PART + OWS_PATTERN_PART + '=' + OWS_PATTERN_PART - + QUOTED_STRING_PATTERN_PART + '$'); + private static final ByteString QUOTED_STRING_DELIMITERS = ByteString.encodeUtf8("\"\\"); + private static final ByteString TOKEN_DELIMITERS = ByteString.encodeUtf8("\t ,="); private HttpHeaders() { } @@ -179,104 +145,168 @@ public static Headers varyHeaders(Headers requestHeaders, Headers responseHeader } /** - * Parse RFC 7235 challenges. + * Parse RFC 7235 challenges. This is awkward because we need to look ahead to know how to + * interpret a token. + * + *

For example, the first line has a parameter name/value pair and the second line has a single + * token68: + * + *

   {@code
+   *
+   *   WWW-Authenticate: Digest foo=bar
+   *   WWW-Authenticate: Digest foo=
+   * }
+ * + *

Similarly, the first line has one challenge and the second line has two challenges: + * + *

   {@code
+   *
+   *   WWW-Authenticate: Digest ,foo=bar
+   *   WWW-Authenticate: Digest ,foo
+   * }
*/ - public static List parseChallenges(Headers responseHeaders, String challengeHeader) { - List challenges = new ArrayList<>(); - List authenticationHeaders = responseHeaders.values(challengeHeader); -headerLoop: - for (String header : authenticationHeaders) { - // ignore invalid header value - if (!AUTHENTICATION_HEADER_VALUE_PATTERN.matcher(header).matches()) { - continue; + public static List parseChallenges(Headers responseHeaders, String headerName) { + List result = new ArrayList<>(); + for (int h = 0; h < responseHeaders.size(); h++) { + if (headerName.equalsIgnoreCase(responseHeaders.name(h))) { + Buffer header = new Buffer().writeUtf8(responseHeaders.value(h)); + parseChallengeHeader(result, header); } + } + return result; + } - // needed to properly abort if a header is invalid due to repeated auth param names - List headerChallenges = new ArrayList<>(); + private static void parseChallengeHeader(List result, Buffer header) { + String peek = null; - String[] challengeParts = AUTHENTICATION_HEADER_VALUE_SPLIT_PATTERN.split(header); - String authScheme = null; - Map authParams = new LinkedHashMap<>(); - for (int i = 0, j = challengeParts.length; i < j; i++) { - String challengePart = challengeParts[i]; + while (true) { + // Read a scheme name for this challenge if we don't have one already. + if (peek == null) { + skipWhitespaceAndCommas(header); + peek = readToken(header); + if (peek == null) return; + } - // skip empty parts that can occur as first and last element - if (challengePart.isEmpty()) { - continue; - } + String schemeName = peek; - String newAuthScheme = null; - String authParam = null; - if (AUTH_SCHEME_PATTERN.matcher(challengePart).matches()) { - newAuthScheme = challengePart; - } else if (AUTH_SCHEME_AND_TOKEN68_PATTERN.matcher(challengePart).matches()) { - String[] authSchemeAndToken68 = WHITESPACE_SPLIT_PATTERN.split(challengePart, 2); - newAuthScheme = authSchemeAndToken68[0]; - if (authParams.put(null, authSchemeAndToken68[1]) != null) { - // if the regex is correct, this must not happen - throw new AssertionError(); - } - } else if (AUTH_SCHEME_AND_PARAM_PATTERN.matcher(challengePart).matches()) { - String[] authSchemeAndParam = WHITESPACE_SPLIT_PATTERN.split(challengePart, 2); - newAuthScheme = authSchemeAndParam[0]; - authParam = authSchemeAndParam[1]; - } else if (AUTH_PARAM_PATTERN.matcher(challengePart).matches()) { - authParam = challengePart; - } else { - // comma in quoted string part got split wrongly - StringBuilder patternBuilder = new StringBuilder(); - patternBuilder.append('^').append(Pattern.quote(challengeParts[0])); - for (int i2 = 1; i2 < i; i2++) { - patternBuilder - .append(AUTHENTICATION_HEADER_VALUE_SPLIT_PATTERN_PART) - .append(Pattern.quote(challengeParts[i2])); - } - // if the algorithm has a flaw, the loop will crash with an ArrayIndexOutOfBoundsException - // if this happens, the algorithm or overall regex has to be fixed, not the array access - Matcher quotedStringAuthParamAtEndMatcher; - do { - patternBuilder - .append(AUTHENTICATION_HEADER_VALUE_SPLIT_PATTERN_PART) - .append(Pattern.quote(challengeParts[i++])); - Matcher matcher = Pattern.compile(patternBuilder.toString()).matcher(header); - if (!matcher.find()) { - // if the algorithm is flawless, this must not happen - throw new AssertionError(); - } - quotedStringAuthParamAtEndMatcher = - QUOTED_STRING_AUTH_PARAM_AT_END_PATTERN.matcher(matcher.group()); - } while (!quotedStringAuthParamAtEndMatcher.find()); - authParam = quotedStringAuthParamAtEndMatcher.group(); - } + // Read a token68, a sequence of parameters, or nothing. + boolean commaPrefixed = skipWhitespaceAndCommas(header); + peek = readToken(header); + if (peek == null) { + if (!header.exhausted()) return; // Expected a token; got something else. + result.add(new Challenge(schemeName, Collections.emptyMap())); + return; + } - if (newAuthScheme != null) { - if (authScheme != null) { - headerChallenges.add(new Challenge(authScheme, authParams)); - authParams.clear(); - } - authScheme = newAuthScheme; - } + int eqCount = skipAll(header, (byte) '='); + boolean commaSuffixed = skipWhitespaceAndCommas(header); - if (authParam != null) { - String[] authParamPair = AUTH_PARAM_SPLIT_PATTERN.split(authParam, 2); - // lower-case to easily check for multiple occurrences - String authParamKey = authParamPair[0].toLowerCase(US); - String authParamValue = authParamPair[1]; - if (!TOKEN_PATTERN.matcher(authParamValue).matches()) { - authParamValue = authParamValue.substring(1, authParamValue.length() - 1); - authParamValue = QUOTED_PAIR_PATTERN.matcher(authParamValue).replaceAll("$1"); - } - if (authParams.put(authParamKey, authParamValue) != null) { - // ignore invalid header value - // auth param keys must not occur multiple times within one challenge - continue headerLoop; - } + // It's a token68 because there isn't a value after it. + if (!commaPrefixed && (commaSuffixed || header.exhausted())) { + result.add(new Challenge(schemeName, Collections.singletonMap( + (String) null, peek + repeat('=', eqCount)))); + peek = null; + continue; + } + + // It's a series of parameter names and values. + Map parameters = new LinkedHashMap<>(); + eqCount += skipAll(header, (byte) '='); + while (true) { + if (peek == null) { + peek = readToken(header); + if (skipWhitespaceAndCommas(header)) break; // We peeked a scheme name followed by ','. + eqCount = skipAll(header, (byte) '='); } + if (eqCount == 0) break; // We peeked a scheme name. + if (eqCount > 1) return; // Unexpected '=' characters. + if (skipWhitespaceAndCommas(header)) return; // Unexpected ','. + + String parameterValue = !header.exhausted() && header.getByte(0) == '"' + ? readQuotedString(header) + : readToken(header); + if (parameterValue == null) return; // Expected a value. + String replaced = parameters.put(peek, parameterValue); + peek = null; + if (replaced != null) return; // Unexpected duplicate parameter. + if (!skipWhitespaceAndCommas(header) && !header.exhausted()) return; // Expected ',' or EOF. + } + result.add(new Challenge(schemeName, parameters)); + } + } + + /** Returns true if any commas were skipped. */ + private static boolean skipWhitespaceAndCommas(Buffer buffer) { + boolean commaFound = false; + while (!buffer.exhausted()) { + byte b = buffer.getByte(0); + if (b == ',') { + buffer.readByte(); // Consume ','. + commaFound = true; + } else if (b == ' ' || b == '\t') { + buffer.readByte(); // Consume space or tab. + } else { + break; } - headerChallenges.add(new Challenge(authScheme, authParams)); - challenges.addAll(headerChallenges); } - return challenges; + return commaFound; + } + + private static int skipAll(Buffer buffer, byte b) { + int count = 0; + while (!buffer.exhausted() && buffer.getByte(0) == b) { + count++; + buffer.readByte(); + } + return count; + } + + /** + * Reads a double-quoted string, unescaping quoted pairs like {@code \"} to the 2nd character in + * each sequence. Returns the unescaped string, or null if the buffer isn't prefixed with a + * double-quoted string. + */ + private static String readQuotedString(Buffer buffer) { + if (buffer.readByte() != '\"') throw new IllegalArgumentException(); + Buffer result = new Buffer(); + while (true) { + long i = buffer.indexOfElement(QUOTED_STRING_DELIMITERS); + if (i == -1L) return null; // Unterminated quoted string. + + if (buffer.getByte(i) == '"') { + result.write(buffer, i); + buffer.readByte(); // Consume '"'. + return result.readUtf8(); + } + + if (buffer.size() == i + 1L) return null; // Dangling escape. + result.write(buffer, i); + buffer.readByte(); // Consume '\'. + result.write(buffer, 1L); // The escaped character. + } + } + + /** + * Consumes and returns a non-empty token, terminating at special characters in {@link + * #TOKEN_DELIMITERS}. Returns null if the buffer is empty or prefixed with a delimiter. + */ + private static String readToken(Buffer buffer) { + try { + long tokenSize = buffer.indexOfElement(TOKEN_DELIMITERS); + if (tokenSize == -1L) tokenSize = buffer.size(); + + return tokenSize != 0L + ? buffer.readUtf8(tokenSize) + : null; + } catch (EOFException e) { + throw new AssertionError(); + } + } + + private static String repeat(char c, int count) { + char[] array = new char[count]; + Arrays.fill(array, c); + return new String(array); } public static void receiveHeaders(CookieJar cookieJar, HttpUrl url, Headers headers) { From 70bf8e78b7dbf8ed08dfd93596ba6ebfca52d3a3 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 3 Nov 2018 13:17:22 +0000 Subject: [PATCH 05/20] CipherSuite init speedup (#4340) --- okhttp/src/main/java/okhttp3/CipherSuite.java | 692 +++++++++--------- 1 file changed, 355 insertions(+), 337 deletions(-) diff --git a/okhttp/src/main/java/okhttp3/CipherSuite.java b/okhttp/src/main/java/okhttp3/CipherSuite.java index b2b6918aa890..ec1875359b18 100644 --- a/okhttp/src/main/java/okhttp3/CipherSuite.java +++ b/okhttp/src/main/java/okhttp3/CipherSuite.java @@ -18,9 +18,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.TreeMap; /** * TLS cipher @@ -61,346 +61,346 @@ public final class CipherSuite { }; /** - * Holds interned instances. This needs to be above the of() calls below so that it's + * Holds interned instances. This needs to be above the init() calls below so that it's * initialized by the time those parts of {@code ()} run. Guarded by CipherSuite.class. */ - private static final Map INSTANCES = new TreeMap<>(ORDER_BY_NAME); + private static final Map INSTANCES = new LinkedHashMap<>(); // Last updated 2016-07-03 using cipher suites from Android 24 and Java 9. - // public static final CipherSuite TLS_NULL_WITH_NULL_NULL = of("TLS_NULL_WITH_NULL_NULL", 0x0000); - public static final CipherSuite TLS_RSA_WITH_NULL_MD5 = of("SSL_RSA_WITH_NULL_MD5", 0x0001); - public static final CipherSuite TLS_RSA_WITH_NULL_SHA = of("SSL_RSA_WITH_NULL_SHA", 0x0002); - public static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = of("SSL_RSA_EXPORT_WITH_RC4_40_MD5", 0x0003); - public static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 = of("SSL_RSA_WITH_RC4_128_MD5", 0x0004); - public static final CipherSuite TLS_RSA_WITH_RC4_128_SHA = of("SSL_RSA_WITH_RC4_128_SHA", 0x0005); - // public static final CipherSuite TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = of("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5", 0x0006); - // public static final CipherSuite TLS_RSA_WITH_IDEA_CBC_SHA = of("TLS_RSA_WITH_IDEA_CBC_SHA", 0x0007); - public static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = of("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0008); - public static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA = of("SSL_RSA_WITH_DES_CBC_SHA", 0x0009); - public static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = of("SSL_RSA_WITH_3DES_EDE_CBC_SHA", 0x000a); - // public static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = of("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x000b); - // public static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = of("TLS_DH_DSS_WITH_DES_CBC_SHA", 0x000c); - // public static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = of("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", 0x000d); - // public static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = of("SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x000e); - // public static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = of("TLS_DH_RSA_WITH_DES_CBC_SHA", 0x000f); - // public static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = of("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", 0x0010); - public static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = of("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x0011); - public static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = of("SSL_DHE_DSS_WITH_DES_CBC_SHA", 0x0012); - public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = of("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", 0x0013); - public static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = of("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0014); - public static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = of("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0015); - public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = of("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", 0x0016); - public static final CipherSuite TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = of("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", 0x0017); - public static final CipherSuite TLS_DH_anon_WITH_RC4_128_MD5 = of("SSL_DH_anon_WITH_RC4_128_MD5", 0x0018); - public static final CipherSuite TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = of("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", 0x0019); - public static final CipherSuite TLS_DH_anon_WITH_DES_CBC_SHA = of("SSL_DH_anon_WITH_DES_CBC_SHA", 0x001a); - public static final CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = of("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", 0x001b); - public static final CipherSuite TLS_KRB5_WITH_DES_CBC_SHA = of("TLS_KRB5_WITH_DES_CBC_SHA", 0x001e); - public static final CipherSuite TLS_KRB5_WITH_3DES_EDE_CBC_SHA = of("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", 0x001f); - public static final CipherSuite TLS_KRB5_WITH_RC4_128_SHA = of("TLS_KRB5_WITH_RC4_128_SHA", 0x0020); - // public static final CipherSuite TLS_KRB5_WITH_IDEA_CBC_SHA = of("TLS_KRB5_WITH_IDEA_CBC_SHA", 0x0021); - public static final CipherSuite TLS_KRB5_WITH_DES_CBC_MD5 = of("TLS_KRB5_WITH_DES_CBC_MD5", 0x0022); - public static final CipherSuite TLS_KRB5_WITH_3DES_EDE_CBC_MD5 = of("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", 0x0023); - public static final CipherSuite TLS_KRB5_WITH_RC4_128_MD5 = of("TLS_KRB5_WITH_RC4_128_MD5", 0x0024); - // public static final CipherSuite TLS_KRB5_WITH_IDEA_CBC_MD5 = of("TLS_KRB5_WITH_IDEA_CBC_MD5", 0x0025); - public static final CipherSuite TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA = of("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", 0x0026); - // public static final CipherSuite TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA = of("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", 0x0027); - public static final CipherSuite TLS_KRB5_EXPORT_WITH_RC4_40_SHA = of("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", 0x0028); - public static final CipherSuite TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 = of("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", 0x0029); - // public static final CipherSuite TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 = of("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", 0x002a); - public static final CipherSuite TLS_KRB5_EXPORT_WITH_RC4_40_MD5 = of("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", 0x002b); - // public static final CipherSuite TLS_PSK_WITH_NULL_SHA = of("TLS_PSK_WITH_NULL_SHA", 0x002c); - // public static final CipherSuite TLS_DHE_PSK_WITH_NULL_SHA = of("TLS_DHE_PSK_WITH_NULL_SHA", 0x002d); - // public static final CipherSuite TLS_RSA_PSK_WITH_NULL_SHA = of("TLS_RSA_PSK_WITH_NULL_SHA", 0x002e); - public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA = of("TLS_RSA_WITH_AES_128_CBC_SHA", 0x002f); - // public static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA = of("TLS_DH_DSS_WITH_AES_128_CBC_SHA", 0x0030); - // public static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA = of("TLS_DH_RSA_WITH_AES_128_CBC_SHA", 0x0031); - public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA = of("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 0x0032); - public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA = of("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 0x0033); - public static final CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA = of("TLS_DH_anon_WITH_AES_128_CBC_SHA", 0x0034); - public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = of("TLS_RSA_WITH_AES_256_CBC_SHA", 0x0035); - // public static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA = of("TLS_DH_DSS_WITH_AES_256_CBC_SHA", 0x0036); - // public static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA = of("TLS_DH_RSA_WITH_AES_256_CBC_SHA", 0x0037); - public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA = of("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", 0x0038); - public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA = of("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", 0x0039); - public static final CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA = of("TLS_DH_anon_WITH_AES_256_CBC_SHA", 0x003a); - public static final CipherSuite TLS_RSA_WITH_NULL_SHA256 = of("TLS_RSA_WITH_NULL_SHA256", 0x003b); - public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA256 = of("TLS_RSA_WITH_AES_128_CBC_SHA256", 0x003c); - public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA256 = of("TLS_RSA_WITH_AES_256_CBC_SHA256", 0x003d); - // public static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = of("TLS_DH_DSS_WITH_AES_128_CBC_SHA256", 0x003e); - // public static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = of("TLS_DH_RSA_WITH_AES_128_CBC_SHA256", 0x003f); - public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = of("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", 0x0040); - public static final CipherSuite TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = of("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0041); - // public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = of("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0042); - // public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = of("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0043); - public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = of("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0044); - public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = of("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0045); - // public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = of("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", 0x0046); - public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = of("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", 0x0067); - // public static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = of("TLS_DH_DSS_WITH_AES_256_CBC_SHA256", 0x0068); - // public static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = of("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x0069); - public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = of("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", 0x006a); - public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = of("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", 0x006b); - public static final CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA256 = of("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x006c); - public static final CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA256 = of("TLS_DH_anon_WITH_AES_256_CBC_SHA256", 0x006d); - public static final CipherSuite TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = of("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0084); - // public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = of("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0085); - // public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = of("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0086); - public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = of("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0087); - public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = of("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0088); - // public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = of("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", 0x0089); - public static final CipherSuite TLS_PSK_WITH_RC4_128_SHA = of("TLS_PSK_WITH_RC4_128_SHA", 0x008a); - public static final CipherSuite TLS_PSK_WITH_3DES_EDE_CBC_SHA = of("TLS_PSK_WITH_3DES_EDE_CBC_SHA", 0x008b); - public static final CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA = of("TLS_PSK_WITH_AES_128_CBC_SHA", 0x008c); - public static final CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA = of("TLS_PSK_WITH_AES_256_CBC_SHA", 0x008d); - // public static final CipherSuite TLS_DHE_PSK_WITH_RC4_128_SHA = of("TLS_DHE_PSK_WITH_RC4_128_SHA", 0x008e); - // public static final CipherSuite TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = of("TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", 0x008f); - // public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CBC_SHA = of("TLS_DHE_PSK_WITH_AES_128_CBC_SHA", 0x0090); - // public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CBC_SHA = of("TLS_DHE_PSK_WITH_AES_256_CBC_SHA", 0x0091); - // public static final CipherSuite TLS_RSA_PSK_WITH_RC4_128_SHA = of("TLS_RSA_PSK_WITH_RC4_128_SHA", 0x0092); - // public static final CipherSuite TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = of("TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", 0x0093); - // public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_CBC_SHA = of("TLS_RSA_PSK_WITH_AES_128_CBC_SHA", 0x0094); - // public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_CBC_SHA = of("TLS_RSA_PSK_WITH_AES_256_CBC_SHA", 0x0095); - public static final CipherSuite TLS_RSA_WITH_SEED_CBC_SHA = of("TLS_RSA_WITH_SEED_CBC_SHA", 0x0096); - // public static final CipherSuite TLS_DH_DSS_WITH_SEED_CBC_SHA = of("TLS_DH_DSS_WITH_SEED_CBC_SHA", 0x0097); - // public static final CipherSuite TLS_DH_RSA_WITH_SEED_CBC_SHA = of("TLS_DH_RSA_WITH_SEED_CBC_SHA", 0x0098); - // public static final CipherSuite TLS_DHE_DSS_WITH_SEED_CBC_SHA = of("TLS_DHE_DSS_WITH_SEED_CBC_SHA", 0x0099); - // public static final CipherSuite TLS_DHE_RSA_WITH_SEED_CBC_SHA = of("TLS_DHE_RSA_WITH_SEED_CBC_SHA", 0x009a); - // public static final CipherSuite TLS_DH_anon_WITH_SEED_CBC_SHA = of("TLS_DH_anon_WITH_SEED_CBC_SHA", 0x009b); - public static final CipherSuite TLS_RSA_WITH_AES_128_GCM_SHA256 = of("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x009c); - public static final CipherSuite TLS_RSA_WITH_AES_256_GCM_SHA384 = of("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x009d); - public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = of("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x009e); - public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = of("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x009f); - // public static final CipherSuite TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = of("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0x00a0); - // public static final CipherSuite TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = of("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0x00a1); - public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = of("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x00a2); - public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = of("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x00a3); - // public static final CipherSuite TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = of("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0x00a4); - // public static final CipherSuite TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = of("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0x00a5); - public static final CipherSuite TLS_DH_anon_WITH_AES_128_GCM_SHA256 = of("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x00a6); - public static final CipherSuite TLS_DH_anon_WITH_AES_256_GCM_SHA384 = of("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x00a7); - // public static final CipherSuite TLS_PSK_WITH_AES_128_GCM_SHA256 = of("TLS_PSK_WITH_AES_128_GCM_SHA256", 0x00a8); - // public static final CipherSuite TLS_PSK_WITH_AES_256_GCM_SHA384 = of("TLS_PSK_WITH_AES_256_GCM_SHA384", 0x00a9); - // public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = of("TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", 0x00aa); - // public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = of("TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", 0x00ab); - // public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 = of("TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", 0x00ac); - // public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 = of("TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", 0x00ad); - // public static final CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA256 = of("TLS_PSK_WITH_AES_128_CBC_SHA256", 0x00ae); - // public static final CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA384 = of("TLS_PSK_WITH_AES_256_CBC_SHA384", 0x00af); - // public static final CipherSuite TLS_PSK_WITH_NULL_SHA256 = of("TLS_PSK_WITH_NULL_SHA256", 0x00b0); - // public static final CipherSuite TLS_PSK_WITH_NULL_SHA384 = of("TLS_PSK_WITH_NULL_SHA384", 0x00b1); - // public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = of("TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", 0x00b2); - // public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = of("TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", 0x00b3); - // public static final CipherSuite TLS_DHE_PSK_WITH_NULL_SHA256 = of("TLS_DHE_PSK_WITH_NULL_SHA256", 0x00b4); - // public static final CipherSuite TLS_DHE_PSK_WITH_NULL_SHA384 = of("TLS_DHE_PSK_WITH_NULL_SHA384", 0x00b5); - // public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = of("TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", 0x00b6); - // public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = of("TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", 0x00b7); - // public static final CipherSuite TLS_RSA_PSK_WITH_NULL_SHA256 = of("TLS_RSA_PSK_WITH_NULL_SHA256", 0x00b8); - // public static final CipherSuite TLS_RSA_PSK_WITH_NULL_SHA384 = of("TLS_RSA_PSK_WITH_NULL_SHA384", 0x00b9); - // public static final CipherSuite TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00ba); - // public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bb); - // public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00bc); - // public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bd); - // public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00be); - // public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", 0x00bf); - // public static final CipherSuite TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 = of("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c0); - // public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 = of("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c1); - // public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 = of("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c2); - // public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = of("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c3); - // public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = of("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c4); - // public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = of("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", 0x00c5); - public static final CipherSuite TLS_EMPTY_RENEGOTIATION_INFO_SCSV = of("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", 0x00ff); - public static final CipherSuite TLS_FALLBACK_SCSV = of("TLS_FALLBACK_SCSV", 0x5600); - public static final CipherSuite TLS_ECDH_ECDSA_WITH_NULL_SHA = of("TLS_ECDH_ECDSA_WITH_NULL_SHA", 0xc001); - public static final CipherSuite TLS_ECDH_ECDSA_WITH_RC4_128_SHA = of("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", 0xc002); - public static final CipherSuite TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = of("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xc003); - public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = of("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", 0xc004); - public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = of("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", 0xc005); - public static final CipherSuite TLS_ECDHE_ECDSA_WITH_NULL_SHA = of("TLS_ECDHE_ECDSA_WITH_NULL_SHA", 0xc006); - public static final CipherSuite TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = of("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 0xc007); - public static final CipherSuite TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = of("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xc008); - public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = of("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", 0xc009); - public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = of("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", 0xc00a); - public static final CipherSuite TLS_ECDH_RSA_WITH_NULL_SHA = of("TLS_ECDH_RSA_WITH_NULL_SHA", 0xc00b); - public static final CipherSuite TLS_ECDH_RSA_WITH_RC4_128_SHA = of("TLS_ECDH_RSA_WITH_RC4_128_SHA", 0xc00c); - public static final CipherSuite TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = of("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", 0xc00d); - public static final CipherSuite TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = of("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", 0xc00e); - public static final CipherSuite TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = of("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", 0xc00f); - public static final CipherSuite TLS_ECDHE_RSA_WITH_NULL_SHA = of("TLS_ECDHE_RSA_WITH_NULL_SHA", 0xc010); - public static final CipherSuite TLS_ECDHE_RSA_WITH_RC4_128_SHA = of("TLS_ECDHE_RSA_WITH_RC4_128_SHA", 0xc011); - public static final CipherSuite TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = of("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", 0xc012); - public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = of("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 0xc013); - public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = of("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 0xc014); - public static final CipherSuite TLS_ECDH_anon_WITH_NULL_SHA = of("TLS_ECDH_anon_WITH_NULL_SHA", 0xc015); - public static final CipherSuite TLS_ECDH_anon_WITH_RC4_128_SHA = of("TLS_ECDH_anon_WITH_RC4_128_SHA", 0xc016); - public static final CipherSuite TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = of("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", 0xc017); - public static final CipherSuite TLS_ECDH_anon_WITH_AES_128_CBC_SHA = of("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", 0xc018); - public static final CipherSuite TLS_ECDH_anon_WITH_AES_256_CBC_SHA = of("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", 0xc019); - // public static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = of("TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", 0xc01a); - // public static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = of("TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", 0xc01b); - // public static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = of("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", 0xc01c); - // public static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA = of("TLS_SRP_SHA_WITH_AES_128_CBC_SHA", 0xc01d); - // public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = of("TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", 0xc01e); - // public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = of("TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", 0xc01f); - // public static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA = of("TLS_SRP_SHA_WITH_AES_256_CBC_SHA", 0xc020); - // public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = of("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xc021); - // public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = of("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xc022); - public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = of("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 0xc023); - public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = of("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", 0xc024); - public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = of("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", 0xc025); - public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = of("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", 0xc026); - public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = of("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", 0xc027); - public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = of("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", 0xc028); - public static final CipherSuite TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = of("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", 0xc029); - public static final CipherSuite TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = of("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", 0xc02a); - public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = of("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02b); - public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = of("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02c); - public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = of("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02d); - public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = of("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02e); - public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = of("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0xc02f); - public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = of("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0xc030); - public static final CipherSuite TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = of("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0xc031); - public static final CipherSuite TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = of("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0xc032); - // public static final CipherSuite TLS_ECDHE_PSK_WITH_RC4_128_SHA = of("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xc033); - // public static final CipherSuite TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = of("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xc034); - public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = of("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", 0xc035); - public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = of("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", 0xc036); - // public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = of("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", 0xc037); - // public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = of("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", 0xc038); - // public static final CipherSuite TLS_ECDHE_PSK_WITH_NULL_SHA = of("TLS_ECDHE_PSK_WITH_NULL_SHA", 0xc039); - // public static final CipherSuite TLS_ECDHE_PSK_WITH_NULL_SHA256 = of("TLS_ECDHE_PSK_WITH_NULL_SHA256", 0xc03a); - // public static final CipherSuite TLS_ECDHE_PSK_WITH_NULL_SHA384 = of("TLS_ECDHE_PSK_WITH_NULL_SHA384", 0xc03b); - // public static final CipherSuite TLS_RSA_WITH_ARIA_128_CBC_SHA256 = of("TLS_RSA_WITH_ARIA_128_CBC_SHA256", 0xc03c); - // public static final CipherSuite TLS_RSA_WITH_ARIA_256_CBC_SHA384 = of("TLS_RSA_WITH_ARIA_256_CBC_SHA384", 0xc03d); - // public static final CipherSuite TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 = of("TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256", 0xc03e); - // public static final CipherSuite TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 = of("TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384", 0xc03f); - // public static final CipherSuite TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 = of("TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256", 0xc040); - // public static final CipherSuite TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 = of("TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384", 0xc041); - // public static final CipherSuite TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 = of("TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", 0xc042); - // public static final CipherSuite TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 = of("TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", 0xc043); - // public static final CipherSuite TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 = of("TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", 0xc044); - // public static final CipherSuite TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 = of("TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", 0xc045); - // public static final CipherSuite TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 = of("TLS_DH_anon_WITH_ARIA_128_CBC_SHA256", 0xc046); - // public static final CipherSuite TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 = of("TLS_DH_anon_WITH_ARIA_256_CBC_SHA384", 0xc047); - // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 = of("TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", 0xc048); - // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 = of("TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", 0xc049); - // public static final CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 = of("TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", 0xc04a); - // public static final CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 = of("TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", 0xc04b); - // public static final CipherSuite TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 = of("TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", 0xc04c); - // public static final CipherSuite TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 = of("TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", 0xc04d); - // public static final CipherSuite TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 = of("TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", 0xc04e); - // public static final CipherSuite TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 = of("TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", 0xc04f); - // public static final CipherSuite TLS_RSA_WITH_ARIA_128_GCM_SHA256 = of("TLS_RSA_WITH_ARIA_128_GCM_SHA256", 0xc050); - // public static final CipherSuite TLS_RSA_WITH_ARIA_256_GCM_SHA384 = of("TLS_RSA_WITH_ARIA_256_GCM_SHA384", 0xc051); - // public static final CipherSuite TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 = of("TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256", 0xc052); - // public static final CipherSuite TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 = of("TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384", 0xc053); - // public static final CipherSuite TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 = of("TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256", 0xc054); - // public static final CipherSuite TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 = of("TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384", 0xc055); - // public static final CipherSuite TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 = of("TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256", 0xc056); - // public static final CipherSuite TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 = of("TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384", 0xc057); - // public static final CipherSuite TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 = of("TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256", 0xc058); - // public static final CipherSuite TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 = of("TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384", 0xc059); - // public static final CipherSuite TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 = of("TLS_DH_anon_WITH_ARIA_128_GCM_SHA256", 0xc05a); - // public static final CipherSuite TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 = of("TLS_DH_anon_WITH_ARIA_256_GCM_SHA384", 0xc05b); - // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 = of("TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", 0xc05c); - // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 = of("TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", 0xc05d); - // public static final CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 = of("TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", 0xc05e); - // public static final CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 = of("TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", 0xc05f); - // public static final CipherSuite TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 = of("TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", 0xc060); - // public static final CipherSuite TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 = of("TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", 0xc061); - // public static final CipherSuite TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 = of("TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", 0xc062); - // public static final CipherSuite TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 = of("TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", 0xc063); - // public static final CipherSuite TLS_PSK_WITH_ARIA_128_CBC_SHA256 = of("TLS_PSK_WITH_ARIA_128_CBC_SHA256", 0xc064); - // public static final CipherSuite TLS_PSK_WITH_ARIA_256_CBC_SHA384 = of("TLS_PSK_WITH_ARIA_256_CBC_SHA384", 0xc065); - // public static final CipherSuite TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 = of("TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", 0xc066); - // public static final CipherSuite TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 = of("TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", 0xc067); - // public static final CipherSuite TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 = of("TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256", 0xc068); - // public static final CipherSuite TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 = of("TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384", 0xc069); - // public static final CipherSuite TLS_PSK_WITH_ARIA_128_GCM_SHA256 = of("TLS_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06a); - // public static final CipherSuite TLS_PSK_WITH_ARIA_256_GCM_SHA384 = of("TLS_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06b); - // public static final CipherSuite TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 = of("TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06c); - // public static final CipherSuite TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 = of("TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06d); - // public static final CipherSuite TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 = of("TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06e); - // public static final CipherSuite TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 = of("TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06f); - // public static final CipherSuite TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 = of("TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", 0xc070); - // public static final CipherSuite TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 = of("TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", 0xc071); - // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc072); - // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = of("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc073); - // public static final CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc074); - // public static final CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = of("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc075); - // public static final CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc076); - // public static final CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 = of("TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc077); - // public static final CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc078); - // public static final CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 = of("TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc079); - // public static final CipherSuite TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07a); - // public static final CipherSuite TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07b); - // public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07c); - // public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07d); - // public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07e); - // public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07f); - // public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", 0xc080); - // public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", 0xc081); - // public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256", 0xc082); - // public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384", 0xc083); - // public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256", 0xc084); - // public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384", 0xc085); - // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc086); - // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc087); - // public static final CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc088); - // public static final CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc089); - // public static final CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc08a); - // public static final CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc08b); - // public static final CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc08c); - // public static final CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc08d); - // public static final CipherSuite TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc08e); - // public static final CipherSuite TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc08f); - // public static final CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc090); - // public static final CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc091); - // public static final CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 = of("TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc092); - // public static final CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 = of("TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc093); - // public static final CipherSuite TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc094); - // public static final CipherSuite TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 = of("TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc095); - // public static final CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc096); - // public static final CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = of("TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc097); - // public static final CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc098); - // public static final CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 = of("TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc099); - // public static final CipherSuite TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = of("TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc09a); - // public static final CipherSuite TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = of("TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc09b); - // public static final CipherSuite TLS_RSA_WITH_AES_128_CCM = of("TLS_RSA_WITH_AES_128_CCM", 0xc09c); - // public static final CipherSuite TLS_RSA_WITH_AES_256_CCM = of("TLS_RSA_WITH_AES_256_CCM", 0xc09d); - // public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CCM = of("TLS_DHE_RSA_WITH_AES_128_CCM", 0xc09e); - // public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CCM = of("TLS_DHE_RSA_WITH_AES_256_CCM", 0xc09f); - // public static final CipherSuite TLS_RSA_WITH_AES_128_CCM_8 = of("TLS_RSA_WITH_AES_128_CCM_8", 0xc0a0); - // public static final CipherSuite TLS_RSA_WITH_AES_256_CCM_8 = of("TLS_RSA_WITH_AES_256_CCM_8", 0xc0a1); - // public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CCM_8 = of("TLS_DHE_RSA_WITH_AES_128_CCM_8", 0xc0a2); - // public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CCM_8 = of("TLS_DHE_RSA_WITH_AES_256_CCM_8", 0xc0a3); - // public static final CipherSuite TLS_PSK_WITH_AES_128_CCM = of("TLS_PSK_WITH_AES_128_CCM", 0xc0a4); - // public static final CipherSuite TLS_PSK_WITH_AES_256_CCM = of("TLS_PSK_WITH_AES_256_CCM", 0xc0a5); - // public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CCM = of("TLS_DHE_PSK_WITH_AES_128_CCM", 0xc0a6); - // public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CCM = of("TLS_DHE_PSK_WITH_AES_256_CCM", 0xc0a7); - // public static final CipherSuite TLS_PSK_WITH_AES_128_CCM_8 = of("TLS_PSK_WITH_AES_128_CCM_8", 0xc0a8); - // public static final CipherSuite TLS_PSK_WITH_AES_256_CCM_8 = of("TLS_PSK_WITH_AES_256_CCM_8", 0xc0a9); - // public static final CipherSuite TLS_PSK_DHE_WITH_AES_128_CCM_8 = of("TLS_PSK_DHE_WITH_AES_128_CCM_8", 0xc0aa); - // public static final CipherSuite TLS_PSK_DHE_WITH_AES_256_CCM_8 = of("TLS_PSK_DHE_WITH_AES_256_CCM_8", 0xc0ab); - // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CCM = of("TLS_ECDHE_ECDSA_WITH_AES_128_CCM", 0xc0ac); - // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CCM = of("TLS_ECDHE_ECDSA_WITH_AES_256_CCM", 0xc0ad); - // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = of("TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", 0xc0ae); - // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 = of("TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", 0xc0af); - public static final CipherSuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = of("TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", 0xcca8); - public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = of("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", 0xcca9); - public static final CipherSuite TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = of("TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", 0xccaa); - // public static final CipherSuite TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = of("TLS_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccab); - public static final CipherSuite TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = of("TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccac); - // public static final CipherSuite TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = of("TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccad); - // public static final CipherSuite TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = of("TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccae); + // public static final CipherSuite TLS_NULL_WITH_NULL_NULL = init("TLS_NULL_WITH_NULL_NULL", 0x0000); + public static final CipherSuite TLS_RSA_WITH_NULL_MD5 = init("SSL_RSA_WITH_NULL_MD5", 0x0001); + public static final CipherSuite TLS_RSA_WITH_NULL_SHA = init("SSL_RSA_WITH_NULL_SHA", 0x0002); + public static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = init("SSL_RSA_EXPORT_WITH_RC4_40_MD5", 0x0003); + public static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 = init("SSL_RSA_WITH_RC4_128_MD5", 0x0004); + public static final CipherSuite TLS_RSA_WITH_RC4_128_SHA = init("SSL_RSA_WITH_RC4_128_SHA", 0x0005); + // public static final CipherSuite TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = init("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5", 0x0006); + // public static final CipherSuite TLS_RSA_WITH_IDEA_CBC_SHA = init("TLS_RSA_WITH_IDEA_CBC_SHA", 0x0007); + public static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = init("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0008); + public static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA = init("SSL_RSA_WITH_DES_CBC_SHA", 0x0009); + public static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = init("SSL_RSA_WITH_3DES_EDE_CBC_SHA", 0x000a); + // public static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = init("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x000b); + // public static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = init("TLS_DH_DSS_WITH_DES_CBC_SHA", 0x000c); + // public static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = init("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", 0x000d); + // public static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = init("SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x000e); + // public static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = init("TLS_DH_RSA_WITH_DES_CBC_SHA", 0x000f); + // public static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = init("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", 0x0010); + public static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = init("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x0011); + public static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = init("SSL_DHE_DSS_WITH_DES_CBC_SHA", 0x0012); + public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = init("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", 0x0013); + public static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = init("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0014); + public static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = init("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0015); + public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = init("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", 0x0016); + public static final CipherSuite TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = init("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", 0x0017); + public static final CipherSuite TLS_DH_anon_WITH_RC4_128_MD5 = init("SSL_DH_anon_WITH_RC4_128_MD5", 0x0018); + public static final CipherSuite TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = init("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", 0x0019); + public static final CipherSuite TLS_DH_anon_WITH_DES_CBC_SHA = init("SSL_DH_anon_WITH_DES_CBC_SHA", 0x001a); + public static final CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = init("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", 0x001b); + public static final CipherSuite TLS_KRB5_WITH_DES_CBC_SHA = init("TLS_KRB5_WITH_DES_CBC_SHA", 0x001e); + public static final CipherSuite TLS_KRB5_WITH_3DES_EDE_CBC_SHA = init("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", 0x001f); + public static final CipherSuite TLS_KRB5_WITH_RC4_128_SHA = init("TLS_KRB5_WITH_RC4_128_SHA", 0x0020); + // public static final CipherSuite TLS_KRB5_WITH_IDEA_CBC_SHA = init("TLS_KRB5_WITH_IDEA_CBC_SHA", 0x0021); + public static final CipherSuite TLS_KRB5_WITH_DES_CBC_MD5 = init("TLS_KRB5_WITH_DES_CBC_MD5", 0x0022); + public static final CipherSuite TLS_KRB5_WITH_3DES_EDE_CBC_MD5 = init("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", 0x0023); + public static final CipherSuite TLS_KRB5_WITH_RC4_128_MD5 = init("TLS_KRB5_WITH_RC4_128_MD5", 0x0024); + // public static final CipherSuite TLS_KRB5_WITH_IDEA_CBC_MD5 = init("TLS_KRB5_WITH_IDEA_CBC_MD5", 0x0025); + public static final CipherSuite TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA = init("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", 0x0026); + // public static final CipherSuite TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA = init("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", 0x0027); + public static final CipherSuite TLS_KRB5_EXPORT_WITH_RC4_40_SHA = init("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", 0x0028); + public static final CipherSuite TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 = init("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", 0x0029); + // public static final CipherSuite TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 = init("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", 0x002a); + public static final CipherSuite TLS_KRB5_EXPORT_WITH_RC4_40_MD5 = init("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", 0x002b); + // public static final CipherSuite TLS_PSK_WITH_NULL_SHA = init("TLS_PSK_WITH_NULL_SHA", 0x002c); + // public static final CipherSuite TLS_DHE_PSK_WITH_NULL_SHA = init("TLS_DHE_PSK_WITH_NULL_SHA", 0x002d); + // public static final CipherSuite TLS_RSA_PSK_WITH_NULL_SHA = init("TLS_RSA_PSK_WITH_NULL_SHA", 0x002e); + public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA = init("TLS_RSA_WITH_AES_128_CBC_SHA", 0x002f); + // public static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA = init("TLS_DH_DSS_WITH_AES_128_CBC_SHA", 0x0030); + // public static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA = init("TLS_DH_RSA_WITH_AES_128_CBC_SHA", 0x0031); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA = init("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 0x0032); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA = init("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 0x0033); + public static final CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA = init("TLS_DH_anon_WITH_AES_128_CBC_SHA", 0x0034); + public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = init("TLS_RSA_WITH_AES_256_CBC_SHA", 0x0035); + // public static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA = init("TLS_DH_DSS_WITH_AES_256_CBC_SHA", 0x0036); + // public static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA = init("TLS_DH_RSA_WITH_AES_256_CBC_SHA", 0x0037); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA = init("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", 0x0038); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA = init("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", 0x0039); + public static final CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA = init("TLS_DH_anon_WITH_AES_256_CBC_SHA", 0x003a); + public static final CipherSuite TLS_RSA_WITH_NULL_SHA256 = init("TLS_RSA_WITH_NULL_SHA256", 0x003b); + public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA256 = init("TLS_RSA_WITH_AES_128_CBC_SHA256", 0x003c); + public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA256 = init("TLS_RSA_WITH_AES_256_CBC_SHA256", 0x003d); + // public static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = init("TLS_DH_DSS_WITH_AES_128_CBC_SHA256", 0x003e); + // public static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = init("TLS_DH_RSA_WITH_AES_128_CBC_SHA256", 0x003f); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = init("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", 0x0040); + public static final CipherSuite TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = init("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0041); + // public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0042); + // public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0043); + public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0044); + public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0045); + // public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", 0x0046); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = init("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", 0x0067); + // public static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = init("TLS_DH_DSS_WITH_AES_256_CBC_SHA256", 0x0068); + // public static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = init("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x0069); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = init("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", 0x006a); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = init("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", 0x006b); + public static final CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA256 = init("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x006c); + public static final CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA256 = init("TLS_DH_anon_WITH_AES_256_CBC_SHA256", 0x006d); + public static final CipherSuite TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = init("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0084); + // public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0085); + // public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0086); + public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0087); + public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0088); + // public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", 0x0089); + public static final CipherSuite TLS_PSK_WITH_RC4_128_SHA = init("TLS_PSK_WITH_RC4_128_SHA", 0x008a); + public static final CipherSuite TLS_PSK_WITH_3DES_EDE_CBC_SHA = init("TLS_PSK_WITH_3DES_EDE_CBC_SHA", 0x008b); + public static final CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA = init("TLS_PSK_WITH_AES_128_CBC_SHA", 0x008c); + public static final CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA = init("TLS_PSK_WITH_AES_256_CBC_SHA", 0x008d); + // public static final CipherSuite TLS_DHE_PSK_WITH_RC4_128_SHA = init("TLS_DHE_PSK_WITH_RC4_128_SHA", 0x008e); + // public static final CipherSuite TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = init("TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", 0x008f); + // public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CBC_SHA = init("TLS_DHE_PSK_WITH_AES_128_CBC_SHA", 0x0090); + // public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CBC_SHA = init("TLS_DHE_PSK_WITH_AES_256_CBC_SHA", 0x0091); + // public static final CipherSuite TLS_RSA_PSK_WITH_RC4_128_SHA = init("TLS_RSA_PSK_WITH_RC4_128_SHA", 0x0092); + // public static final CipherSuite TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = init("TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", 0x0093); + // public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_CBC_SHA = init("TLS_RSA_PSK_WITH_AES_128_CBC_SHA", 0x0094); + // public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_CBC_SHA = init("TLS_RSA_PSK_WITH_AES_256_CBC_SHA", 0x0095); + public static final CipherSuite TLS_RSA_WITH_SEED_CBC_SHA = init("TLS_RSA_WITH_SEED_CBC_SHA", 0x0096); + // public static final CipherSuite TLS_DH_DSS_WITH_SEED_CBC_SHA = init("TLS_DH_DSS_WITH_SEED_CBC_SHA", 0x0097); + // public static final CipherSuite TLS_DH_RSA_WITH_SEED_CBC_SHA = init("TLS_DH_RSA_WITH_SEED_CBC_SHA", 0x0098); + // public static final CipherSuite TLS_DHE_DSS_WITH_SEED_CBC_SHA = init("TLS_DHE_DSS_WITH_SEED_CBC_SHA", 0x0099); + // public static final CipherSuite TLS_DHE_RSA_WITH_SEED_CBC_SHA = init("TLS_DHE_RSA_WITH_SEED_CBC_SHA", 0x009a); + // public static final CipherSuite TLS_DH_anon_WITH_SEED_CBC_SHA = init("TLS_DH_anon_WITH_SEED_CBC_SHA", 0x009b); + public static final CipherSuite TLS_RSA_WITH_AES_128_GCM_SHA256 = init("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x009c); + public static final CipherSuite TLS_RSA_WITH_AES_256_GCM_SHA384 = init("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x009d); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = init("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x009e); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = init("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x009f); + // public static final CipherSuite TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = init("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0x00a0); + // public static final CipherSuite TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = init("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0x00a1); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = init("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x00a2); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = init("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x00a3); + // public static final CipherSuite TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = init("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0x00a4); + // public static final CipherSuite TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = init("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0x00a5); + public static final CipherSuite TLS_DH_anon_WITH_AES_128_GCM_SHA256 = init("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x00a6); + public static final CipherSuite TLS_DH_anon_WITH_AES_256_GCM_SHA384 = init("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x00a7); + // public static final CipherSuite TLS_PSK_WITH_AES_128_GCM_SHA256 = init("TLS_PSK_WITH_AES_128_GCM_SHA256", 0x00a8); + // public static final CipherSuite TLS_PSK_WITH_AES_256_GCM_SHA384 = init("TLS_PSK_WITH_AES_256_GCM_SHA384", 0x00a9); + // public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = init("TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", 0x00aa); + // public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = init("TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", 0x00ab); + // public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 = init("TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", 0x00ac); + // public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 = init("TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", 0x00ad); + // public static final CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA256 = init("TLS_PSK_WITH_AES_128_CBC_SHA256", 0x00ae); + // public static final CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA384 = init("TLS_PSK_WITH_AES_256_CBC_SHA384", 0x00af); + // public static final CipherSuite TLS_PSK_WITH_NULL_SHA256 = init("TLS_PSK_WITH_NULL_SHA256", 0x00b0); + // public static final CipherSuite TLS_PSK_WITH_NULL_SHA384 = init("TLS_PSK_WITH_NULL_SHA384", 0x00b1); + // public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = init("TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", 0x00b2); + // public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = init("TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", 0x00b3); + // public static final CipherSuite TLS_DHE_PSK_WITH_NULL_SHA256 = init("TLS_DHE_PSK_WITH_NULL_SHA256", 0x00b4); + // public static final CipherSuite TLS_DHE_PSK_WITH_NULL_SHA384 = init("TLS_DHE_PSK_WITH_NULL_SHA384", 0x00b5); + // public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = init("TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", 0x00b6); + // public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = init("TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", 0x00b7); + // public static final CipherSuite TLS_RSA_PSK_WITH_NULL_SHA256 = init("TLS_RSA_PSK_WITH_NULL_SHA256", 0x00b8); + // public static final CipherSuite TLS_RSA_PSK_WITH_NULL_SHA384 = init("TLS_RSA_PSK_WITH_NULL_SHA384", 0x00b9); + // public static final CipherSuite TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00ba); + // public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bb); + // public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00bc); + // public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bd); + // public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00be); + // public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", 0x00bf); + // public static final CipherSuite TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c0); + // public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c1); + // public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c2); + // public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c3); + // public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c4); + // public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", 0x00c5); + public static final CipherSuite TLS_EMPTY_RENEGOTIATION_INFO_SCSV = init("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", 0x00ff); + public static final CipherSuite TLS_FALLBACK_SCSV = init("TLS_FALLBACK_SCSV", 0x5600); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_NULL_SHA = init("TLS_ECDH_ECDSA_WITH_NULL_SHA", 0xc001); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_RC4_128_SHA = init("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", 0xc002); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xc003); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = init("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", 0xc004); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = init("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", 0xc005); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_NULL_SHA = init("TLS_ECDHE_ECDSA_WITH_NULL_SHA", 0xc006); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = init("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 0xc007); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xc008); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = init("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", 0xc009); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = init("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", 0xc00a); + public static final CipherSuite TLS_ECDH_RSA_WITH_NULL_SHA = init("TLS_ECDH_RSA_WITH_NULL_SHA", 0xc00b); + public static final CipherSuite TLS_ECDH_RSA_WITH_RC4_128_SHA = init("TLS_ECDH_RSA_WITH_RC4_128_SHA", 0xc00c); + public static final CipherSuite TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", 0xc00d); + public static final CipherSuite TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = init("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", 0xc00e); + public static final CipherSuite TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = init("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", 0xc00f); + public static final CipherSuite TLS_ECDHE_RSA_WITH_NULL_SHA = init("TLS_ECDHE_RSA_WITH_NULL_SHA", 0xc010); + public static final CipherSuite TLS_ECDHE_RSA_WITH_RC4_128_SHA = init("TLS_ECDHE_RSA_WITH_RC4_128_SHA", 0xc011); + public static final CipherSuite TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", 0xc012); + public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = init("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 0xc013); + public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = init("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 0xc014); + public static final CipherSuite TLS_ECDH_anon_WITH_NULL_SHA = init("TLS_ECDH_anon_WITH_NULL_SHA", 0xc015); + public static final CipherSuite TLS_ECDH_anon_WITH_RC4_128_SHA = init("TLS_ECDH_anon_WITH_RC4_128_SHA", 0xc016); + public static final CipherSuite TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", 0xc017); + public static final CipherSuite TLS_ECDH_anon_WITH_AES_128_CBC_SHA = init("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", 0xc018); + public static final CipherSuite TLS_ECDH_anon_WITH_AES_256_CBC_SHA = init("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", 0xc019); + // public static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = init("TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", 0xc01a); + // public static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = init("TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", 0xc01b); + // public static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = init("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", 0xc01c); + // public static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA = init("TLS_SRP_SHA_WITH_AES_128_CBC_SHA", 0xc01d); + // public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = init("TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", 0xc01e); + // public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = init("TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", 0xc01f); + // public static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA = init("TLS_SRP_SHA_WITH_AES_256_CBC_SHA", 0xc020); + // public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = init("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xc021); + // public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = init("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xc022); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = init("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 0xc023); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = init("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", 0xc024); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = init("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", 0xc025); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = init("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", 0xc026); + public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = init("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", 0xc027); + public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = init("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", 0xc028); + public static final CipherSuite TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = init("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", 0xc029); + public static final CipherSuite TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = init("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", 0xc02a); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = init("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02b); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = init("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02c); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = init("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02d); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = init("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02e); + public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = init("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0xc02f); + public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = init("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0xc030); + public static final CipherSuite TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = init("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0xc031); + public static final CipherSuite TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = init("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0xc032); + // public static final CipherSuite TLS_ECDHE_PSK_WITH_RC4_128_SHA = init("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xc033); + // public static final CipherSuite TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xc034); + public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = init("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", 0xc035); + public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = init("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", 0xc036); + // public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = init("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", 0xc037); + // public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = init("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", 0xc038); + // public static final CipherSuite TLS_ECDHE_PSK_WITH_NULL_SHA = init("TLS_ECDHE_PSK_WITH_NULL_SHA", 0xc039); + // public static final CipherSuite TLS_ECDHE_PSK_WITH_NULL_SHA256 = init("TLS_ECDHE_PSK_WITH_NULL_SHA256", 0xc03a); + // public static final CipherSuite TLS_ECDHE_PSK_WITH_NULL_SHA384 = init("TLS_ECDHE_PSK_WITH_NULL_SHA384", 0xc03b); + // public static final CipherSuite TLS_RSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_RSA_WITH_ARIA_128_CBC_SHA256", 0xc03c); + // public static final CipherSuite TLS_RSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_RSA_WITH_ARIA_256_CBC_SHA384", 0xc03d); + // public static final CipherSuite TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 = init("TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256", 0xc03e); + // public static final CipherSuite TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 = init("TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384", 0xc03f); + // public static final CipherSuite TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256", 0xc040); + // public static final CipherSuite TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384", 0xc041); + // public static final CipherSuite TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 = init("TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", 0xc042); + // public static final CipherSuite TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 = init("TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", 0xc043); + // public static final CipherSuite TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", 0xc044); + // public static final CipherSuite TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", 0xc045); + // public static final CipherSuite TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 = init("TLS_DH_anon_WITH_ARIA_128_CBC_SHA256", 0xc046); + // public static final CipherSuite TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 = init("TLS_DH_anon_WITH_ARIA_256_CBC_SHA384", 0xc047); + // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", 0xc048); + // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", 0xc049); + // public static final CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", 0xc04a); + // public static final CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", 0xc04b); + // public static final CipherSuite TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", 0xc04c); + // public static final CipherSuite TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", 0xc04d); + // public static final CipherSuite TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", 0xc04e); + // public static final CipherSuite TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", 0xc04f); + // public static final CipherSuite TLS_RSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_RSA_WITH_ARIA_128_GCM_SHA256", 0xc050); + // public static final CipherSuite TLS_RSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_RSA_WITH_ARIA_256_GCM_SHA384", 0xc051); + // public static final CipherSuite TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256", 0xc052); + // public static final CipherSuite TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384", 0xc053); + // public static final CipherSuite TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256", 0xc054); + // public static final CipherSuite TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384", 0xc055); + // public static final CipherSuite TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 = init("TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256", 0xc056); + // public static final CipherSuite TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 = init("TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384", 0xc057); + // public static final CipherSuite TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 = init("TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256", 0xc058); + // public static final CipherSuite TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 = init("TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384", 0xc059); + // public static final CipherSuite TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 = init("TLS_DH_anon_WITH_ARIA_128_GCM_SHA256", 0xc05a); + // public static final CipherSuite TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 = init("TLS_DH_anon_WITH_ARIA_256_GCM_SHA384", 0xc05b); + // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", 0xc05c); + // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", 0xc05d); + // public static final CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", 0xc05e); + // public static final CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", 0xc05f); + // public static final CipherSuite TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", 0xc060); + // public static final CipherSuite TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", 0xc061); + // public static final CipherSuite TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", 0xc062); + // public static final CipherSuite TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", 0xc063); + // public static final CipherSuite TLS_PSK_WITH_ARIA_128_CBC_SHA256 = init("TLS_PSK_WITH_ARIA_128_CBC_SHA256", 0xc064); + // public static final CipherSuite TLS_PSK_WITH_ARIA_256_CBC_SHA384 = init("TLS_PSK_WITH_ARIA_256_CBC_SHA384", 0xc065); + // public static final CipherSuite TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 = init("TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", 0xc066); + // public static final CipherSuite TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 = init("TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", 0xc067); + // public static final CipherSuite TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 = init("TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256", 0xc068); + // public static final CipherSuite TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 = init("TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384", 0xc069); + // public static final CipherSuite TLS_PSK_WITH_ARIA_128_GCM_SHA256 = init("TLS_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06a); + // public static final CipherSuite TLS_PSK_WITH_ARIA_256_GCM_SHA384 = init("TLS_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06b); + // public static final CipherSuite TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 = init("TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06c); + // public static final CipherSuite TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 = init("TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06d); + // public static final CipherSuite TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 = init("TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06e); + // public static final CipherSuite TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 = init("TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06f); + // public static final CipherSuite TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 = init("TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", 0xc070); + // public static final CipherSuite TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 = init("TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", 0xc071); + // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc072); + // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc073); + // public static final CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc074); + // public static final CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc075); + // public static final CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc076); + // public static final CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc077); + // public static final CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc078); + // public static final CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc079); + // public static final CipherSuite TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07a); + // public static final CipherSuite TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07b); + // public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07c); + // public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07d); + // public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07e); + // public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07f); + // public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", 0xc080); + // public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", 0xc081); + // public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256", 0xc082); + // public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384", 0xc083); + // public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256", 0xc084); + // public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384", 0xc085); + // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc086); + // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc087); + // public static final CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc088); + // public static final CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc089); + // public static final CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc08a); + // public static final CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc08b); + // public static final CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc08c); + // public static final CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc08d); + // public static final CipherSuite TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc08e); + // public static final CipherSuite TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc08f); + // public static final CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc090); + // public static final CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc091); + // public static final CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc092); + // public static final CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc093); + // public static final CipherSuite TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc094); + // public static final CipherSuite TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc095); + // public static final CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc096); + // public static final CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc097); + // public static final CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc098); + // public static final CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc099); + // public static final CipherSuite TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc09a); + // public static final CipherSuite TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc09b); + // public static final CipherSuite TLS_RSA_WITH_AES_128_CCM = init("TLS_RSA_WITH_AES_128_CCM", 0xc09c); + // public static final CipherSuite TLS_RSA_WITH_AES_256_CCM = init("TLS_RSA_WITH_AES_256_CCM", 0xc09d); + // public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CCM = init("TLS_DHE_RSA_WITH_AES_128_CCM", 0xc09e); + // public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CCM = init("TLS_DHE_RSA_WITH_AES_256_CCM", 0xc09f); + // public static final CipherSuite TLS_RSA_WITH_AES_128_CCM_8 = init("TLS_RSA_WITH_AES_128_CCM_8", 0xc0a0); + // public static final CipherSuite TLS_RSA_WITH_AES_256_CCM_8 = init("TLS_RSA_WITH_AES_256_CCM_8", 0xc0a1); + // public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CCM_8 = init("TLS_DHE_RSA_WITH_AES_128_CCM_8", 0xc0a2); + // public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CCM_8 = init("TLS_DHE_RSA_WITH_AES_256_CCM_8", 0xc0a3); + // public static final CipherSuite TLS_PSK_WITH_AES_128_CCM = init("TLS_PSK_WITH_AES_128_CCM", 0xc0a4); + // public static final CipherSuite TLS_PSK_WITH_AES_256_CCM = init("TLS_PSK_WITH_AES_256_CCM", 0xc0a5); + // public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CCM = init("TLS_DHE_PSK_WITH_AES_128_CCM", 0xc0a6); + // public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CCM = init("TLS_DHE_PSK_WITH_AES_256_CCM", 0xc0a7); + // public static final CipherSuite TLS_PSK_WITH_AES_128_CCM_8 = init("TLS_PSK_WITH_AES_128_CCM_8", 0xc0a8); + // public static final CipherSuite TLS_PSK_WITH_AES_256_CCM_8 = init("TLS_PSK_WITH_AES_256_CCM_8", 0xc0a9); + // public static final CipherSuite TLS_PSK_DHE_WITH_AES_128_CCM_8 = init("TLS_PSK_DHE_WITH_AES_128_CCM_8", 0xc0aa); + // public static final CipherSuite TLS_PSK_DHE_WITH_AES_256_CCM_8 = init("TLS_PSK_DHE_WITH_AES_256_CCM_8", 0xc0ab); + // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CCM = init("TLS_ECDHE_ECDSA_WITH_AES_128_CCM", 0xc0ac); + // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CCM = init("TLS_ECDHE_ECDSA_WITH_AES_256_CCM", 0xc0ad); + // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = init("TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", 0xc0ae); + // public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 = init("TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", 0xc0af); + public static final CipherSuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", 0xcca8); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", 0xcca9); + public static final CipherSuite TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", 0xccaa); + // public static final CipherSuite TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccab); + public static final CipherSuite TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccac); + // public static final CipherSuite TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccad); + // public static final CipherSuite TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccae); // TLS 1.3 https://tools.ietf.org/html/rfc8446 - public static final CipherSuite TLS_AES_128_GCM_SHA256 = of("TLS_AES_128_GCM_SHA256", 0x1301); - public static final CipherSuite TLS_AES_256_GCM_SHA384 = of("TLS_AES_256_GCM_SHA384", 0x1302); - public static final CipherSuite TLS_CHACHA20_POLY1305_SHA256 = of("TLS_CHACHA20_POLY1305_SHA256", 0x1303); - public static final CipherSuite TLS_AES_128_CCM_SHA256 = of("TLS_AES_128_CCM_SHA256", 0x1304); - public static final CipherSuite TLS_AES_256_CCM_8_SHA256 = of("TLS_AES_256_CCM_8_SHA256", 0x1305); + public static final CipherSuite TLS_AES_128_GCM_SHA256 = init("TLS_AES_128_GCM_SHA256", 0x1301); + public static final CipherSuite TLS_AES_256_GCM_SHA384 = init("TLS_AES_256_GCM_SHA384", 0x1302); + public static final CipherSuite TLS_CHACHA20_POLY1305_SHA256 = init("TLS_CHACHA20_POLY1305_SHA256", 0x1303); + public static final CipherSuite TLS_AES_128_CCM_SHA256 = init("TLS_AES_128_CCM_SHA256", 0x1304); + public static final CipherSuite TLS_AES_256_CCM_8_SHA256 = init("TLS_AES_256_CCM_8_SHA256", 0x1305); final String javaName; @@ -411,12 +411,28 @@ public final class CipherSuite { public static synchronized CipherSuite forJavaName(String javaName) { CipherSuite result = INSTANCES.get(javaName); if (result == null) { - result = new CipherSuite(javaName); + result = INSTANCES.get(secondaryName(javaName)); + + if (result == null) { + result = new CipherSuite(javaName); + } + + // Add the new cipher suite, or a confirmed alias. INSTANCES.put(javaName, result); } return result; } + private static String secondaryName(String javaName) { + if (javaName.startsWith("TLS_")) { + return "SSL_" + javaName.substring(4); + } else if (javaName.startsWith("SSL_")) { + return "TLS_" + javaName.substring(4); + } else { + return javaName; + } + } + static List forJavaNames(String... cipherSuites) { List result = new ArrayList<>(cipherSuites.length); for (String cipherSuite : cipherSuites) { @@ -437,8 +453,10 @@ private CipherSuite(String javaName) { * 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.) */ - private static CipherSuite of(String javaName, int value) { - return forJavaName(javaName); + private static CipherSuite init(String javaName, int value) { + CipherSuite suite = new CipherSuite(javaName); + INSTANCES.put(javaName, suite); + return suite; } /** From 2b0a9f4909e841f174791501108f17b28230f640 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 3 Nov 2018 13:39:20 +0000 Subject: [PATCH 06/20] Remove colon when scheme missing in builder toString (#4361) --- okhttp-tests/src/test/java/okhttp3/HttpUrlTest.java | 4 ++-- okhttp/src/main/java/okhttp3/HttpUrl.java | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/okhttp-tests/src/test/java/okhttp3/HttpUrlTest.java b/okhttp-tests/src/test/java/okhttp3/HttpUrlTest.java index 6589d5850c9d..e780d8bd9b9d 100644 --- a/okhttp-tests/src/test/java/okhttp3/HttpUrlTest.java +++ b/okhttp-tests/src/test/java/okhttp3/HttpUrlTest.java @@ -779,9 +779,9 @@ HttpUrl parse(String url) { @Test public void incompleteBuilderToString() { assertEquals("https:///path", new HttpUrl.Builder().scheme("https").encodedPath("/path").toString()); - assertEquals("://host.com/path", + assertEquals("//host.com/path", new HttpUrl.Builder().host("host.com").encodedPath("/path").toString()); - assertEquals("://host.com:8080/path", + assertEquals("//host.com:8080/path", new HttpUrl.Builder().host("host.com").encodedPath("/path").port(8080).toString()); } diff --git a/okhttp/src/main/java/okhttp3/HttpUrl.java b/okhttp/src/main/java/okhttp3/HttpUrl.java index 528d1cc46a58..9ca007cefd37 100644 --- a/okhttp/src/main/java/okhttp3/HttpUrl.java +++ b/okhttp/src/main/java/okhttp3/HttpUrl.java @@ -1260,8 +1260,10 @@ public HttpUrl build() { StringBuilder result = new StringBuilder(); if (scheme != null) { result.append(scheme); + result.append("://"); + } else { + result.append("//"); } - result.append("://"); if (!encodedUsername.isEmpty() || !encodedPassword.isEmpty()) { result.append(encodedUsername); From fbf243b8807aae8e4eabfc91b29abe42334c7004 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Sun, 4 Nov 2018 07:49:39 +1100 Subject: [PATCH 07/20] Make scheme names case-sensitive again. --- .../src/test/java/okhttp3/HeadersTest.java | 20 +++++++++---------- okhttp/src/main/java/okhttp3/Challenge.java | 11 +++++----- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/okhttp-tests/src/test/java/okhttp3/HeadersTest.java b/okhttp-tests/src/test/java/okhttp3/HeadersTest.java index fc134f49e502..494ac90b8563 100644 --- a/okhttp-tests/src/test/java/okhttp3/HeadersTest.java +++ b/okhttp-tests/src/test/java/okhttp3/HeadersTest.java @@ -430,7 +430,7 @@ public final class HeadersTest { .build(); List challenges = HttpHeaders.parseChallenges(headers, "WWW-Authenticate"); assertEquals(1, challenges.size()); - assertEquals("digest", challenges.get(0).scheme()); + assertEquals("Digest", challenges.get(0).scheme()); assertEquals("myrealm", challenges.get(0).realm()); Map expectedAuthParams = new LinkedHashMap<>(); expectedAuthParams.put("realm", "myrealm"); @@ -447,7 +447,7 @@ public final class HeadersTest { .build(); List challenges = HttpHeaders.parseChallenges(headers, "WWW-Authenticate"); assertEquals(1, challenges.size()); - assertEquals("digest", challenges.get(0).scheme()); + assertEquals("Digest", challenges.get(0).scheme()); assertEquals("myrealm", challenges.get(0).realm()); Map expectedAuthParams = new LinkedHashMap<>(); expectedAuthParams.put("realm", "myrealm"); @@ -464,7 +464,7 @@ public final class HeadersTest { .build(); List challenges = HttpHeaders.parseChallenges(headers, "WWW-Authenticate"); assertEquals(1, challenges.size()); - assertEquals("digest", challenges.get(0).scheme()); + assertEquals("Digest", challenges.get(0).scheme()); assertEquals("myrealm", challenges.get(0).realm()); Map expectedAuthParams = new LinkedHashMap<>(); expectedAuthParams.put("realm", "myrealm"); @@ -481,7 +481,7 @@ public final class HeadersTest { .build(); List challenges = HttpHeaders.parseChallenges(headers, "WWW-Authenticate"); assertEquals(1, challenges.size()); - assertEquals("digest", challenges.get(0).scheme()); + assertEquals("Digest", challenges.get(0).scheme()); assertNull(challenges.get(0).realm()); Map expectedAuthParams = new LinkedHashMap<>(); expectedAuthParams.put("underrealm", "myrealm"); @@ -498,7 +498,7 @@ public final class HeadersTest { .build(); List challenges = HttpHeaders.parseChallenges(headers, "WWW-Authenticate"); assertEquals(1, challenges.size()); - assertEquals("digest", challenges.get(0).scheme()); + assertEquals("Digest", challenges.get(0).scheme()); assertEquals("myrealm", challenges.get(0).realm()); Map expectedAuthParams = new LinkedHashMap<>(); expectedAuthParams.put("realm", "myrealm"); @@ -515,7 +515,7 @@ public final class HeadersTest { .build(); List challenges = HttpHeaders.parseChallenges(headers, "WWW-Authenticate"); assertEquals(1, challenges.size()); - assertEquals("digest", challenges.get(0).scheme()); + assertEquals("Digest", challenges.get(0).scheme()); assertEquals("myrealm", challenges.get(0).realm()); Map expectedAuthParams = new LinkedHashMap<>(); expectedAuthParams.put("realm", "myrealm"); @@ -532,7 +532,7 @@ public final class HeadersTest { .build(); List challenges = HttpHeaders.parseChallenges(headers, "WWW-Authenticate"); assertEquals(1, challenges.size()); - assertEquals("digest", challenges.get(0).scheme()); + assertEquals("DiGeSt", challenges.get(0).scheme()); assertEquals("myrealm", challenges.get(0).realm()); Map expectedAuthParams = new LinkedHashMap<>(); expectedAuthParams.put("realm", "myrealm"); @@ -550,7 +550,7 @@ public final class HeadersTest { .build(); List challenges = HttpHeaders.parseChallenges(headers, "WWW-Authenticate"); assertEquals(1, challenges.size()); - assertEquals("digest", challenges.get(0).scheme()); + assertEquals("DIgEsT", challenges.get(0).scheme()); assertEquals("myrealm", challenges.get(0).realm()); Map expectedAuthParams = new LinkedHashMap<>(); expectedAuthParams.put("realm", "myrealm"); @@ -565,7 +565,7 @@ public final class HeadersTest { .add("WWW-Authenticate", "Digest realm=myrealm").build(); List challenges = HttpHeaders.parseChallenges(headers, "WWW-Authenticate"); assertEquals(1, challenges.size()); - assertEquals("digest", challenges.get(0).scheme()); + assertEquals("Digest", challenges.get(0).scheme()); assertEquals("myrealm", challenges.get(0).realm()); assertEquals(singletonMap("realm", "myrealm"), challenges.get(0).authParams()); } @@ -576,7 +576,7 @@ public final class HeadersTest { .add("WWW-Authenticate", "Digest").build(); List challenges = HttpHeaders.parseChallenges(headers, "WWW-Authenticate"); assertEquals(1, challenges.size()); - assertEquals("digest", challenges.get(0).scheme()); + assertEquals("Digest", challenges.get(0).scheme()); assertNull(challenges.get(0).realm()); assertEquals(emptyMap(), challenges.get(0).authParams()); } diff --git a/okhttp/src/main/java/okhttp3/Challenge.java b/okhttp/src/main/java/okhttp3/Challenge.java index 5acaa907deda..bff1cb830e32 100644 --- a/okhttp/src/main/java/okhttp3/Challenge.java +++ b/okhttp/src/main/java/okhttp3/Challenge.java @@ -34,7 +34,7 @@ public final class Challenge { public Challenge(String scheme, Map authParams) { if (scheme == null) throw new NullPointerException("scheme == null"); if (authParams == null) throw new NullPointerException("authParams == null"); - this.scheme = scheme.toLowerCase(US); + this.scheme = scheme; Map newAuthParams = new LinkedHashMap<>(); for (Entry authParam : authParams.entrySet()) { String key = (authParam.getKey() == null) ? null : authParam.getKey().toLowerCase(US); @@ -46,7 +46,7 @@ public Challenge(String scheme, Map authParams) { public Challenge(String scheme, String realm) { if (scheme == null) throw new NullPointerException("scheme == null"); if (realm == null) throw new NullPointerException("realm == null"); - this.scheme = scheme.toLowerCase(US); + this.scheme = scheme; this.authParams = singletonMap("realm", realm); } @@ -58,15 +58,14 @@ public Challenge withCharset(Charset charset) { return new Challenge(scheme, authParams); } - /** Returns the authentication scheme in lowercase, like {@code basic}. */ + /** Returns the authentication scheme, like {@code Basic}. */ public String scheme() { return scheme; } /** - * Returns the auth params, including {@code realm} and {@code charset} if present, - * but as {@code String}s. The keys are all lowercase, as the auth param names - * are to be treated case insensitively anyway. + * Returns the auth params, including {@code realm} and {@code charset} if present, but as + * strings. The map's keys are lowercase and should be treated case-insensitively. */ public Map authParams() { return authParams; From 5373160d20aa3f6036ff5ebc91137888c4abffbe Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Sun, 4 Nov 2018 08:53:55 +1100 Subject: [PATCH 08/20] Whole operation timeouts Strictly-speaking this change is backwards-incompatible because it adds a new method to the Call interface. The method returns the call's timeout. The trickiest part of this is signaling the end of the call, which occurs after the last byte is consumed of the last follow up request, or when the call fails. Fortunately this is made easier by borrowing the sites used by EventListener, which already plots out where calls end. https://github.com/square/okhttp/issues/2840 --- .../okhttp3/WholeOperationTimeoutTest.java | 274 ++++++++++++++++++ okhttp/src/main/java/okhttp3/Call.java | 7 + .../src/main/java/okhttp3/OkHttpClient.java | 7 +- okhttp/src/main/java/okhttp3/RealCall.java | 27 ++ .../main/java/okhttp3/internal/Internal.java | 4 + .../internal/connection/StreamAllocation.java | 3 + 6 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 okhttp-tests/src/test/java/okhttp3/WholeOperationTimeoutTest.java diff --git a/okhttp-tests/src/test/java/okhttp3/WholeOperationTimeoutTest.java b/okhttp-tests/src/test/java/okhttp3/WholeOperationTimeoutTest.java new file mode 100644 index 000000000000..591a756c0b3a --- /dev/null +++ b/okhttp-tests/src/test/java/okhttp3/WholeOperationTimeoutTest.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2018 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. + */ +package okhttp3; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.HttpURLConnection; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okio.BufferedSink; +import org.junit.Rule; +import org.junit.Test; + +import static okhttp3.TestUtil.defaultClient; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public final class WholeOperationTimeoutTest { + /** A large response body. Smaller bodies might successfully read after the socket is closed! */ + private static final String BIG_ENOUGH_BODY = TestUtil.repeat('a', 64 * 1024); + + @Rule public final MockWebServer server = new MockWebServer(); + + private OkHttpClient client = defaultClient(); + + @Test public void timeoutWritingRequest() throws Exception { + server.enqueue(new MockResponse()); + + Request request = new Request.Builder() + .url(server.url("/")) + .post(sleepingRequestBody(500)) + .build(); + + Call call = client.newCall(request); + call.timeout().timeout(250, TimeUnit.MILLISECONDS); + try { + call.execute(); + fail(); + } catch (IOException e) { + assertTrue(call.isCanceled()); + } + } + + @Test public void timeoutWritingRequestWithEnqueue() throws Exception { + server.enqueue(new MockResponse()); + + Request request = new Request.Builder() + .url(server.url("/")) + .post(sleepingRequestBody(500)) + .build(); + + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference exceptionRef = new AtomicReference<>(); + + Call call = client.newCall(request); + call.timeout().timeout(250, TimeUnit.MILLISECONDS); + call.enqueue(new Callback() { + @Override public void onFailure(Call call, IOException e) { + exceptionRef.set(e); + latch.countDown(); + } + + @Override public void onResponse(Call call, Response response) throws IOException { + response.close(); + latch.countDown(); + } + }); + + latch.await(); + assertTrue(call.isCanceled()); + assertNotNull(exceptionRef.get()); + } + + @Test public void timeoutProcessing() throws Exception { + server.enqueue(new MockResponse() + .setHeadersDelay(500, TimeUnit.MILLISECONDS)); + + Request request = new Request.Builder() + .url(server.url("/")) + .build(); + + Call call = client.newCall(request); + call.timeout().timeout(250, TimeUnit.MILLISECONDS); + try { + call.execute(); + fail(); + } catch (IOException e) { + assertTrue(call.isCanceled()); + } + } + + @Test public void timeoutProcessingWithEnqueue() throws Exception { + server.enqueue(new MockResponse() + .setHeadersDelay(500, TimeUnit.MILLISECONDS)); + + Request request = new Request.Builder() + .url(server.url("/")) + .build(); + + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference exceptionRef = new AtomicReference<>(); + + Call call = client.newCall(request); + call.timeout().timeout(250, TimeUnit.MILLISECONDS); + call.enqueue(new Callback() { + @Override public void onFailure(Call call, IOException e) { + exceptionRef.set(e); + latch.countDown(); + } + + @Override public void onResponse(Call call, Response response) throws IOException { + response.close(); + latch.countDown(); + } + }); + + latch.await(); + assertTrue(call.isCanceled()); + assertNotNull(exceptionRef.get()); + } + + @Test public void timeoutReadingResponse() throws Exception { + server.enqueue(new MockResponse() + .setBody(BIG_ENOUGH_BODY)); + + Request request = new Request.Builder() + .url(server.url("/")) + .build(); + + Call call = client.newCall(request); + call.timeout().timeout(250, TimeUnit.MILLISECONDS); + Response response = call.execute(); + Thread.sleep(500); + try { + response.body().source().readUtf8(); + fail(); + } catch (IOException e) { + assertTrue(call.isCanceled()); + } + } + + @Test public void timeoutReadingResponseWithEnqueue() throws Exception { + server.enqueue(new MockResponse() + .setBody(BIG_ENOUGH_BODY)); + + Request request = new Request.Builder() + .url(server.url("/")) + .build(); + + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference exceptionRef = new AtomicReference<>(); + + Call call = client.newCall(request); + call.timeout().timeout(250, TimeUnit.MILLISECONDS); + call.enqueue(new Callback() { + @Override public void onFailure(Call call, IOException e) { + latch.countDown(); + } + + @Override public void onResponse(Call call, Response response) throws IOException { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + throw new AssertionError(); + } + try { + response.body().source().readUtf8(); + fail(); + } catch (IOException e) { + exceptionRef.set(e); + } finally { + latch.countDown(); + } + } + }); + + latch.await(); + assertTrue(call.isCanceled()); + assertNotNull(exceptionRef.get()); + } + + @Test public void singleTimeoutForAllFollowUpRequests() throws Exception { + server.enqueue(new MockResponse() + .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) + .setHeader("Location", "/b") + .setHeadersDelay(100, TimeUnit.MILLISECONDS)); + server.enqueue(new MockResponse() + .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) + .setHeader("Location", "/c") + .setHeadersDelay(100, TimeUnit.MILLISECONDS)); + server.enqueue(new MockResponse() + .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) + .setHeader("Location", "/d") + .setHeadersDelay(100, TimeUnit.MILLISECONDS)); + server.enqueue(new MockResponse() + .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) + .setHeader("Location", "/e") + .setHeadersDelay(100, TimeUnit.MILLISECONDS)); + server.enqueue(new MockResponse() + .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) + .setHeader("Location", "/f") + .setHeadersDelay(100, TimeUnit.MILLISECONDS)); + server.enqueue(new MockResponse()); + + Request request = new Request.Builder() + .url(server.url("/a")) + .build(); + + Call call = client.newCall(request); + call.timeout().timeout(250, TimeUnit.MILLISECONDS); + try { + call.execute(); + fail(); + } catch (IOException e) { + assertTrue(call.isCanceled()); + } + } + + @Test public void noTimeout() throws Exception { + server.enqueue(new MockResponse() + .setHeadersDelay(250, TimeUnit.MILLISECONDS) + .setBody(BIG_ENOUGH_BODY)); + + Request request = new Request.Builder() + .url(server.url("/")) + .post(sleepingRequestBody(250)) + .build(); + + Call call = client.newCall(request); + call.timeout().timeout(1000, TimeUnit.MILLISECONDS); + Response response = call.execute(); + Thread.sleep(250); + response.body().source().readUtf8(); + response.close(); + assertFalse(call.isCanceled()); + } + + private RequestBody sleepingRequestBody(final int sleepMillis) { + return new RequestBody() { + @Override public MediaType contentType() { + return MediaType.parse("text/plain"); + } + + @Override public void writeTo(BufferedSink sink) throws IOException { + try { + sink.writeUtf8("abc"); + sink.flush(); + Thread.sleep(sleepMillis); + sink.writeUtf8("def"); + } catch (InterruptedException e) { + throw new InterruptedIOException(); + } + } + }; + } +} diff --git a/okhttp/src/main/java/okhttp3/Call.java b/okhttp/src/main/java/okhttp3/Call.java index cb9ac837f715..2a0a548f7a69 100644 --- a/okhttp/src/main/java/okhttp3/Call.java +++ b/okhttp/src/main/java/okhttp3/Call.java @@ -16,6 +16,7 @@ package okhttp3; import java.io.IOException; +import okio.Timeout; /** * A call is a request that has been prepared for execution. A call can be canceled. As this object @@ -80,6 +81,12 @@ public interface Call extends Cloneable { boolean isCanceled(); + /** + * Returns a timeout that applies to the entire call: writing the request, server processing, + * and reading the response. + */ + Timeout timeout(); + /** * Create a new, identical call to this one which can be enqueued or executed even if this call * has already been. diff --git a/okhttp/src/main/java/okhttp3/OkHttpClient.java b/okhttp/src/main/java/okhttp3/OkHttpClient.java index 9272828aa136..7b44bbac97c4 100644 --- a/okhttp/src/main/java/okhttp3/OkHttpClient.java +++ b/okhttp/src/main/java/okhttp3/OkHttpClient.java @@ -15,6 +15,7 @@ */ package okhttp3; +import java.io.IOException; import java.net.Proxy; import java.net.ProxySelector; import java.net.Socket; @@ -37,11 +38,11 @@ import okhttp3.internal.Internal; import okhttp3.internal.Util; import okhttp3.internal.cache.InternalCache; -import okhttp3.internal.proxy.NullProxySelector; import okhttp3.internal.connection.RealConnection; import okhttp3.internal.connection.RouteDatabase; import okhttp3.internal.connection.StreamAllocation; import okhttp3.internal.platform.Platform; +import okhttp3.internal.proxy.NullProxySelector; import okhttp3.internal.tls.CertificateChainCleaner; import okhttp3.internal.tls.OkHostnameVerifier; import okhttp3.internal.ws.RealWebSocket; @@ -187,6 +188,10 @@ public void apply(ConnectionSpec tlsConfiguration, SSLSocket sslSocket, boolean return ((RealCall) call).streamAllocation(); } + @Override public @Nullable IOException timeoutExit(Call call, @Nullable IOException e) { + return ((RealCall) call).timeoutExit(e); + } + @Override public Call newWebSocketCall(OkHttpClient client, Request originalRequest) { return RealCall.newRealCall(client, originalRequest, true); } diff --git a/okhttp/src/main/java/okhttp3/RealCall.java b/okhttp/src/main/java/okhttp3/RealCall.java index 9bd403a7295d..659b4b9e5cca 100644 --- a/okhttp/src/main/java/okhttp3/RealCall.java +++ b/okhttp/src/main/java/okhttp3/RealCall.java @@ -16,6 +16,7 @@ package okhttp3; import java.io.IOException; +import java.io.InterruptedIOException; import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; @@ -28,12 +29,15 @@ import okhttp3.internal.http.RealInterceptorChain; import okhttp3.internal.http.RetryAndFollowUpInterceptor; import okhttp3.internal.platform.Platform; +import okio.AsyncTimeout; +import okio.Timeout; import static okhttp3.internal.platform.Platform.INFO; final class RealCall implements Call { final OkHttpClient client; final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor; + final AsyncTimeout timeout; /** * There is a cycle between the {@link Call} and {@link EventListener} that makes this awkward. @@ -53,6 +57,11 @@ private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSoc this.originalRequest = originalRequest; this.forWebSocket = forWebSocket; this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); + this.timeout = new AsyncTimeout() { + @Override protected void timedOut() { + cancel(); + } + }; } static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { @@ -72,6 +81,7 @@ static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolea executed = true; } captureCallStackTrace(); + timeout.enter(); eventListener.callStart(this); try { client.dispatcher().executed(this); @@ -79,6 +89,7 @@ static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolea if (result == null) throw new IOException("Canceled"); return result; } catch (IOException e) { + e = timeoutExit(e); eventListener.callFailed(this, e); throw e; } finally { @@ -86,6 +97,16 @@ static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolea } } + @Nullable IOException timeoutExit(@Nullable IOException cause) { + if (!timeout.exit()) return cause; + + InterruptedIOException e = new InterruptedIOException("timeout"); + if (cause != null) { + e.initCause(cause); + } + return e; + } + private void captureCallStackTrace() { Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()"); retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace); @@ -105,6 +126,10 @@ private void captureCallStackTrace() { retryAndFollowUpInterceptor.cancel(); } + @Override public Timeout timeout() { + return timeout; + } + @Override public synchronized boolean isExecuted() { return executed; } @@ -144,6 +169,7 @@ RealCall get() { @Override protected void execute() { boolean signalledCallback = false; + timeout.enter(); try { Response response = getResponseWithInterceptorChain(); if (retryAndFollowUpInterceptor.isCanceled()) { @@ -154,6 +180,7 @@ RealCall get() { responseCallback.onResponse(RealCall.this, response); } } catch (IOException e) { + e = timeoutExit(e); if (signalledCallback) { // Do not signal the callback twice! Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e); diff --git a/okhttp/src/main/java/okhttp3/internal/Internal.java b/okhttp/src/main/java/okhttp3/internal/Internal.java index 4bb228275642..62fcfaa73274 100644 --- a/okhttp/src/main/java/okhttp3/internal/Internal.java +++ b/okhttp/src/main/java/okhttp3/internal/Internal.java @@ -15,7 +15,9 @@ */ package okhttp3.internal; +import java.io.IOException; import java.net.Socket; +import javax.annotation.Nullable; import javax.net.ssl.SSLSocket; import okhttp3.Address; import okhttp3.Call; @@ -73,5 +75,7 @@ public abstract void apply(ConnectionSpec tlsConfiguration, SSLSocket sslSocket, public abstract StreamAllocation streamAllocation(Call call); + public abstract @Nullable IOException timeoutExit(Call call, @Nullable IOException e); + public abstract Call newWebSocketCall(OkHttpClient client, Request request); } diff --git a/okhttp/src/main/java/okhttp3/internal/connection/StreamAllocation.java b/okhttp/src/main/java/okhttp3/internal/connection/StreamAllocation.java index 243a1e82f149..dcad3d80dbaf 100644 --- a/okhttp/src/main/java/okhttp3/internal/connection/StreamAllocation.java +++ b/okhttp/src/main/java/okhttp3/internal/connection/StreamAllocation.java @@ -317,8 +317,10 @@ public void streamFinished(boolean noNewStreams, HttpCodec codec, long bytesRead } if (e != null) { + e = Internal.instance.timeoutExit(call, e); eventListener.callFailed(call, e); } else if (callEnd) { + Internal.instance.timeoutExit(call, null); eventListener.callEnd(call); } } @@ -351,6 +353,7 @@ public void release() { } closeQuietly(socket); if (releasedConnection != null) { + Internal.instance.timeoutExit(call, null); eventListener.connectionReleased(call, releasedConnection); eventListener.callEnd(call); } From 0a8f4186440d7635eb19fdf7e685126fd0b00486 Mon Sep 17 00:00:00 2001 From: jjshanks Date: Sun, 4 Nov 2018 10:05:01 -0800 Subject: [PATCH 09/20] Add basic auth interceptor recipe (#4336) --- .../java/okhttp3/recipes/PreemptiveAuth.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 samples/guide/src/main/java/okhttp3/recipes/PreemptiveAuth.java diff --git a/samples/guide/src/main/java/okhttp3/recipes/PreemptiveAuth.java b/samples/guide/src/main/java/okhttp3/recipes/PreemptiveAuth.java new file mode 100644 index 000000000000..8b1407ac1f38 --- /dev/null +++ b/samples/guide/src/main/java/okhttp3/recipes/PreemptiveAuth.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2018 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. + */ +package okhttp3.recipes; + +import okhttp3.Credentials; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; + +public class PreemptiveAuth { + private final OkHttpClient client; + + public PreemptiveAuth() { + client = new OkHttpClient.Builder() + .addInterceptor( + new BasicAuthInterceptor("publicobject.com", "jesse", "password1")) + .build(); + } + + public void run() throws Exception { + Request request = new Request.Builder() + .url("https://publicobject.com/secrets/hellosecret.txt") + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + System.out.println(response.body().string()); + } + } + + public static void main(String... args) throws Exception { + new PreemptiveAuth().run(); + } + + class BasicAuthInterceptor implements Interceptor { + private final String credentials; + private final String host; + + BasicAuthInterceptor(String host, String username, String password) { + this.credentials = Credentials.basic(username, password); + this.host = host; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + if (request.url().host().equals(host)) { + request = request.newBuilder() + .header("Authorization", credentials) + .build(); + } + return chain.proceed(request); + } + } + +} From bcbbfc6a541a58960c85a765dd4bd5d3c6272c5c Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Mon, 5 Nov 2018 18:46:46 +1100 Subject: [PATCH 10/20] Make the nested BasicAuthInterceptor static (#4368) --- .../src/main/java/okhttp3/recipes/PreemptiveAuth.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/samples/guide/src/main/java/okhttp3/recipes/PreemptiveAuth.java b/samples/guide/src/main/java/okhttp3/recipes/PreemptiveAuth.java index 8b1407ac1f38..abbf0eb0c031 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/PreemptiveAuth.java +++ b/samples/guide/src/main/java/okhttp3/recipes/PreemptiveAuth.java @@ -15,15 +15,14 @@ */ package okhttp3.recipes; +import java.io.IOException; import okhttp3.Credentials; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; -import java.io.IOException; - -public class PreemptiveAuth { +public final class PreemptiveAuth { private final OkHttpClient client; public PreemptiveAuth() { @@ -49,7 +48,7 @@ public static void main(String... args) throws Exception { new PreemptiveAuth().run(); } - class BasicAuthInterceptor implements Interceptor { + static final class BasicAuthInterceptor implements Interceptor { private final String credentials; private final String host; @@ -58,8 +57,7 @@ class BasicAuthInterceptor implements Interceptor { this.host = host; } - @Override - public Response intercept(Chain chain) throws IOException { + @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (request.url().host().equals(host)) { request = request.newBuilder() @@ -69,5 +67,4 @@ public Response intercept(Chain chain) throws IOException { return chain.proceed(request); } } - } From 9f9903e7a36a6b2d7944dc12bac4344b68643d8f Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Mon, 5 Nov 2018 18:49:01 +1100 Subject: [PATCH 11/20] Recover from executor shutdowns gracefully. (#4365) This turns out to be pretty difficult because of the way our dispatcher works. Calls can be rejected either immediately when the user calls enqueue(), or later when a queued call is promoted. It's also awkward because we don't want to hold locks when calling the user's callFailed() method. --- .../src/test/java/okhttp3/DispatcherTest.java | 57 ++++++++++++++- okhttp/src/main/java/okhttp3/Dispatcher.java | 72 ++++++++++++------- okhttp/src/main/java/okhttp3/RealCall.java | 24 +++++++ 3 files changed, 125 insertions(+), 28 deletions(-) diff --git a/okhttp-tests/src/test/java/okhttp3/DispatcherTest.java b/okhttp-tests/src/test/java/okhttp3/DispatcherTest.java index cba980294c7d..80cdb78cfdb2 100644 --- a/okhttp-tests/src/test/java/okhttp3/DispatcherTest.java +++ b/okhttp-tests/src/test/java/okhttp3/DispatcherTest.java @@ -1,6 +1,7 @@ package okhttp3; import java.io.IOException; +import java.io.InterruptedIOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -10,6 +11,7 @@ import java.util.Set; import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import okhttp3.RealCall.AsyncCall; @@ -28,13 +30,16 @@ public final class DispatcherTest { RecordingCallback callback = new RecordingCallback(); RecordingWebSocketListener webSocketListener = new RecordingWebSocketListener(); Dispatcher dispatcher = new Dispatcher(executor); + RecordingEventListener listener = new RecordingEventListener(); OkHttpClient client = defaultClient().newBuilder() .dispatcher(dispatcher) + .eventListener(listener) .build(); @Before public void setUp() throws Exception { dispatcher.setMaxRequests(20); dispatcher.setMaxRequestsPerHost(10); + listener.forbidLock(dispatcher); } @Test public void maxRequestsZero() throws Exception { @@ -264,6 +269,54 @@ public final class DispatcherTest { assertTrue(idle.get()); } + @Test public void executionRejectedImmediately() throws Exception { + Request request = newRequest("http://a/1"); + executor.shutdown(); + client.newCall(request).enqueue(callback); + callback.await(request.url()).assertFailure(InterruptedIOException.class); + assertEquals(Arrays.asList("CallStart", "CallFailed"), listener.recordedEventTypes()); + } + + @Test public void executionRejectedAfterMaxRequestsChange() throws Exception { + Request request1 = newRequest("http://a/1"); + Request request2 = newRequest("http://a/2"); + dispatcher.setMaxRequests(1); + client.newCall(request1).enqueue(callback); + executor.shutdown(); + client.newCall(request2).enqueue(callback); + dispatcher.setMaxRequests(2); // Trigger promotion. + callback.await(request2.url()).assertFailure(InterruptedIOException.class); + + assertEquals(Arrays.asList("CallStart", "CallStart", "CallFailed"), + listener.recordedEventTypes()); + } + + @Test public void executionRejectedAfterMaxRequestsPerHostChange() throws Exception { + Request request1 = newRequest("http://a/1"); + Request request2 = newRequest("http://a/2"); + dispatcher.setMaxRequestsPerHost(1); + client.newCall(request1).enqueue(callback); + executor.shutdown(); + client.newCall(request2).enqueue(callback); + dispatcher.setMaxRequestsPerHost(2); // Trigger promotion. + callback.await(request2.url()).assertFailure(InterruptedIOException.class); + assertEquals(Arrays.asList("CallStart", "CallStart", "CallFailed"), + listener.recordedEventTypes()); + } + + @Test public void executionRejectedAfterPrecedingCallFinishes() throws Exception { + Request request1 = newRequest("http://a/1"); + Request request2 = newRequest("http://a/2"); + dispatcher.setMaxRequests(1); + client.newCall(request1).enqueue(callback); + executor.shutdown(); + client.newCall(request2).enqueue(callback); + executor.finishJob("http://a/1"); // Trigger promotion. + callback.await(request2.url()).assertFailure(InterruptedIOException.class); + assertEquals(Arrays.asList("CallStart", "CallStart", "CallFailed"), + listener.recordedEventTypes()); + } + private Set set(T... values) { return set(Arrays.asList(values)); } @@ -287,9 +340,11 @@ private Thread makeSynchronousCall(final Call call) { } class RecordingExecutor extends AbstractExecutorService { + private boolean shutdown; private List calls = new ArrayList<>(); @Override public void execute(Runnable command) { + if (shutdown) throw new RejectedExecutionException(); calls.add((AsyncCall) command); } @@ -314,7 +369,7 @@ public void finishJob(String url) { } @Override public void shutdown() { - throw new UnsupportedOperationException(); + shutdown = true; } @Override public List shutdownNow() { diff --git a/okhttp/src/main/java/okhttp3/Dispatcher.java b/okhttp/src/main/java/okhttp3/Dispatcher.java index 21013bda11c8..3e33dff6bf59 100644 --- a/okhttp/src/main/java/okhttp3/Dispatcher.java +++ b/okhttp/src/main/java/okhttp3/Dispatcher.java @@ -75,12 +75,14 @@ public synchronized ExecutorService executorService() { *

If more than {@code maxRequests} requests are in flight when this is invoked, those requests * will remain in flight. */ - public synchronized void setMaxRequests(int maxRequests) { + public void setMaxRequests(int maxRequests) { if (maxRequests < 1) { throw new IllegalArgumentException("max < 1: " + maxRequests); } - this.maxRequests = maxRequests; - promoteCalls(); + synchronized (this) { + this.maxRequests = maxRequests; + } + promoteAndExecute(); } public synchronized int getMaxRequests() { @@ -98,12 +100,14 @@ public synchronized int getMaxRequests() { * *

WebSocket connections to hosts do not count against this limit. */ - public synchronized void setMaxRequestsPerHost(int maxRequestsPerHost) { + public void setMaxRequestsPerHost(int maxRequestsPerHost) { if (maxRequestsPerHost < 1) { throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost); } - this.maxRequestsPerHost = maxRequestsPerHost; - promoteCalls(); + synchronized (this) { + this.maxRequestsPerHost = maxRequestsPerHost; + } + promoteAndExecute(); } public synchronized int getMaxRequestsPerHost() { @@ -126,13 +130,11 @@ public synchronized void setIdleCallback(@Nullable Runnable idleCallback) { this.idleCallback = idleCallback; } - synchronized void enqueue(AsyncCall call) { - if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { - runningAsyncCalls.add(call); - executorService().execute(call); - } else { + void enqueue(AsyncCall call) { + synchronized (this) { readyAsyncCalls.add(call); } + promoteAndExecute(); } /** @@ -153,21 +155,38 @@ public synchronized void cancelAll() { } } - private void promoteCalls() { - if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity. - if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote. + /** + * Promotes eligible calls from {@link #readyAsyncCalls} to {@link #runningAsyncCalls} and runs + * them on the executor service. Must not be called with synchronization because executing calls + * can call into user code. + * + * @return true if the dispatcher is currently running calls. + */ + private boolean promoteAndExecute() { + assert (!Thread.holdsLock(this)); + + List executableCalls = new ArrayList<>(); + boolean isRunning; + synchronized (this) { + for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) { + AsyncCall asyncCall = i.next(); - for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) { - AsyncCall call = i.next(); + if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity. + if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity. - if (runningCallsForHost(call) < maxRequestsPerHost) { i.remove(); - runningAsyncCalls.add(call); - executorService().execute(call); + executableCalls.add(asyncCall); + runningAsyncCalls.add(asyncCall); } + isRunning = runningCallsCount() > 0; + } - if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity. + for (int i = 0, size = executableCalls.size(); i < size; i++) { + AsyncCall asyncCall = executableCalls.get(i); + asyncCall.executeOn(executorService()); } + + return isRunning; } /** Returns the number of running calls that share a host with {@code call}. */ @@ -187,25 +206,24 @@ synchronized void executed(RealCall call) { /** Used by {@code AsyncCall#run} to signal completion. */ void finished(AsyncCall call) { - finished(runningAsyncCalls, call, true); + finished(runningAsyncCalls, call); } /** Used by {@code Call#execute} to signal completion. */ void finished(RealCall call) { - finished(runningSyncCalls, call, false); + finished(runningSyncCalls, call); } - private void finished(Deque calls, T call, boolean promoteCalls) { - int runningCallsCount; + private void finished(Deque calls, T call) { Runnable idleCallback; synchronized (this) { if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!"); - if (promoteCalls) promoteCalls(); - runningCallsCount = runningCallsCount(); idleCallback = this.idleCallback; } - if (runningCallsCount == 0 && idleCallback != null) { + boolean isRunning = promoteAndExecute(); + + if (!isRunning && idleCallback != null) { idleCallback.run(); } } diff --git a/okhttp/src/main/java/okhttp3/RealCall.java b/okhttp/src/main/java/okhttp3/RealCall.java index 659b4b9e5cca..eb43ead47b9f 100644 --- a/okhttp/src/main/java/okhttp3/RealCall.java +++ b/okhttp/src/main/java/okhttp3/RealCall.java @@ -19,6 +19,8 @@ import java.io.InterruptedIOException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionException; import javax.annotation.Nullable; import okhttp3.internal.NamedRunnable; import okhttp3.internal.cache.CacheInterceptor; @@ -167,6 +169,28 @@ RealCall get() { return RealCall.this; } + /** + * Attempt to enqueue this async call on {@code executorService}. This will attempt to clean up + * if the executor has been shut down by reporting the call as failed. + */ + void executeOn(ExecutorService executorService) { + assert (!Thread.holdsLock(client.dispatcher())); + boolean success = false; + try { + executorService.execute(this); + success = true; + } catch (RejectedExecutionException e) { + InterruptedIOException ioException = new InterruptedIOException("executor rejected"); + ioException.initCause(e); + eventListener.callFailed(RealCall.this, ioException); + responseCallback.onFailure(RealCall.this, ioException); + } finally { + if (!success) { + client.dispatcher().finished(this); // This call is no longer running! + } + } + } + @Override protected void execute() { boolean signalledCallback = false; timeout.enter(); From af07e023f8d141d4a0cc165962b5f5cc997cff9c Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Tue, 6 Nov 2018 21:21:20 +1100 Subject: [PATCH 12/20] Add APIs to configure the client's default call timeout. (#4369) * Add APIs to configure the client's default call timeout. This isn't independently configured in an interceptor like the other timeouts because it's already started by the time the interceptors run. * Update okhttp/src/main/java/okhttp3/OkHttpClient.java Co-Authored-By: swankjesse * Update okhttp/src/main/java/okhttp3/OkHttpClient.java Co-Authored-By: swankjesse --- .../test/java/okhttp3/OkHttpClientTest.java | 9 ++++ .../okhttp3/WholeOperationTimeoutTest.java | 22 ++++++++++ okhttp/src/main/java/okhttp3/Call.java | 7 +++- .../src/main/java/okhttp3/OkHttpClient.java | 41 ++++++++++++++++++- okhttp/src/main/java/okhttp3/RealCall.java | 2 + 5 files changed, 77 insertions(+), 4 deletions(-) diff --git a/okhttp-tests/src/test/java/okhttp3/OkHttpClientTest.java b/okhttp-tests/src/test/java/okhttp3/OkHttpClientTest.java index 18a252bd693b..b4ee085371a3 100644 --- a/okhttp-tests/src/test/java/okhttp3/OkHttpClientTest.java +++ b/okhttp-tests/src/test/java/okhttp3/OkHttpClientTest.java @@ -53,6 +53,7 @@ public final class OkHttpClientTest { @Test public void durationDefaults() { OkHttpClient client = defaultClient(); + assertEquals(0, client.callTimeoutMillis()); assertEquals(10_000, client.connectTimeoutMillis()); assertEquals(10_000, client.readTimeoutMillis()); assertEquals(10_000, client.writeTimeoutMillis()); @@ -61,6 +62,10 @@ public final class OkHttpClientTest { @Test public void timeoutValidRange() { OkHttpClient.Builder builder = new OkHttpClient.Builder(); + try { + builder.callTimeout(1, TimeUnit.NANOSECONDS); + } catch (IllegalArgumentException ignored) { + } try { builder.connectTimeout(1, TimeUnit.NANOSECONDS); } catch (IllegalArgumentException ignored) { @@ -73,6 +78,10 @@ public final class OkHttpClientTest { builder.readTimeout(1, TimeUnit.NANOSECONDS); } catch (IllegalArgumentException ignored) { } + try { + builder.callTimeout(365, TimeUnit.DAYS); + } catch (IllegalArgumentException ignored) { + } try { builder.connectTimeout(365, TimeUnit.DAYS); } catch (IllegalArgumentException ignored) { diff --git a/okhttp-tests/src/test/java/okhttp3/WholeOperationTimeoutTest.java b/okhttp-tests/src/test/java/okhttp3/WholeOperationTimeoutTest.java index 591a756c0b3a..603f221397d9 100644 --- a/okhttp-tests/src/test/java/okhttp3/WholeOperationTimeoutTest.java +++ b/okhttp-tests/src/test/java/okhttp3/WholeOperationTimeoutTest.java @@ -28,6 +28,7 @@ import org.junit.Test; import static okhttp3.TestUtil.defaultClient; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -41,6 +42,27 @@ public final class WholeOperationTimeoutTest { private OkHttpClient client = defaultClient(); + @Test public void defaultConfigIsNoTimeout() throws Exception { + Request request = new Request.Builder() + .url(server.url("/")) + .build(); + Call call = client.newCall(request); + assertEquals(0, call.timeout().timeoutNanos()); + } + + @Test public void configureClientDefault() throws Exception { + Request request = new Request.Builder() + .url(server.url("/")) + .build(); + + OkHttpClient timeoutClient = client.newBuilder() + .callTimeout(456, TimeUnit.MILLISECONDS) + .build(); + + Call call = timeoutClient.newCall(request); + assertEquals(TimeUnit.MILLISECONDS.toNanos(456), call.timeout().timeoutNanos()); + } + @Test public void timeoutWritingRequest() throws Exception { server.enqueue(new MockResponse()); diff --git a/okhttp/src/main/java/okhttp3/Call.java b/okhttp/src/main/java/okhttp3/Call.java index 2a0a548f7a69..67d0f88d3d28 100644 --- a/okhttp/src/main/java/okhttp3/Call.java +++ b/okhttp/src/main/java/okhttp3/Call.java @@ -82,8 +82,11 @@ public interface Call extends Cloneable { boolean isCanceled(); /** - * Returns a timeout that applies to the entire call: writing the request, server processing, - * and reading the response. + * Returns a timeout that spans the entire call: resolving DNS, connecting, writing the request + * body, server processing, and reading the response body. If the call requires redirects or + * retries all must complete within one timeout period. + * + *

Configure the client's default timeout with {@link OkHttpClient.Builder#callTimeout}. */ Timeout timeout(); diff --git a/okhttp/src/main/java/okhttp3/OkHttpClient.java b/okhttp/src/main/java/okhttp3/OkHttpClient.java index 7b44bbac97c4..1686af2aa969 100644 --- a/okhttp/src/main/java/okhttp3/OkHttpClient.java +++ b/okhttp/src/main/java/okhttp3/OkHttpClient.java @@ -221,6 +221,7 @@ public void apply(ConnectionSpec tlsConfiguration, SSLSocket sslSocket, boolean final boolean followSslRedirects; final boolean followRedirects; final boolean retryOnConnectionFailure; + final int callTimeout; final int connectTimeout; final int readTimeout; final int writeTimeout; @@ -272,6 +273,7 @@ public OkHttpClient() { this.followSslRedirects = builder.followSslRedirects; this.followRedirects = builder.followRedirects; this.retryOnConnectionFailure = builder.retryOnConnectionFailure; + this.callTimeout = builder.callTimeout; this.connectTimeout = builder.connectTimeout; this.readTimeout = builder.readTimeout; this.writeTimeout = builder.writeTimeout; @@ -295,6 +297,11 @@ private static SSLSocketFactory newSslSocketFactory(X509TrustManager trustManage } } + /** Default call timeout (in milliseconds). */ + public int callTimeoutMillis() { + return callTimeout; + } + /** Default connect timeout (in milliseconds). */ public int connectTimeoutMillis() { return connectTimeout; @@ -457,6 +464,7 @@ public static final class Builder { boolean followSslRedirects; boolean followRedirects; boolean retryOnConnectionFailure; + int callTimeout; int connectTimeout; int readTimeout; int writeTimeout; @@ -482,6 +490,7 @@ public Builder() { followSslRedirects = true; followRedirects = true; retryOnConnectionFailure = true; + callTimeout = 0; connectTimeout = 10_000; readTimeout = 10_000; writeTimeout = 10_000; @@ -512,18 +521,46 @@ public Builder() { this.followSslRedirects = okHttpClient.followSslRedirects; this.followRedirects = okHttpClient.followRedirects; this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure; + this.callTimeout = okHttpClient.callTimeout; this.connectTimeout = okHttpClient.connectTimeout; this.readTimeout = okHttpClient.readTimeout; this.writeTimeout = okHttpClient.writeTimeout; this.pingInterval = okHttpClient.pingInterval; } + /** + * Sets the default timeout for complete calls. A value of 0 means no timeout, otherwise values + * must be between 1 and {@link Integer#MAX_VALUE} when converted to milliseconds. + * + *

The call timeout spans the entire call: resolving DNS, connecting, writing the request + * body, server processing, and reading the response body. If the call requires redirects or + * retries all must complete within one timeout period. + */ + public Builder callTimeout(long timeout, TimeUnit unit) { + callTimeout = checkDuration("timeout", timeout, unit); + return this; + } + + /** + * Sets the default timeout for complete calls. A value of 0 means no timeout, otherwise values + * must be between 1 and {@link Integer#MAX_VALUE} when converted to milliseconds. + * + *

The call timeout spans the entire call: resolving DNS, connecting, writing the request + * body, server processing, and reading the response body. If the call requires redirects or + * retries all must complete within one timeout period. + */ + @IgnoreJRERequirement + public Builder callTimeout(Duration duration) { + callTimeout = checkDuration("timeout", duration.toMillis(), TimeUnit.MILLISECONDS); + return this; + } + /** * Sets the default connect timeout for new connections. A value of 0 means no timeout, * otherwise values must be between 1 and {@link Integer#MAX_VALUE} when converted to * milliseconds. * - *

The connectTimeout is applied when connecting a TCP socket to the target host. + *

The connect timeout is applied when connecting a TCP socket to the target host. * The default value is 10 seconds. */ public Builder connectTimeout(long timeout, TimeUnit unit) { @@ -536,7 +573,7 @@ public Builder connectTimeout(long timeout, TimeUnit unit) { * otherwise values must be between 1 and {@link Integer#MAX_VALUE} when converted to * milliseconds. * - *

The connectTimeout is applied when connecting a TCP socket to the target host. + *

The connect timeout is applied when connecting a TCP socket to the target host. * The default value is 10 seconds. */ @IgnoreJRERequirement diff --git a/okhttp/src/main/java/okhttp3/RealCall.java b/okhttp/src/main/java/okhttp3/RealCall.java index eb43ead47b9f..a9ba5be366b4 100644 --- a/okhttp/src/main/java/okhttp3/RealCall.java +++ b/okhttp/src/main/java/okhttp3/RealCall.java @@ -34,6 +34,7 @@ import okio.AsyncTimeout; import okio.Timeout; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static okhttp3.internal.platform.Platform.INFO; final class RealCall implements Call { @@ -64,6 +65,7 @@ private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSoc cancel(); } }; + this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS); } static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { From 04a74b2df4754575a762ec0056209b9c9fce0062 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Tue, 6 Nov 2018 10:52:06 +1100 Subject: [PATCH 13/20] Confirm that call timeouts don't apply to SSE or web sockets. --- okhttp-sse/pom.xml | 5 +++ .../okhttp3/internal/sse/RealEventSource.java | 1 + .../internal/sse/EventSourceHttpTest.java | 24 +++++++++++++- .../src/main}/java/okhttp3/TestUtil.java | 32 ++++++++++++++++-- .../src/test/java/okhttp3/CallTest.java | 4 --- .../test/java/okhttp3/EventListenerTest.java | 13 +++----- .../test/java/okhttp3/URLConnectionTest.java | 7 ---- .../internal/SingleInetAddressDns.java | 33 ------------------- .../internal/http2/HttpOverHttp2Test.java | 2 -- .../internal/ws/WebSocketHttpTest.java | 18 ++++++++++ .../okhttp3/internal/ws/RealWebSocket.java | 1 + 11 files changed, 83 insertions(+), 57 deletions(-) rename {okhttp-tests/src/test => okhttp-testing-support/src/main}/java/okhttp3/TestUtil.java (60%) delete mode 100644 okhttp-tests/src/test/java/okhttp3/internal/SingleInetAddressDns.java diff --git a/okhttp-sse/pom.xml b/okhttp-sse/pom.xml index b46d96f0981a..d2e7505f5e54 100644 --- a/okhttp-sse/pom.xml +++ b/okhttp-sse/pom.xml @@ -18,6 +18,11 @@ okhttp ${project.version} + + ${project.groupId} + okhttp-testing-support + ${project.version} + com.google.code.findbugs jsr305 diff --git a/okhttp-sse/src/main/java/okhttp3/internal/sse/RealEventSource.java b/okhttp-sse/src/main/java/okhttp3/internal/sse/RealEventSource.java index 320ddddd984f..c49e49f4aa02 100644 --- a/okhttp-sse/src/main/java/okhttp3/internal/sse/RealEventSource.java +++ b/okhttp-sse/src/main/java/okhttp3/internal/sse/RealEventSource.java @@ -47,6 +47,7 @@ public void connect(OkHttpClient client) { .eventListener(EventListener.NONE) .build(); call = client.newCall(request); + call.timeout().clearTimeout(); call.enqueue(this); } diff --git a/okhttp-sse/src/test/java/okhttp3/internal/sse/EventSourceHttpTest.java b/okhttp-sse/src/test/java/okhttp3/internal/sse/EventSourceHttpTest.java index ffdabbcd1456..7f576eece9d0 100644 --- a/okhttp-sse/src/test/java/okhttp3/internal/sse/EventSourceHttpTest.java +++ b/okhttp-sse/src/test/java/okhttp3/internal/sse/EventSourceHttpTest.java @@ -15,6 +15,7 @@ */ package okhttp3.internal.sse; +import java.util.concurrent.TimeUnit; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.mockwebserver.MockResponse; @@ -25,13 +26,14 @@ import org.junit.Rule; import org.junit.Test; +import static okhttp3.TestUtil.defaultClient; import static org.junit.Assert.assertEquals; public final class EventSourceHttpTest { @Rule public final MockWebServer server = new MockWebServer(); private final EventSourceRecorder listener = new EventSourceRecorder(); - private final EventSource.Factory factory = EventSources.createFactory(new OkHttpClient()); + private OkHttpClient client = defaultClient(); @After public void after() { listener.assertExhausted(); @@ -69,10 +71,30 @@ public final class EventSourceHttpTest { listener.assertFailure(null); } + @Test public void callTimeoutIsNotApplied() throws Exception { + client = client.newBuilder() + .callTimeout(100, TimeUnit.MILLISECONDS) + .build(); + + server.enqueue(new MockResponse() + .setBodyDelay(500, TimeUnit.MILLISECONDS) + .setHeader("content-type", "text/event-stream") + .setBody("data: hey\n\n")); + + EventSource source = newEventSource(); + + assertEquals("/", source.request().url().encodedPath()); + + listener.assertOpen(); + listener.assertEvent(null, null, "hey"); + listener.assertClose(); + } + private EventSource newEventSource() { Request request = new Request.Builder() .url(server.url("/")) .build(); + EventSource.Factory factory = EventSources.createFactory(client); return factory.newEventSource(request, listener); } } diff --git a/okhttp-tests/src/test/java/okhttp3/TestUtil.java b/okhttp-testing-support/src/main/java/okhttp3/TestUtil.java similarity index 60% rename from okhttp-tests/src/test/java/okhttp3/TestUtil.java rename to okhttp-testing-support/src/main/java/okhttp3/TestUtil.java index 4957087cf78e..2a85617dc18d 100644 --- a/okhttp-tests/src/test/java/okhttp3/TestUtil.java +++ b/okhttp-testing-support/src/main/java/okhttp3/TestUtil.java @@ -1,16 +1,44 @@ +/* + * Copyright (C) 2018 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. + */ package okhttp3; +import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; -import okhttp3.internal.SingleInetAddressDns; import okhttp3.internal.http2.Header; public final class TestUtil { public static final InetSocketAddress UNREACHABLE_ADDRESS = new InetSocketAddress("198.51.100.1", 8080); + /** + * A network that resolves only one IP address per host. Use this when testing route selection + * fallbacks to prevent the host machine's various IP addresses from interfering. + */ + private static final Dns SINGLE_INET_ADDRESS_DNS = new Dns() { + @Override public List lookup(String hostname) throws UnknownHostException { + List addresses = Dns.SYSTEM.lookup(hostname); + return Collections.singletonList(addresses.get(0)); + } + }; + private TestUtil() { } @@ -30,7 +58,7 @@ public static OkHttpClient defaultClient() { return new OkHttpClient.Builder() .connectionPool(connectionPool) .dispatcher(dispatcher) - .dns(new SingleInetAddressDns()) // Prevent unexpected fallback addresses. + .dns(SINGLE_INET_ADDRESS_DNS) // Prevent unexpected fallback addresses. .build(); } diff --git a/okhttp-tests/src/test/java/okhttp3/CallTest.java b/okhttp-tests/src/test/java/okhttp3/CallTest.java index 9bbcce07de04..4d16cf1fefa3 100644 --- a/okhttp-tests/src/test/java/okhttp3/CallTest.java +++ b/okhttp-tests/src/test/java/okhttp3/CallTest.java @@ -59,7 +59,6 @@ import javax.net.ssl.SSLSocketFactory; import okhttp3.internal.DoubleInetAddressDns; import okhttp3.internal.RecordingOkAuthenticator; -import okhttp3.internal.SingleInetAddressDns; import okhttp3.internal.Util; import okhttp3.internal.Version; import okhttp3.internal.http.RecordingProxySelector; @@ -1090,7 +1089,6 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc client = client.newBuilder() .hostnameVerifier(new RecordingHostnameVerifier()) - .dns(new SingleInetAddressDns()) // Attempt RESTRICTED_TLS then fall back to MODERN_TLS. .connectionSpecs(Arrays.asList(ConnectionSpec.RESTRICTED_TLS, ConnectionSpec.MODERN_TLS)) .sslSocketFactory( @@ -1119,7 +1117,6 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc // Attempt RESTRICTED_TLS then fall back to MODERN_TLS. .connectionSpecs(Arrays.asList(ConnectionSpec.RESTRICTED_TLS, ConnectionSpec.MODERN_TLS)) .hostnameVerifier(new RecordingHostnameVerifier()) - .dns(new SingleInetAddressDns()) .build(); Request request = new Request.Builder().url(server.url("/")).build(); @@ -1161,7 +1158,6 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc client = client.newBuilder() .connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT)) .hostnameVerifier(new RecordingHostnameVerifier()) - .dns(new SingleInetAddressDns()) .sslSocketFactory( suppressTlsFallbackClientSocketFactory(), handshakeCertificates.trustManager()) .build(); diff --git a/okhttp-tests/src/test/java/okhttp3/EventListenerTest.java b/okhttp-tests/src/test/java/okhttp3/EventListenerTest.java index 8d22f7cb53db..5a9780e7630d 100644 --- a/okhttp-tests/src/test/java/okhttp3/EventListenerTest.java +++ b/okhttp-tests/src/test/java/okhttp3/EventListenerTest.java @@ -42,7 +42,6 @@ import okhttp3.RecordingEventListener.SecureConnectStart; import okhttp3.internal.DoubleInetAddressDns; import okhttp3.internal.RecordingOkAuthenticator; -import okhttp3.internal.SingleInetAddressDns; import okhttp3.logging.HttpLoggingInterceptor; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; @@ -80,7 +79,6 @@ public final class EventListenerTest { public static final Matcher anyResponse = CoreMatchers.any(Response.class); @Rule public final MockWebServer server = new MockWebServer(); - private final SingleInetAddressDns singleDns = new SingleInetAddressDns(); private final RecordingEventListener listener = new RecordingEventListener(); private final HandshakeCertificates handshakeCertificates = localhost(); @@ -89,7 +87,6 @@ public final class EventListenerTest { @Before public void setUp() { client = defaultClient().newBuilder() - .dns(singleDns) .eventListener(listener) .build(); @@ -437,8 +434,8 @@ private Matcher matchesProtocol(final Protocol protocol) { server.enqueue(new MockResponse()); FakeDns dns = new FakeDns(); - dns.set("fakeurl", singleDns.lookup(server.getHostName())); - dns.set("www.fakeurl", singleDns.lookup(server.getHostName())); + dns.set("fakeurl", client.dns().lookup(server.getHostName())); + dns.set("www.fakeurl", client.dns().lookup(server.getHostName())); client = client.newBuilder() .dns(dns) @@ -513,7 +510,7 @@ private Matcher matchesProtocol(final Protocol protocol) { assertEquals(200, response.code()); response.body().close(); - InetAddress address = singleDns.lookup(server.getHostName()).get(0); + InetAddress address = client.dns().lookup(server.getHostName()).get(0); InetSocketAddress expectedAddress = new InetSocketAddress(address, server.getPort()); ConnectStart connectStart = listener.removeUpToEvent(ConnectStart.class); @@ -541,7 +538,7 @@ private Matcher matchesProtocol(final Protocol protocol) { } catch (IOException expected) { } - InetAddress address = singleDns.lookup(server.getHostName()).get(0); + InetAddress address = client.dns().lookup(server.getHostName()).get(0); InetSocketAddress expectedAddress = new InetSocketAddress(address, server.getPort()); ConnectStart connectStart = listener.removeUpToEvent(ConnectStart.class); @@ -593,7 +590,7 @@ private Matcher matchesProtocol(final Protocol protocol) { assertEquals(200, response.code()); response.body().close(); - InetAddress address = singleDns.lookup(server.getHostName()).get(0); + InetAddress address = client.dns().lookup(server.getHostName()).get(0); InetSocketAddress expectedAddress = new InetSocketAddress(address, server.getPort()); ConnectStart connectStart = listener.removeUpToEvent(ConnectStart.class); diff --git a/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java b/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java index 452949039642..1bf5e2b6903a 100644 --- a/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java +++ b/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java @@ -67,7 +67,6 @@ import okhttp3.internal.Internal; import okhttp3.internal.RecordingAuthenticator; import okhttp3.internal.RecordingOkAuthenticator; -import okhttp3.internal.SingleInetAddressDns; import okhttp3.internal.Util; import okhttp3.internal.Version; import okhttp3.internal.huc.OkHttpURLConnection; @@ -88,7 +87,6 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; -import static java.util.Collections.singletonMap; import static java.util.Locale.US; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.NANOSECONDS; @@ -719,7 +717,6 @@ private void connectViaHttpsReusingConnections(boolean rebuildClient) throws Exc server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE)); urlFactory.setClient(urlFactory.client().newBuilder() - .dns(new SingleInetAddressDns()) .connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS)) .hostnameVerifier(new RecordingHostnameVerifier()) .sslSocketFactory( @@ -1021,7 +1018,6 @@ private void testConnectViaHttpProxyToHttps(ProxyConfig proxyConfig) throws Exce // Configure a single IP address for the host and a single configuration, so we only need one // failure to fail permanently. urlFactory.setClient(urlFactory.client().newBuilder() - .dns(new SingleInetAddressDns()) .sslSocketFactory( handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager()) .connectionSpecs(Util.immutableList(ConnectionSpec.MODERN_TLS)) @@ -2648,9 +2644,6 @@ protected ServerSocket configureServerSocket(ServerSocket serverSocket) * https://code.google.com/p/android/issues/detail?id=41576 */ @Test public void sameConnectionRedirectAndReuse() throws Exception { - urlFactory.setClient(urlFactory.client().newBuilder() - .dns(new SingleInetAddressDns()) - .build()); server.enqueue(new MockResponse() .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) .setSocketPolicy(SHUTDOWN_INPUT_AT_END) diff --git a/okhttp-tests/src/test/java/okhttp3/internal/SingleInetAddressDns.java b/okhttp-tests/src/test/java/okhttp3/internal/SingleInetAddressDns.java deleted file mode 100644 index 03e8ce08e958..000000000000 --- a/okhttp-tests/src/test/java/okhttp3/internal/SingleInetAddressDns.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ -package okhttp3.internal; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Collections; -import java.util.List; -import okhttp3.Dns; - -/** - * A network that resolves only one IP address per host. Use this when testing route selection - * fallbacks to prevent the host machine's various IP addresses from interfering. - */ -public class SingleInetAddressDns implements Dns { - @Override public List lookup(String hostname) throws UnknownHostException { - List addresses = Dns.SYSTEM.lookup(hostname); - return Collections.singletonList(addresses.get(0)); - } -} diff --git a/okhttp-tests/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.java b/okhttp-tests/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.java index 6e8f5b8e24a7..3e4552aed51f 100644 --- a/okhttp-tests/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.java +++ b/okhttp-tests/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.java @@ -51,7 +51,6 @@ import okhttp3.TestUtil; import okhttp3.internal.DoubleInetAddressDns; import okhttp3.internal.RecordingOkAuthenticator; -import okhttp3.internal.SingleInetAddressDns; import okhttp3.internal.Util; import okhttp3.internal.connection.RealConnection; import okhttp3.mockwebserver.Dispatcher; @@ -125,7 +124,6 @@ private static OkHttpClient buildH2PriorKnowledgeClient() { private static OkHttpClient buildHttp2Client() { return defaultClient().newBuilder() .protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1)) - .dns(new SingleInetAddressDns()) .sslSocketFactory( handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager()) .hostnameVerifier(new RecordingHostnameVerifier()) diff --git a/okhttp-tests/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.java b/okhttp-tests/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.java index 565ffdac5823..4ef795d33471 100644 --- a/okhttp-tests/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.java +++ b/okhttp-tests/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.java @@ -677,6 +677,24 @@ public final class WebSocketHttpTest { assertEquals(Collections.emptyList(), listener.recordedEventTypes()); } + @Test public void callTimeoutIsNotApplied() throws Exception { + client = client.newBuilder() + .callTimeout(100, TimeUnit.MILLISECONDS) + .build(); + + webServer.enqueue(new MockResponse() + .withWebSocketUpgrade(serverListener)); + newWebSocket(); + + clientListener.assertOpen(); + WebSocket server = serverListener.assertOpen(); + + Thread.sleep(500); + + server.send("Hello, WebSockets!"); + clientListener.assertTextMessage("Hello, WebSockets!"); + } + private MockResponse upgradeResponse(RecordedRequest request) { String key = request.getHeader("Sec-WebSocket-Key"); return new MockResponse() diff --git a/okhttp/src/main/java/okhttp3/internal/ws/RealWebSocket.java b/okhttp/src/main/java/okhttp3/internal/ws/RealWebSocket.java index 092dc5775e83..baee049f1bc9 100644 --- a/okhttp/src/main/java/okhttp3/internal/ws/RealWebSocket.java +++ b/okhttp/src/main/java/okhttp3/internal/ws/RealWebSocket.java @@ -189,6 +189,7 @@ public void connect(OkHttpClient client) { .header("Sec-WebSocket-Version", "13") .build(); call = Internal.instance.newWebSocketCall(client, request); + call.timeout().clearTimeout(); call.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { try { From 2c95b0437ba953459838a72133baabc386ac7721 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Tue, 6 Nov 2018 21:48:46 +1100 Subject: [PATCH 14/20] Don't specify a crypto provider in HeldCertificate. Closes: https://github.com/square/okhttp/issues/4183 --- okhttp-tls/src/main/java/okhttp3/tls/HeldCertificate.java | 4 ++-- okhttp-tls/src/test/java/okhttp3/tls/HeldCertificateTest.java | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/okhttp-tls/src/main/java/okhttp3/tls/HeldCertificate.java b/okhttp-tls/src/main/java/okhttp3/tls/HeldCertificate.java index 5f4b56096b86..02a3d40eab06 100644 --- a/okhttp-tls/src/main/java/okhttp3/tls/HeldCertificate.java +++ b/okhttp-tls/src/main/java/okhttp3/tls/HeldCertificate.java @@ -401,7 +401,7 @@ public HeldCertificate build() { try { X509Certificate certificate = generator.generateX509Certificate( - signedByKeyPair.getPrivate(), "BC"); + signedByKeyPair.getPrivate()); return new HeldCertificate(heldKeyPair, certificate); } catch (GeneralSecurityException e) { throw new AssertionError(e); @@ -423,7 +423,7 @@ private X500Principal buildSubject() { private KeyPair generateKeyPair() { try { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm, "BC"); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm); keyPairGenerator.initialize(keySize, new SecureRandom()); return keyPairGenerator.generateKeyPair(); } catch (GeneralSecurityException e) { diff --git a/okhttp-tls/src/test/java/okhttp3/tls/HeldCertificateTest.java b/okhttp-tls/src/test/java/okhttp3/tls/HeldCertificateTest.java index 96c8601b24c6..ffec150f3281 100644 --- a/okhttp-tls/src/test/java/okhttp3/tls/HeldCertificateTest.java +++ b/okhttp-tls/src/test/java/okhttp3/tls/HeldCertificateTest.java @@ -52,9 +52,6 @@ public final class HeldCertificateTest { long durationMillis = TimeUnit.MINUTES.toMillis(60 * 24); assertEquals((double) now, certificate.getNotBefore().getTime(), deltaMillis); assertEquals((double) now + durationMillis, certificate.getNotAfter().getTime(), deltaMillis); - - System.out.println(ByteString.of(heldCertificate.keyPair().getPublic().getEncoded()).base64()); - System.out.println(ByteString.of(heldCertificate.keyPair().getPrivate().getEncoded()).base64()); } @Test public void customInterval() { From 62f2f823410661128d1d9549b9b727f824637f6c Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Tue, 6 Nov 2018 22:36:54 +1100 Subject: [PATCH 15/20] Fix connection leaks on failed web socket upgrades. Closes: https://github.com/square/okhttp/issues/4258 --- .../internal/ws/WebSocketHttpTest.java | 32 +++++++++++++++++++ .../http/RetryAndFollowUpInterceptor.java | 4 +-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/okhttp-tests/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.java b/okhttp-tests/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.java index 4ef795d33471..1e17baa9c2ab 100644 --- a/okhttp-tests/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.java +++ b/okhttp-tests/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.java @@ -17,8 +17,10 @@ import java.io.EOFException; import java.io.IOException; +import java.net.HttpURLConnection; import java.net.ProtocolException; import java.net.SocketTimeoutException; +import java.util.Arrays; import java.util.Collections; import java.util.Random; import java.util.concurrent.CountDownLatch; @@ -27,6 +29,7 @@ import java.util.logging.Logger; import okhttp3.Interceptor; import okhttp3.OkHttpClient; +import okhttp3.Protocol; import okhttp3.RecordingEventListener; import okhttp3.RecordingHostnameVerifier; import okhttp3.Request; @@ -695,6 +698,35 @@ public final class WebSocketHttpTest { clientListener.assertTextMessage("Hello, WebSockets!"); } + /** + * We had a bug where web socket connections were leaked if the HTTP connection upgrade was not + * successful. This test confirms that connections are released back to the connection pool! + * https://github.com/square/okhttp/issues/4258 + */ + @Test public void webSocketConnectionIsReleased() throws Exception { + // This test assumes HTTP/1.1 pooling semantics. + client = client.newBuilder() + .protocols(Arrays.asList(Protocol.HTTP_1_1)) + .build(); + + webServer.enqueue(new MockResponse() + .setResponseCode(HttpURLConnection.HTTP_NOT_FOUND) + .setBody("not found!")); + webServer.enqueue(new MockResponse()); + + newWebSocket(); + clientListener.assertFailure(); + + Request regularRequest = new Request.Builder() + .url(webServer.url("/")) + .build(); + Response response = client.newCall(regularRequest).execute(); + response.close(); + + assertEquals(0, webServer.takeRequest().getSequenceNumber()); + assertEquals(1, webServer.takeRequest().getSequenceNumber()); + } + private MockResponse upgradeResponse(RecordedRequest request) { String key = request.getHeader("Sec-WebSocket-Key"); return new MockResponse() diff --git a/okhttp/src/main/java/okhttp3/internal/http/RetryAndFollowUpInterceptor.java b/okhttp/src/main/java/okhttp3/internal/http/RetryAndFollowUpInterceptor.java index ffb75058aa7b..d682de8bf04f 100644 --- a/okhttp/src/main/java/okhttp3/internal/http/RetryAndFollowUpInterceptor.java +++ b/okhttp/src/main/java/okhttp3/internal/http/RetryAndFollowUpInterceptor.java @@ -164,9 +164,7 @@ public StreamAllocation streamAllocation() { } if (followUp == null) { - if (!forWebSocket) { - streamAllocation.release(); - } + streamAllocation.release(); return response; } From 495b5f78a072b7812fe06f0b4c6565d5036f0587 Mon Sep 17 00:00:00 2001 From: John Carlson Date: Wed, 7 Nov 2018 05:01:01 -0600 Subject: [PATCH 16/20] Add some docs for Cache class (#4375) * Add some docs for cache * Correction to size getter * Update based on feedback --- okhttp/src/main/java/okhttp3/Cache.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/okhttp/src/main/java/okhttp3/Cache.java b/okhttp/src/main/java/okhttp3/Cache.java index d43d91d25732..343df45113a1 100644 --- a/okhttp/src/main/java/okhttp3/Cache.java +++ b/okhttp/src/main/java/okhttp3/Cache.java @@ -175,6 +175,9 @@ public final class Cache implements Closeable, Flushable { private int hitCount; private int requestCount; + /** + * Create a cache of at most {@code maxSize} bytes in {@code directory}. + */ public Cache(File directory, long maxSize) { this(directory, maxSize, FileSystem.SYSTEM); } @@ -379,6 +382,7 @@ public long size() throws IOException { return cache.size(); } + /** Max size of the cache (in bytes). */ public long maxSize() { return cache.getMaxSize(); } From 764b31b3e2367dcadacc08b818739b065b1c4bef Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Mon, 12 Nov 2018 22:30:49 -0500 Subject: [PATCH 17/20] Relax handling of Cache-Control: immutable Previously we were treating this header as if the response would never change. This was incorrect. The correct behavior according to RFC 8246 is that the 'immutable' directive only applies to conditional requests made during the freshness lifetime. We don't make conditional requests during the freshness lifetime, so the entire directive doesn't apply to us. https://github.com/square/okhttp/issues/4313 --- .../src/test/java/okhttp3/CacheTest.java | 17 +++++++++++++++-- .../okhttp3/internal/cache/CacheStrategy.java | 3 --- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/okhttp-tests/src/test/java/okhttp3/CacheTest.java b/okhttp-tests/src/test/java/okhttp3/CacheTest.java index 8673ffa03194..0d9ca9fa75f2 100644 --- a/okhttp-tests/src/test/java/okhttp3/CacheTest.java +++ b/okhttp-tests/src/test/java/okhttp3/CacheTest.java @@ -2524,7 +2524,7 @@ private RecordedRequest assertConditionallyCached(MockResponse response) throws @Test public void immutableIsCached() throws Exception { server.enqueue(new MockResponse() - .addHeader("Cache-Control", "immutable") + .addHeader("Cache-Control", "immutable, max-age=10") .setBody("A")); server.enqueue(new MockResponse() .setBody("B")); @@ -2538,7 +2538,7 @@ private RecordedRequest assertConditionallyCached(MockResponse response) throws server.enqueue(new MockResponse() .setBody("A")); server.enqueue(new MockResponse() - .addHeader("Cache-Control", "immutable") + .addHeader("Cache-Control", "immutable, max-age=10") .setBody("B")); server.enqueue(new MockResponse() .setBody("C")); @@ -2549,6 +2549,19 @@ private RecordedRequest assertConditionallyCached(MockResponse response) throws assertEquals("B", get(url).body().string()); } + @Test public void immutableIsNotCachedBeyondFreshnessLifetime() throws Exception { + // last modified: 115 seconds ago + // served: 15 seconds ago + // default lifetime: (115 - 15) / 10 = 10 seconds + // expires: 10 seconds from served date = 5 seconds ago + String lastModifiedDate = formatDate(-115, TimeUnit.SECONDS); + RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() + .addHeader("Cache-Control: immutable") + .addHeader("Last-Modified: " + lastModifiedDate) + .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS))); + assertEquals(lastModifiedDate, conditionalRequest.getHeader("If-Modified-Since")); + } + private void assertFullyCached(MockResponse response) throws Exception { server.enqueue(response.setBody("A")); server.enqueue(response.setBody("B")); diff --git a/okhttp/src/main/java/okhttp3/internal/cache/CacheStrategy.java b/okhttp/src/main/java/okhttp3/internal/cache/CacheStrategy.java index 3ae192665052..c7fb69cebaa6 100644 --- a/okhttp/src/main/java/okhttp3/internal/cache/CacheStrategy.java +++ b/okhttp/src/main/java/okhttp3/internal/cache/CacheStrategy.java @@ -205,9 +205,6 @@ private CacheStrategy getCandidate() { } CacheControl responseCaching = cacheResponse.cacheControl(); - if (responseCaching.immutable()) { - return new CacheStrategy(null, cacheResponse); - } long ageMillis = cacheResponseAge(); long freshMillis = computeFreshnessLifetime(); From 5a316c0b403809558d9a2227a4d8820642ec34f5 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Wed, 7 Nov 2018 21:46:41 +1100 Subject: [PATCH 18/20] Preemptive auth for proxy CONNECT All other forms of preemptive auth are nicely covered by interceptors, but CONNECT doesn't get that luxury. https://github.com/square/okhttp/issues/2435 --- .../src/test/java/okhttp3/CallTest.java | 122 ++++++++++++++++-- .../test/java/okhttp3/ConnectionPoolTest.java | 2 +- .../test/java/okhttp3/EventListenerTest.java | 2 +- .../test/java/okhttp3/URLConnectionTest.java | 15 ++- .../internal/RecordingOkAuthenticator.java | 21 ++- .../internal/http2/HttpOverHttp2Test.java | 2 +- .../src/main/java/okhttp3/Authenticator.java | 59 +++++++-- .../internal/connection/RealConnection.java | 28 +++- 8 files changed, 210 insertions(+), 41 deletions(-) diff --git a/okhttp-tests/src/test/java/okhttp3/CallTest.java b/okhttp-tests/src/test/java/okhttp3/CallTest.java index 4d16cf1fefa3..a58bc879c27b 100644 --- a/okhttp-tests/src/test/java/okhttp3/CallTest.java +++ b/okhttp-tests/src/test/java/okhttp3/CallTest.java @@ -397,7 +397,7 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc String credential = Credentials.basic("jesse", "secret"); client = client.newBuilder() - .authenticator(new RecordingOkAuthenticator(credential)) + .authenticator(new RecordingOkAuthenticator(credential, null)) .build(); Response response = client.newCall(request).execute(); @@ -423,7 +423,7 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc String credential = Credentials.basic("jesse", "secret"); client = client.newBuilder() - .authenticator(new RecordingOkAuthenticator(credential)) + .authenticator(new RecordingOkAuthenticator(credential, null)) .build(); executeSynchronously("/") @@ -438,7 +438,7 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc String credential = Credentials.basic("jesse", "secret"); client = client.newBuilder() - .authenticator(new RecordingOkAuthenticator(credential)) + .authenticator(new RecordingOkAuthenticator(credential, null)) .build(); try { @@ -459,7 +459,7 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc .setResponseCode(401) .setSocketPolicy(SocketPolicy.DISCONNECT_AT_END)); - RecordingOkAuthenticator authenticator = new RecordingOkAuthenticator(null); + RecordingOkAuthenticator authenticator = new RecordingOkAuthenticator(null, null); client = client.newBuilder() .authenticator(authenticator) @@ -1878,7 +1878,7 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc .addHeader("Location: " + server2.url("/b"))); client = client.newBuilder() - .authenticator(new RecordingOkAuthenticator(Credentials.basic("jesse", "secret"))) + .authenticator(new RecordingOkAuthenticator(Credentials.basic("jesse", "secret"), null)) .build(); Request request = new Request.Builder().url(server.url("/a")).build(); @@ -2316,7 +2316,7 @@ private void cancelDuringConnect(String scheme) throws Exception { .setBody(gzip("abcabcabc")) .addHeader("Content-Encoding: gzip")); client = client.newBuilder() - .authenticator(new RecordingOkAuthenticator("password")) + .authenticator(new RecordingOkAuthenticator("password", null)) .build(); executeSynchronously("/").assertBody("abcabcabc"); @@ -2720,7 +2720,7 @@ private void cancelDuringConnect(String scheme) throws Exception { .sslSocketFactory( handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager()) .proxy(server.toProxyAddress()) - .proxyAuthenticator(new RecordingOkAuthenticator("password")) + .proxyAuthenticator(new RecordingOkAuthenticator("password", "Basic")) .hostnameVerifier(new RecordingHostnameVerifier()) .build(); @@ -2753,7 +2753,7 @@ private void cancelDuringConnect(String scheme) throws Exception { client = client.newBuilder() .proxy(server.toProxyAddress()) - .proxyAuthenticator(new RecordingOkAuthenticator("password")) + .proxyAuthenticator(new RecordingOkAuthenticator("password", "Basic")) .build(); Request request = new Request.Builder() @@ -2792,7 +2792,7 @@ private void cancelDuringConnect(String scheme) throws Exception { .sslSocketFactory( handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager()) .proxy(server.toProxyAddress()) - .proxyAuthenticator(new RecordingOkAuthenticator("password")) + .proxyAuthenticator(new RecordingOkAuthenticator("password", "Basic")) .hostnameVerifier(new RecordingHostnameVerifier()) .build(); @@ -2826,7 +2826,7 @@ private void cancelDuringConnect(String scheme) throws Exception { .sslSocketFactory( handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager()) .proxy(server.toProxyAddress()) - .proxyAuthenticator(new RecordingOkAuthenticator("password")) + .proxyAuthenticator(new RecordingOkAuthenticator("password", "Basic")) .hostnameVerifier(new RecordingHostnameVerifier()) .build(); @@ -2845,7 +2845,7 @@ private void cancelDuringConnect(String scheme) throws Exception { * We used to have that behavior but it is problematic because unrelated requests end up sharing * credentials. Worse, that approach leaks proxy credentials to the origin server. */ - @Test public void noProactiveProxyAuthorization() throws Exception { + @Test public void noPreemptiveProxyAuthorization() throws Exception { server.useHttps(handshakeCertificates.sslSocketFactory(), true); server.enqueue(new MockResponse() .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END) @@ -2867,11 +2867,107 @@ private void cancelDuringConnect(String scheme) throws Exception { Response response = client.newCall(request).execute(); assertEquals("response body", response.body().string()); + RecordedRequest connect1 = server.takeRequest(); + assertNull(connect1.getHeader("Proxy-Authorization")); + + RecordedRequest connect2 = server.takeRequest(); + assertEquals("password", connect2.getHeader("Proxy-Authorization")); + } + + /** Confirm that we can send authentication information without being prompted first. */ + @Test public void preemptiveProxyAuthentication() throws Exception { + server.useHttps(handshakeCertificates.sslSocketFactory(), true); + server.enqueue(new MockResponse() + .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END) + .clearHeaders()); + server.enqueue(new MockResponse() + .setBody("encrypted response from the origin server")); + + final String credential = Credentials.basic("jesse", "password1"); + + client = client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager()) + .proxy(server.toProxyAddress()) + .hostnameVerifier(new RecordingHostnameVerifier()) + .proxyAuthenticator(new Authenticator() { + @Override public Request authenticate(Route route, Response response) { + assertEquals("CONNECT", response.request().method()); + assertEquals(HttpURLConnection.HTTP_PROXY_AUTH, response.code()); + assertEquals("android.com", response.request().url().host()); + + List challenges = response.challenges(); + assertEquals("OkHttp-Preemptive", challenges.get(0).scheme()); + + return response.request().newBuilder() + .header("Proxy-Authorization", credential) + .build(); + } + }) + .build(); + + Request request = new Request.Builder() + .url("https://android.com/foo") + .build(); + + executeSynchronously(request).assertSuccessful(); + RecordedRequest connect = server.takeRequest(); - assertNull(connect.getHeader("Proxy-Authorization")); + assertEquals("CONNECT", connect.getMethod()); + assertEquals(credential, connect.getHeader("Proxy-Authorization")); + assertEquals("/", connect.getPath()); RecordedRequest get = server.takeRequest(); - assertEquals("password", get.getHeader("Proxy-Authorization")); + assertEquals("GET", get.getMethod()); + assertNull(get.getHeader("Proxy-Authorization")); + assertEquals("/foo", get.getPath()); + } + + @Test public void preemptiveThenReactiveProxyAuthentication() throws Exception { + server.useHttps(handshakeCertificates.sslSocketFactory(), true); + server.enqueue(new MockResponse() + .setResponseCode(HttpURLConnection.HTTP_PROXY_AUTH) + .addHeader("Proxy-Authenticate", "Basic realm=\"localhost\"") + .setBody("proxy auth required")); + server.enqueue(new MockResponse() + .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END) + .clearHeaders()); + server.enqueue(new MockResponse()); + + final List challengeSchemes = new ArrayList<>(); + final String credential = Credentials.basic("jesse", "password1"); + + client = client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager()) + .proxy(server.toProxyAddress()) + .hostnameVerifier(new RecordingHostnameVerifier()) + .proxyAuthenticator(new Authenticator() { + @Override public Request authenticate(Route route, Response response) { + List challenges = response.challenges(); + challengeSchemes.add(challenges.get(0).scheme()); + return response.request().newBuilder() + .header("Proxy-Authorization", credential) + .build(); + } + }) + .build(); + + Request request = new Request.Builder() + .url("https://android.com/foo") + .build(); + + executeSynchronously(request).assertSuccessful(); + + RecordedRequest connect1 = server.takeRequest(); + assertEquals("CONNECT", connect1.getMethod()); + assertEquals(credential, connect1.getHeader("Proxy-Authorization")); + + RecordedRequest connect2 = server.takeRequest(); + assertEquals("CONNECT", connect2.getMethod()); + assertEquals(credential, connect2.getHeader("Proxy-Authorization")); + + assertEquals(Arrays.asList("OkHttp-Preemptive", "Basic"), challengeSchemes); } @Test public void interceptorGetsHttp2() throws Exception { diff --git a/okhttp-tests/src/test/java/okhttp3/ConnectionPoolTest.java b/okhttp-tests/src/test/java/okhttp3/ConnectionPoolTest.java index ae8b0a2f6c78..d2c778ce655b 100644 --- a/okhttp-tests/src/test/java/okhttp3/ConnectionPoolTest.java +++ b/okhttp-tests/src/test/java/okhttp3/ConnectionPoolTest.java @@ -193,7 +193,7 @@ private RealConnection newConnection(ConnectionPool pool, Route route, long idle private Address newAddress(String name) { return new Address(name, 1, Dns.SYSTEM, SocketFactory.getDefault(), null, null, null, - new RecordingOkAuthenticator("password"), null, Collections.emptyList(), + new RecordingOkAuthenticator("password", null), null, Collections.emptyList(), Collections.emptyList(), ProxySelector.getDefault()); } diff --git a/okhttp-tests/src/test/java/okhttp3/EventListenerTest.java b/okhttp-tests/src/test/java/okhttp3/EventListenerTest.java index 5a9780e7630d..14758e244ce0 100644 --- a/okhttp-tests/src/test/java/okhttp3/EventListenerTest.java +++ b/okhttp-tests/src/test/java/okhttp3/EventListenerTest.java @@ -648,7 +648,7 @@ private Matcher matchesProtocol(final Protocol protocol) { client = client.newBuilder() .proxy(server.toProxyAddress()) - .proxyAuthenticator(new RecordingOkAuthenticator("password")) + .proxyAuthenticator(new RecordingOkAuthenticator("password", "Basic")) .build(); Call call = client.newCall(new Request.Builder() diff --git a/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java b/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java index 1bf5e2b6903a..963f45f333c4 100644 --- a/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java +++ b/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java @@ -1613,7 +1613,7 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc String credential = Credentials.basic("jesse", "secret"); urlFactory.setClient(urlFactory.client().newBuilder() - .authenticator(new RecordingOkAuthenticator(credential)) + .authenticator(new RecordingOkAuthenticator(credential, null)) .build()); connection = urlFactory.open(server.url("/").url()); @@ -2232,7 +2232,7 @@ private void redirectToAnotherOriginServer(boolean https) throws Exception { .addHeader("Location: " + server2.url("/b").url())); urlFactory.setClient(urlFactory.client().newBuilder() - .authenticator(new RecordingOkAuthenticator(Credentials.basic("jesse", "secret"))) + .authenticator(new RecordingOkAuthenticator(Credentials.basic("jesse", "secret"), null)) .build()); assertContent("Page 2", urlFactory.open(server.url("/a").url())); @@ -3179,7 +3179,7 @@ private void reusedConnectionFailsWithPost(TransferKind transferKind, int reques server.enqueue(new MockResponse().setBody("A")); String credential = Credentials.basic("jesse", "peanutbutter"); - RecordingOkAuthenticator authenticator = new RecordingOkAuthenticator(credential); + RecordingOkAuthenticator authenticator = new RecordingOkAuthenticator(credential, null); urlFactory.setClient(urlFactory.client().newBuilder() .authenticator(authenticator) .build()); @@ -3201,7 +3201,8 @@ private void reusedConnectionFailsWithPost(TransferKind transferKind, int reques server.enqueue(pleaseAuthenticate); server.enqueue(new MockResponse().setBody("A")); - RecordingOkAuthenticator authenticator = new RecordingOkAuthenticator("oauthed abc123"); + RecordingOkAuthenticator authenticator + = new RecordingOkAuthenticator("oauthed abc123", "Bearer"); urlFactory.setClient(urlFactory.client().newBuilder() .authenticator(authenticator) .build()); @@ -3225,7 +3226,7 @@ private void reusedConnectionFailsWithPost(TransferKind transferKind, int reques server.enqueue(new MockResponse().setBody("c")); RecordingOkAuthenticator authenticator = new RecordingOkAuthenticator( - Credentials.basic("jesse", "peanutbutter")); + Credentials.basic("jesse", "peanutbutter"), "Basic"); urlFactory.setClient(urlFactory.client().newBuilder() .authenticator(authenticator) .build()); @@ -3246,7 +3247,7 @@ private void reusedConnectionFailsWithPost(TransferKind transferKind, int reques String credential = Credentials.basic("jesse", "peanutbutter"); urlFactory.setClient(urlFactory.client().newBuilder() - .authenticator(new RecordingOkAuthenticator(credential)) + .authenticator(new RecordingOkAuthenticator(credential, null)) .build()); connection = urlFactory.open(server.url("/0").url()); @@ -3260,7 +3261,7 @@ private void reusedConnectionFailsWithPost(TransferKind transferKind, int reques String credential = Credentials.basic("jesse", "peanutbutter"); urlFactory.setClient(urlFactory.client().newBuilder() - .authenticator(new RecordingOkAuthenticator(credential)) + .authenticator(new RecordingOkAuthenticator(credential, null)) .build()); connection = urlFactory.open(server.url("/").url()); diff --git a/okhttp-tests/src/test/java/okhttp3/internal/RecordingOkAuthenticator.java b/okhttp-tests/src/test/java/okhttp3/internal/RecordingOkAuthenticator.java index 2464a910b4c8..126fce4d7e91 100644 --- a/okhttp-tests/src/test/java/okhttp3/internal/RecordingOkAuthenticator.java +++ b/okhttp-tests/src/test/java/okhttp3/internal/RecordingOkAuthenticator.java @@ -18,7 +18,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nullable; import okhttp3.Authenticator; +import okhttp3.Challenge; import okhttp3.Request; import okhttp3.Response; import okhttp3.Route; @@ -26,10 +28,12 @@ public final class RecordingOkAuthenticator implements Authenticator { public final List responses = new ArrayList<>(); public final List routes = new ArrayList<>(); - public final String credential; + public @Nullable String credential; + public @Nullable String scheme; - public RecordingOkAuthenticator(String credential) { + public RecordingOkAuthenticator(@Nullable String credential, @Nullable String scheme) { this.credential = credential; + this.scheme = scheme; } public Response onlyResponse() { @@ -49,10 +53,21 @@ public Route onlyRoute() { responses.add(response); routes.add(route); - if (credential == null) return null; + if (!schemeMatches(response) || credential == null) return null; + String header = response.code() == 407 ? "Proxy-Authorization" : "Authorization"; return response.request().newBuilder() .addHeader(header, credential) .build(); } + + private boolean schemeMatches(Response response) { + if (scheme == null) return true; + + for (Challenge challenge : response.challenges()) { + if (challenge.scheme().equalsIgnoreCase(scheme)) return true; + } + + return false; + } } diff --git a/okhttp-tests/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.java b/okhttp-tests/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.java index 3e4552aed51f..eb0acf496313 100644 --- a/okhttp-tests/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.java +++ b/okhttp-tests/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.java @@ -432,7 +432,7 @@ private void waitForDataFrames(int dataLength) throws Exception { String credential = Credentials.basic("username", "password"); client = client.newBuilder() - .authenticator(new RecordingOkAuthenticator(credential)) + .authenticator(new RecordingOkAuthenticator(credential, "Basic")) .build(); Call call = client.newCall(new Request.Builder() diff --git a/okhttp/src/main/java/okhttp3/Authenticator.java b/okhttp/src/main/java/okhttp3/Authenticator.java index 016d482005b0..10482ffeada4 100644 --- a/okhttp/src/main/java/okhttp3/Authenticator.java +++ b/okhttp/src/main/java/okhttp3/Authenticator.java @@ -19,17 +19,50 @@ import javax.annotation.Nullable; /** - * Responds to an authentication challenge from either a remote web server or a proxy server. - * Implementations may either attempt to satisfy the challenge by returning a request that includes - * an authorization header, or they may refuse the challenge by returning null. In this case the - * unauthenticated response will be returned to the caller that triggered it. + * Performs either preemptive authentication before connecting to a proxy server, + * or reactive authentication after receiving a challenge from either an origin web + * server or proxy server. + * + *

Preemptive Authentication

+ * + *

To make HTTPS calls using an HTTP proxy server OkHttp must first negotiate a connection with + * the proxy. This proxy connection is called a "TLS Tunnel" and is specified by RFC 2817. The HTTP CONNECT request that creates + * this tunnel connection is special: it does not participate in any {@linkplain Interceptor + * interceptors} or {@linkplain EventListener event listeners}. It doesn't include the motivating + * request's HTTP headers or even its full URL; only the target server's hostname is sent to the + * proxy. + * + *

Prior to sending any CONNECT request OkHttp always calls the proxy authenticator so that it + * may prepare preemptive authentication. OkHttp will call {@link #authenticate} with a fake {@code + * HTTP/1.1 407 Proxy Authentication Required} response that has a {@code Proxy-Authenticate: + * OkHttp-Preemptive} challenge. The proxy authenticator may return either either an authenticated + * request, or null to connect without authentication. + *

   {@code
+ *    for (Challenge challenge : response.challenges()) {
+ *      // If this is preemptive auth, use a preemptive credential.
+ *      if (challenge.scheme().equalsIgnoreCase("OkHttp-Preemptive")) {
+ *        return response.request().newBuilder()
+ *            .header("Proxy-Authorization", "secret")
+ *            .build();
+ *      }
+ *    }
+ *
+ *    return null; // Didn't find a preemptive auth scheme.
+ * }
+ * + *

Reactive Authentication

+ * + *

Implementations authenticate by returning a follow-up request that includes an authorization + * header, or they may decline the challenge by returning null. In this case the unauthenticated + * response will be returned to the caller that triggered it. * *

Implementations should check if the initial request already included an attempt to * authenticate. If so it is likely that further attempts will not be useful and the authenticator * should give up. * - *

When authentication is requested by an origin server, the response code is 401 and the - * implementation should respond with a new request that sets the "Authorization" header. + *

When reactive authentication is requested by an origin web server, the response code is 401 + * and the implementation should respond with a new request that sets the "Authorization" header. *

   {@code
  *
  *    if (response.request().header("Authorization") != null) {
@@ -42,7 +75,7 @@
  *        .build();
  * }
* - *

When authentication is requested by a proxy server, the response code is 407 and the + *

When reactive authentication is requested by a proxy server, the response code is 407 and the * implementation should respond with a new request that sets the "Proxy-Authorization" header. *

   {@code
  *
@@ -56,6 +89,9 @@
  *        .build();
  * }
* + *

The proxy authenticator may implement preemptive authentication, reactive authentication, or + * both. + * *

Applications may configure OkHttp with an authenticator for origin servers, or proxy servers, * or both. */ @@ -71,12 +107,9 @@ public interface Authenticator { * Returns a request that includes a credential to satisfy an authentication challenge in {@code * response}. Returns null if the challenge cannot be satisfied. * - * The route is best effort, it currently may not always be provided even when logically - * available. It may also not be provided when an Authenticator is re-used manually in - * an application interceptor, e.g. implementing client specific retries. - * - * @param route The route for evaluating how to respond to a challenge e.g. via intranet. - * @param response The response containing the auth challenges to respond to. + *

The route is best effort, it currently may not always be provided even when logically + * available. It may also not be provided when an authenticator is re-used manually in an + * application interceptor, such as when implementing client-specific retries. */ @Nullable Request authenticate(@Nullable Route route, Response response) throws IOException; } diff --git a/okhttp/src/main/java/okhttp3/internal/connection/RealConnection.java b/okhttp/src/main/java/okhttp3/internal/connection/RealConnection.java index ce089d18646d..25445fac5066 100644 --- a/okhttp/src/main/java/okhttp3/internal/connection/RealConnection.java +++ b/okhttp/src/main/java/okhttp3/internal/connection/RealConnection.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.lang.ref.Reference; import java.net.ConnectException; +import java.net.HttpURLConnection; import java.net.ProtocolException; import java.net.Proxy; import java.net.Socket; @@ -416,14 +417,37 @@ private Request createTunnel(int readTimeout, int writeTimeout, Request tunnelRe * Returns a request that creates a TLS tunnel via an HTTP proxy. Everything in the tunnel request * is sent unencrypted to the proxy server, so tunnels include only the minimum set of headers. * This avoids sending potentially sensitive data like HTTP cookies to the proxy unencrypted. + * + *

In order to support preemptive authentication we pass a fake “Auth Failed” response to the + * authenticator. This gives the authenticator the option to customize the CONNECT request. It can + * decline to do so by returning null, in which case OkHttp will use it as-is */ - private Request createTunnelRequest() { - return new Request.Builder() + private Request createTunnelRequest() throws IOException { + Request proxyConnectRequest = new Request.Builder() .url(route.address().url()) + .method("CONNECT", null) .header("Host", Util.hostHeader(route.address().url(), true)) .header("Proxy-Connection", "Keep-Alive") // For HTTP/1.0 proxies like Squid. .header("User-Agent", Version.userAgent()) .build(); + + Response fakeAuthChallengeResponse = new Response.Builder() + .request(proxyConnectRequest) + .protocol(Protocol.HTTP_1_1) + .code(HttpURLConnection.HTTP_PROXY_AUTH) + .message("Preemptive Authenticate") + .body(Util.EMPTY_RESPONSE) + .sentRequestAtMillis(-1L) + .receivedResponseAtMillis(-1L) + .header("Proxy-Authenticate", "OkHttp-Preemptive") + .build(); + + Request authenticatedRequest = route.address().proxyAuthenticator() + .authenticate(route, fakeAuthChallengeResponse); + + return authenticatedRequest != null + ? authenticatedRequest + : proxyConnectRequest; } /** From ef34a41d09fbcc8e03c179cb9b121c918f671f88 Mon Sep 17 00:00:00 2001 From: Amir Livneh Date: Tue, 13 Nov 2018 21:58:22 -0500 Subject: [PATCH 19/20] Add a LoggingEventListener and use it in okcurl (#4353) * Add LoggingEventListener and use it in okcurl * Fix tests failing in IP6 environment * Make less assumptions about test environment * Disable retry in test to make test sequence more predictable * Fix javadoc compilation There seems to be inconsistency between javdoc parsing between 'mvn verify' and Travis CI. Before the change, 'mvn clean verify' passes but Travis CI fails due to missing import of okhttp3.OkHttpClient. Just adding the missing import, causes 'mvn verify' to fail die to unused import. Changing the line wrapping seems to appease 'mvn verify'. * Address comments * Remove unused imports --- okcurl/pom.xml | 5 + okcurl/src/main/java/okhttp3/curl/Main.java | 17 ++ .../okhttp3/logging/LoggingEventListener.java | 178 ++++++++++++++ .../logging/HttpLoggingInterceptorTest.java | 2 +- .../logging/LoggingEventListenerTest.java | 229 ++++++++++++++++++ 5 files changed, 430 insertions(+), 1 deletion(-) create mode 100644 okhttp-logging-interceptor/src/main/java/okhttp3/logging/LoggingEventListener.java create mode 100644 okhttp-logging-interceptor/src/test/java/okhttp3/logging/LoggingEventListenerTest.java diff --git a/okcurl/pom.xml b/okcurl/pom.xml index 6d1cc5c69703..c8a93b7307d7 100644 --- a/okcurl/pom.xml +++ b/okcurl/pom.xml @@ -18,6 +18,11 @@ okhttp ${project.version} + + ${project.groupId} + logging-interceptor + ${project.version} + ${project.groupId} okhttp-testing-support diff --git a/okcurl/src/main/java/okhttp3/curl/Main.java b/okcurl/src/main/java/okhttp3/curl/Main.java index cee260061974..4b1fd210871e 100644 --- a/okcurl/src/main/java/okhttp3/curl/Main.java +++ b/okcurl/src/main/java/okhttp3/curl/Main.java @@ -48,6 +48,8 @@ import okhttp3.internal.http.StatusLine; import okhttp3.internal.http2.Http2; import okhttp3.internal.platform.Platform; +import okhttp3.logging.HttpLoggingInterceptor; +import okhttp3.logging.LoggingEventListener; import okio.BufferedSource; import okio.Okio; import okio.Sink; @@ -121,6 +123,11 @@ private static String protocols() { @Option(name = {"-V", "--version"}, description = "Show version number and quit") public boolean version; + @Option( + name = {"-v", "--verbose"}, + description = "Makes " + NAME + " verbose during the operation") + public boolean verbose; + @Arguments(title = "url", description = "Remote resource URL") public String url; @@ -184,6 +191,16 @@ private OkHttpClient createClient() { builder.sslSocketFactory(sslSocketFactory, trustManager); builder.hostnameVerifier(createInsecureHostnameVerifier()); } + if (verbose) { + HttpLoggingInterceptor.Logger logger = + new HttpLoggingInterceptor.Logger() { + @Override + public void log(String message) { + System.out.println(message); + } + }; + builder.eventListenerFactory(new LoggingEventListener.Factory(logger)); + } return builder.build(); } diff --git a/okhttp-logging-interceptor/src/main/java/okhttp3/logging/LoggingEventListener.java b/okhttp-logging-interceptor/src/main/java/okhttp3/logging/LoggingEventListener.java new file mode 100644 index 000000000000..cc5adde48e9a --- /dev/null +++ b/okhttp-logging-interceptor/src/main/java/okhttp3/logging/LoggingEventListener.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2018 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. + */ +package okhttp3.logging; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.util.List; +import java.util.concurrent.TimeUnit; +import javax.annotation.Nullable; +import okhttp3.Call; +import okhttp3.Connection; +import okhttp3.EventListener; +import okhttp3.Handshake; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; + +/** + * An OkHttp EventListener, which logs call events. Can be applied as an + * {@linkplain OkHttpClient#eventListenerFactory() event listener factory}. + * + *

The format of the logs created by this class should not be considered stable and may change + * slightly between releases. If you need a stable logging format, use your own event listener. + */ +public final class LoggingEventListener extends EventListener { + private final HttpLoggingInterceptor.Logger logger; + private long startNs; + + private LoggingEventListener(HttpLoggingInterceptor.Logger logger) { + this.logger = logger; + } + + @Override + public void callStart(Call call) { + startNs = System.nanoTime(); + + logWithTime("callStart: " + call.request()); + } + + @Override + public void dnsStart(Call call, String domainName) { + logWithTime("dnsStart: " + domainName); + } + + @Override + public void dnsEnd(Call call, String domainName, List inetAddressList) { + logWithTime("dnsEnd: " + inetAddressList); + } + + @Override + public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) { + logWithTime("connectStart: " + inetSocketAddress + " " + proxy); + } + + @Override + public void secureConnectStart(Call call) { + logWithTime("secureConnectStart"); + } + + @Override + public void secureConnectEnd(Call call, @Nullable Handshake handshake) { + logWithTime("secureConnectEnd"); + } + + @Override + public void connectEnd( + Call call, InetSocketAddress inetSocketAddress, Proxy proxy, @Nullable Protocol protocol) { + logWithTime("connectEnd: " + protocol); + } + + @Override + public void connectFailed( + Call call, + InetSocketAddress inetSocketAddress, + Proxy proxy, + @Nullable Protocol protocol, + IOException ioe) { + logWithTime("connectFailed: " + protocol + " " + ioe); + } + + @Override + public void connectionAcquired(Call call, Connection connection) { + logWithTime("connectionAcquired: " + connection); + } + + @Override + public void connectionReleased(Call call, Connection connection) { + logWithTime("connectionReleased"); + } + + @Override + public void requestHeadersStart(Call call) { + logWithTime("requestHeadersStart"); + } + + @Override + public void requestHeadersEnd(Call call, Request request) { + logWithTime("requestHeadersEnd"); + } + + @Override + public void requestBodyStart(Call call) { + logWithTime("requestBodyStart"); + } + + @Override + public void requestBodyEnd(Call call, long byteCount) { + logWithTime("requestBodyEnd: byteCount=" + byteCount); + } + + @Override + public void responseHeadersStart(Call call) { + logWithTime("responseHeadersStart"); + } + + @Override + public void responseHeadersEnd(Call call, Response response) { + logWithTime("responseHeadersEnd: " + response); + } + + @Override + public void responseBodyStart(Call call) { + logWithTime("responseBodyStart"); + } + + @Override + public void responseBodyEnd(Call call, long byteCount) { + logWithTime("responseBodyEnd: byteCount=" + byteCount); + } + + @Override + public void callEnd(Call call) { + logWithTime("callEnd"); + } + + @Override + public void callFailed(Call call, IOException ioe) { + logWithTime("callFailed: " + ioe); + } + + private void logWithTime(String message) { + long timeMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); + logger.log("[" + timeMs + " ms] " + message); + } + + public static class Factory implements EventListener.Factory { + private final HttpLoggingInterceptor.Logger logger; + + public Factory() { + this(HttpLoggingInterceptor.Logger.DEFAULT); + } + + public Factory(HttpLoggingInterceptor.Logger logger) { + this.logger = logger; + } + + @Override + public EventListener create(Call call) { + return new LoggingEventListener(logger); + } + } +} diff --git a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.java b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.java index b2acd9051ac0..48e86ab9cda3 100644 --- a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.java +++ b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.java @@ -807,7 +807,7 @@ private Request.Builder request() { return new Request.Builder().url(url); } - private static class LogRecorder implements HttpLoggingInterceptor.Logger { + static class LogRecorder implements HttpLoggingInterceptor.Logger { private final List logs = new ArrayList<>(); private int index; diff --git a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/LoggingEventListenerTest.java b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/LoggingEventListenerTest.java new file mode 100644 index 000000000000..0f0ea2bd715e --- /dev/null +++ b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/LoggingEventListenerTest.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2018 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. + */ +package okhttp3.logging; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; +import okhttp3.Dns; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.SocketPolicy; +import okhttp3.tls.HandshakeCertificates; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import static okhttp3.tls.internal.TlsUtil.localhost; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +public final class LoggingEventListenerTest { + private static final MediaType PLAIN = MediaType.get("text/plain"); + + @Rule public final MockWebServer server = new MockWebServer(); + + private final HandshakeCertificates handshakeCertificates = localhost(); + private final LogRecorder logRecorder = new LogRecorder(); + private final LoggingEventListener.Factory loggingEventListenerFactory = + new LoggingEventListener.Factory(logRecorder); + private OkHttpClient client; + private HttpUrl url; + + @Before + public void setUp() { + client = + new OkHttpClient.Builder() + .eventListenerFactory(loggingEventListenerFactory) + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager()) + .retryOnConnectionFailure(false) + .build(); + + url = server.url("/"); + } + + @Test + public void get() throws Exception { + server.enqueue(new MockResponse().setBody("Hello!").setHeader("Content-Type", PLAIN)); + Response response = client.newCall(request().build()).execute(); + assertNotNull(response.body()); + response.body().bytes(); + + logRecorder + .assertLogMatch("callStart: Request\\{method=GET, url=" + url + ", tags=\\{\\}\\}") + .assertLogMatch("dnsStart: " + url.host()) + .assertLogMatch("dnsEnd: \\[.+\\]") + .assertLogMatch("connectStart: " + url.host() + "/.+ DIRECT") + .assertLogMatch("connectEnd: http/1.1") + .assertLogMatch( + "connectionAcquired: Connection\\{" + + url.host() + + ":\\d+, proxy=DIRECT hostAddress=" + + url.host() + + "/.+ cipherSuite=none protocol=http/1\\.1\\}") + .assertLogMatch("requestHeadersStart") + .assertLogMatch("requestHeadersEnd") + .assertLogMatch("responseHeadersStart") + .assertLogMatch( + "responseHeadersEnd: Response\\{protocol=http/1\\.1, code=200, message=OK, url=" + + url + + "}") + .assertLogMatch("responseBodyStart") + .assertLogMatch("responseBodyEnd: byteCount=6") + .assertLogMatch("connectionReleased") + .assertLogMatch("callEnd") + .assertNoMoreLogs(); + } + + @Test + public void post() throws IOException { + server.enqueue(new MockResponse()); + client.newCall(request().post(RequestBody.create(PLAIN, "Hello!")).build()).execute(); + + logRecorder + .assertLogMatch("callStart: Request\\{method=POST, url=" + url + ", tags=\\{\\}\\}") + .assertLogMatch("dnsStart: " + url.host()) + .assertLogMatch("dnsEnd: \\[.+\\]") + .assertLogMatch("connectStart: " + url.host() + "/.+ DIRECT") + .assertLogMatch("connectEnd: http/1.1") + .assertLogMatch( + "connectionAcquired: Connection\\{" + + url.host() + + ":\\d+, proxy=DIRECT hostAddress=" + + url.host() + + "/.+ cipherSuite=none protocol=http/1\\.1\\}") + .assertLogMatch("requestHeadersStart") + .assertLogMatch("requestHeadersEnd") + .assertLogMatch("requestBodyStart") + .assertLogMatch("requestBodyEnd: byteCount=6") + .assertLogMatch("responseHeadersStart") + .assertLogMatch( + "responseHeadersEnd: Response\\{protocol=http/1\\.1, code=200, message=OK, url=" + + url + + "}") + .assertLogMatch("responseBodyStart") + .assertLogMatch("responseBodyEnd: byteCount=0") + .assertLogMatch("connectionReleased") + .assertLogMatch("callEnd") + .assertNoMoreLogs(); + } + + @Test + public void secureGet() throws Exception { + server.useHttps(handshakeCertificates.sslSocketFactory(), false); + url = server.url("/"); + + server.enqueue(new MockResponse()); + Response response = client.newCall(request().build()).execute(); + assertNotNull(response.body()); + response.body().bytes(); + + logRecorder + .assertLogMatch("callStart: Request\\{method=GET, url=" + url + ", tags=\\{\\}\\}") + .assertLogMatch("dnsStart: " + url.host()) + .assertLogMatch("dnsEnd: \\[.+\\]") + .assertLogMatch("connectStart: " + url.host() + "/.+ DIRECT") + .assertLogMatch("secureConnectStart") + .assertLogMatch("secureConnectEnd") + .assertLogMatch("connectEnd: h2") + .assertLogMatch( + "connectionAcquired: Connection\\{" + + url.host() + + ":\\d+, proxy=DIRECT hostAddress=" + + url.host() + + "/.+ cipherSuite=.+ protocol=h2}") + .assertLogMatch("requestHeadersStart") + .assertLogMatch("requestHeadersEnd") + .assertLogMatch("responseHeadersStart") + .assertLogMatch( + "responseHeadersEnd: Response\\{protocol=h2, code=200, message=, url=" + url + "}") + .assertLogMatch("responseBodyStart") + .assertLogMatch("responseBodyEnd: byteCount=0") + .assertLogMatch("connectionReleased") + .assertLogMatch("callEnd") + .assertNoMoreLogs(); + } + + @Test + public void dnsFail() throws IOException { + client = + new OkHttpClient.Builder() + .dns( + new Dns() { + @Override + public List lookup(String hostname) throws UnknownHostException { + throw new UnknownHostException("reason"); + } + }) + .eventListenerFactory(loggingEventListenerFactory) + .build(); + + try { + client.newCall(request().build()).execute(); + fail(); + } catch (UnknownHostException expected) { + } + + logRecorder + .assertLogMatch("callStart: Request\\{method=GET, url=" + url + ", tags=\\{\\}\\}") + .assertLogMatch("dnsStart: " + url.host()) + .assertLogMatch("callFailed: java.net.UnknownHostException: reason") + .assertNoMoreLogs(); + } + + @Test + public void connectFail() { + server.useHttps(handshakeCertificates.sslSocketFactory(), false); + server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE)); + url = server.url("/"); + + try { + client.newCall(request().build()).execute(); + fail(); + } catch (IOException expected) { + } + + logRecorder + .assertLogMatch("callStart: Request\\{method=GET, url=" + url + ", tags=\\{\\}\\}") + .assertLogMatch("dnsStart: " + url.host()) + .assertLogMatch("dnsEnd: \\[.+\\]") + .assertLogMatch("connectStart: " + url.host() + "/.+ DIRECT") + .assertLogMatch("secureConnectStart") + .assertLogMatch( + "connectFailed: null javax\\.net\\.ssl\\.SSLProtocolException: Handshake message sequence violation, 1") + .assertLogMatch( + "callFailed: javax.net.ssl.SSLProtocolException: Handshake message sequence violation, 1") + .assertNoMoreLogs(); + } + + private Request.Builder request() { + return new Request.Builder().url(url); + } + + private static class LogRecorder extends HttpLoggingInterceptorTest.LogRecorder { + LogRecorder assertLogMatch(String pattern) { + return (LogRecorder) super.assertLogMatch("\\[\\d+ ms] " + pattern); + } + } +} From 1f7e796e6e658df34a98276b2092a81de118937d Mon Sep 17 00:00:00 2001 From: Amir Livneh Date: Wed, 14 Nov 2018 23:29:45 -0500 Subject: [PATCH 20/20] Cleanup HttpLoggingInterceptor (#4346) * Use try-with-resources * Make bodyHasUnknownEncoding() static * Fix nits in HttpLoggingInterceptorTest * Revert "Use try-with-resources" This reverts commit 57dcd61a9e0a22086bd3291a868258ee23ec4116. --- .../main/java/okhttp3/logging/HttpLoggingInterceptor.java | 2 +- .../java/okhttp3/logging/HttpLoggingInterceptorTest.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/okhttp-logging-interceptor/src/main/java/okhttp3/logging/HttpLoggingInterceptor.java b/okhttp-logging-interceptor/src/main/java/okhttp3/logging/HttpLoggingInterceptor.java index 448b08edd57c..c6acbccf1ebc 100644 --- a/okhttp-logging-interceptor/src/main/java/okhttp3/logging/HttpLoggingInterceptor.java +++ b/okhttp-logging-interceptor/src/main/java/okhttp3/logging/HttpLoggingInterceptor.java @@ -326,7 +326,7 @@ static boolean isPlaintext(Buffer buffer) { } } - private boolean bodyHasUnknownEncoding(Headers headers) { + private static boolean bodyHasUnknownEncoding(Headers headers) { String contentEncoding = headers.get("Content-Encoding"); return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity") diff --git a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.java b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.java index 48e86ab9cda3..6fd53f7753ee 100644 --- a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.java +++ b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.java @@ -59,8 +59,8 @@ public final class HttpLoggingInterceptorTest { @Rule public final MockWebServer server = new MockWebServer(); - private HandshakeCertificates handshakeCertificates = localhost(); - private HostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); + private final HandshakeCertificates handshakeCertificates = localhost(); + private final HostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); private OkHttpClient client; private String host; private HttpUrl url; @@ -650,7 +650,7 @@ private void bodyGetNoBody(int code) throws IOException { .assertNoMoreLogs(); } - @Test public void isPlaintext() throws IOException { + @Test public void isPlaintext() { assertTrue(HttpLoggingInterceptor.isPlaintext(new Buffer())); assertTrue(HttpLoggingInterceptor.isPlaintext(new Buffer().writeUtf8("abc"))); assertTrue(HttpLoggingInterceptor.isPlaintext(new Buffer().writeUtf8("new\r\nlines")));