public void logCloseableLeak(String message, Object stackTrace) { if (stackTrace == null) { message += " To see where this was allocated, set the OkHttpClient logger level to FINE: " + "Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);"; } log(WARN, message, (Throwable) stackTrace); }
public void logCloseableLeak(String message, Object stackTrace) { if (stackTrace == null) { message += " To see where this was allocated, set the OkHttpClient logger level to FINE: " + "Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);"; } log(WARN, message, (Throwable) stackTrace); }
@Override public @Nullable String getSelectedProtocol(SSLSocket socket) { try { AlpnProvider provider = (AlpnProvider) Proxy.getInvocationHandler(getMethod.invoke(null, socket)); if (!provider.unsupported && provider.selected == null) { Platform.get().log(INFO, "ALPN callback dropped: HTTP/2 is disabled. " + "Is alpn-boot on the boot class path?", null); return null; } return provider.unsupported ? null : provider.selected; } catch (InvocationTargetException | IllegalAccessException e) { throw new AssertionError("failed to get ALPN selected protocol", e); } }
@Override public void setRequestProperty(String field, String newValue) { if (connected) { throw new IllegalStateException("Cannot set request property after connection is made"); } if (field == null) { throw new NullPointerException("field == null"); } if (newValue == null) { // Silently ignore null header values for backwards compatibility with older // android versions as well as with other URLConnection implementations. // // Some implementations send a malformed HTTP header when faced with // such requests, we respect the spec and ignore the header. Platform.get().log(WARN, "Ignoring header " + field + " because its value was null.", null); return; } requestHeaders.set(field, newValue); }
@Override public void addRequestProperty(String field, String value) { if (connected) { throw new IllegalStateException("Cannot add request property after connection is made"); } if (field == null) { throw new NullPointerException("field == null"); } if (value == null) { // Silently ignore null header values for backwards compatibility with older // android versions as well as with other URLConnection implementations. // // Some implementations send a malformed HTTP header when faced with // such requests, we respect the spec and ignore the header. Platform.get().log(WARN, "Ignoring header " + field + " because its value was null.", null); return; } requestHeaders.add(field, value); }
/** * Reads the public suffix list treating the operation as uninterruptible. We always want to read * the list otherwise we'll be left in a bad state. If the thread was interrupted prior to this * operation, it will be re-interrupted after the list is read. */ private void readTheListUninterruptibly() { boolean interrupted = false; try { while (true) { try { readTheList(); return; } catch (InterruptedIOException e) { Thread.interrupted(); // Temporarily clear the interrupted state. interrupted = true; } catch (IOException e) { Platform.get().log(Platform.WARN, "Failed to read public suffix list", e); return; } } } finally { if (interrupted) { Thread.currentThread().interrupt(); // Retain interrupted status. } } }
@Override public void log(String message) { Platform.get().log(INFO, message, null); } };
@Override public List<Cookie> loadForRequest(HttpUrl url) { // The RI passes all headers. We don't have 'em, so we don't pass 'em! Map<String, List<String>> headers = Collections.emptyMap(); Map<String, List<String>> cookieHeaders; try { cookieHeaders = cookieHandler.get(url.uri(), headers); } catch (IOException e) { Platform.get().log(WARN, "Loading cookies failed for " + url.resolve("/..."), e); return Collections.emptyList(); } List<Cookie> cookies = null; for (Map.Entry<String, List<String>> entry : cookieHeaders.entrySet()) { String key = entry.getKey(); if (("Cookie".equalsIgnoreCase(key) || "Cookie2".equalsIgnoreCase(key)) && !entry.getValue().isEmpty()) { for (String header : entry.getValue()) { if (cookies == null) cookies = new ArrayList<>(); cookies.addAll(decodeHeaderAsJavaNetCookies(url, header)); } } } return cookies != null ? Collections.unmodifiableList(cookies) : Collections.emptyList(); }
@Override public @Nullable String getSelectedProtocol(SSLSocket socket) { try { AlpnProvider provider = (AlpnProvider) Proxy.getInvocationHandler(getMethod.invoke(null, socket)); if (!provider.unsupported && provider.selected == null) { Platform.get().log(INFO, "ALPN callback dropped: HTTP/2 is disabled. " + "Is alpn-boot on the boot class path?", null); return null; } return provider.unsupported ? null : provider.selected; } catch (InvocationTargetException | IllegalAccessException e) { throw new AssertionError("failed to get ALPN selected protocol", e); } }
@Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) { if (cookieHandler != null) { List<String> cookieStrings = new ArrayList<>(); for (Cookie cookie : cookies) { cookieStrings.add(cookie.toString(true)); } Map<String, List<String>> multimap = Collections.singletonMap("Set-Cookie", cookieStrings); try { cookieHandler.put(url.uri(), multimap); } catch (IOException e) { Platform.get().log(WARN, "Saving cookies failed for " + url.resolve("/..."), e); } } }
@Override public void execute() { try { listener.onStream(newStream); } catch (IOException e) { Platform.get().log( INFO, "Http2Connection.Listener failure for " + connectionName, e); try { newStream.close(ErrorCode.PROTOCOL_ERROR); } catch (IOException ignored) { } } } });
private List<InetAddress> readResponse(String hostname, Response response) throws Exception { if (response.cacheResponse() == null && response.protocol() != Protocol.HTTP_2) { Platform.get().log(Platform.WARN, "Incorrect protocol: " + response.protocol(), null); } try { if (!response.isSuccessful()) { throw new IOException("response: " + response.code() + " " + response.message()); } ResponseBody body = response.body(); if (body.contentLength() > MAX_RESPONSE_SIZE) { throw new IOException("response size exceeds limit (" + MAX_RESPONSE_SIZE + " bytes): " + body.contentLength() + " bytes"); } ByteString responseBytes = body.source().readByteString(); return DnsRecordCodec.decodeAnswers(hostname, responseBytes); } finally { response.close(); } }
/** * Reads the public suffix list treating the operation as uninterruptible. We always want to read * the list otherwise we'll be left in a bad state. If the thread was interrupted prior to this * operation, it will be re-interrupted after the list is read. */ private void readTheListUninterruptibly() { boolean interrupted = false; try { while (true) { try { readTheList(); return; } catch (InterruptedIOException e) { Thread.interrupted(); // Temporarily clear the interrupted state. interrupted = true; } catch (IOException e) { Platform.get().log(Platform.WARN, "Failed to read public suffix list", e); return; } } } finally { if (interrupted) { Thread.currentThread().interrupt(); // Retain interrupted status. } } }
@Override public void execute() { try { listener.onStream(newStream); } catch (IOException e) { Platform.get().log( INFO, "Http2Connection.Listener failure for " + connectionName, e); try { newStream.close(ErrorCode.PROTOCOL_ERROR); } catch (IOException ignored) { } } } });
return; } catch (IOException journalIsCorrupt) { Platform.get().log(WARN, "DiskLruCache " + directory + " is corrupt: " + journalIsCorrupt.getMessage() + ", removing", journalIsCorrupt);
@Override protected void execute() { boolean signalledCallback = false; timeout.enter(); try { Response response = getResponseWithInterceptorChain(); if (retryAndFollowUpInterceptor.isCanceled()) { signalledCallback = true; responseCallback.onFailure(RealCall.this, new IOException("Canceled")); } else { signalledCallback = true; 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); } else { eventListener.callFailed(RealCall.this, e); responseCallback.onFailure(RealCall.this, e); } } finally { client.dispatcher().finished(this); } } }
return; } catch (IOException journalIsCorrupt) { Platform.get().log(WARN, "DiskLruCache " + directory + " is corrupt: " + journalIsCorrupt.getMessage() + ", removing", journalIsCorrupt);
@Override protected void execute() { boolean signalledCallback = false; timeout.enter(); try { Response response = getResponseWithInterceptorChain(); if (retryAndFollowUpInterceptor.isCanceled()) { signalledCallback = true; responseCallback.onFailure(RealCall.this, new IOException("Canceled")); } else { signalledCallback = true; 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); } else { eventListener.callFailed(RealCall.this, e); responseCallback.onFailure(RealCall.this, e); } } finally { client.dispatcher().finished(this); } } }
@Override public void onMessage(WebSocket webSocket, ByteString bytes) { Platform.get().log(Platform.INFO, "[WS " + name + "] onMessage", null); WebSocketListener delegate = this.delegate; if (delegate != null) { this.delegate = null; delegate.onMessage(webSocket, bytes); } else { Message event = new Message(bytes); events.add(event); } }
@Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { Platform.get().log(Platform.INFO, "[WS " + name + "] onFailure", t); WebSocketListener delegate = this.delegate; if (delegate != null) { this.delegate = null; delegate.onFailure(webSocket, t, response); } else { events.add(new Failure(t, response)); } }