All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.grpc.okhttp.ExceptionHandlingFrameWriter Maven / Gradle / Ivy

There is a newer version: 1.68.1
Show newest version
/*
 * Copyright 2018 The gRPC Authors
 *
 * 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 io.grpc.okhttp;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import io.grpc.okhttp.internal.framed.ErrorCode;
import io.grpc.okhttp.internal.framed.FrameWriter;
import io.grpc.okhttp.internal.framed.Header;
import io.grpc.okhttp.internal.framed.Settings;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import okio.Buffer;
import okio.ByteString;

/**
 * FrameWriter that propagates IOExceptions via callback instead of throwing. This allows
 * centralized handling of errors. Exceptions only impact the single call that throws them; callers
 * should be sure to kill the connection after an exception (potentially after sending a GOAWAY) as
 * otherwise additional frames after the failed/omitted one could cause HTTP/2 confusion.
 */
final class ExceptionHandlingFrameWriter implements FrameWriter {

  private static final Logger log = Logger.getLogger(OkHttpClientTransport.class.getName());

  private final TransportExceptionHandler transportExceptionHandler;

  private final FrameWriter frameWriter;

  private final OkHttpFrameLogger frameLogger =
      new OkHttpFrameLogger(Level.FINE, OkHttpClientTransport.class);

  ExceptionHandlingFrameWriter(
      TransportExceptionHandler transportExceptionHandler, FrameWriter frameWriter) {
    this.transportExceptionHandler =
        checkNotNull(transportExceptionHandler, "transportExceptionHandler");
    this.frameWriter = Preconditions.checkNotNull(frameWriter, "frameWriter");
  }

  @Override
  public void connectionPreface() {
    try {
      frameWriter.connectionPreface();
    } catch (IOException e) {
      transportExceptionHandler.onException(e);
    }
  }

  @Override
  public void ackSettings(Settings peerSettings) {
    frameLogger.logSettingsAck(OkHttpFrameLogger.Direction.OUTBOUND);
    try {
      frameWriter.ackSettings(peerSettings);
    } catch (IOException e) {
      transportExceptionHandler.onException(e);
    }
  }

  @Override
  public void pushPromise(int streamId, int promisedStreamId, List
requestHeaders) { frameLogger.logPushPromise(OkHttpFrameLogger.Direction.OUTBOUND, streamId, promisedStreamId, requestHeaders); try { frameWriter.pushPromise(streamId, promisedStreamId, requestHeaders); } catch (IOException e) { transportExceptionHandler.onException(e); } } @Override public void flush() { try { frameWriter.flush(); } catch (IOException e) { transportExceptionHandler.onException(e); } } @Override public void synStream( boolean outFinished, boolean inFinished, int streamId, int associatedStreamId, List
headerBlock) { try { frameWriter.synStream(outFinished, inFinished, streamId, associatedStreamId, headerBlock); } catch (IOException e) { transportExceptionHandler.onException(e); } } @Override public void synReply(boolean outFinished, int streamId, List
headerBlock) { try { frameWriter.synReply(outFinished, streamId, headerBlock); } catch (IOException e) { transportExceptionHandler.onException(e); } } @Override public void headers(int streamId, List
headerBlock) { frameLogger.logHeaders(OkHttpFrameLogger.Direction.OUTBOUND, streamId, headerBlock, false); try { frameWriter.headers(streamId, headerBlock); } catch (IOException e) { transportExceptionHandler.onException(e); } } @Override public void rstStream(int streamId, ErrorCode errorCode) { frameLogger.logRstStream(OkHttpFrameLogger.Direction.OUTBOUND, streamId, errorCode); try { frameWriter.rstStream(streamId, errorCode); } catch (IOException e) { transportExceptionHandler.onException(e); } } @Override public int maxDataLength() { return frameWriter.maxDataLength(); } @Override public void data(boolean outFinished, int streamId, Buffer source, int byteCount) { frameLogger.logData(OkHttpFrameLogger.Direction.OUTBOUND, streamId, source.buffer(), byteCount, outFinished); try { frameWriter.data(outFinished, streamId, source, byteCount); } catch (IOException e) { transportExceptionHandler.onException(e); } } @Override public void settings(Settings okHttpSettings) { frameLogger.logSettings(OkHttpFrameLogger.Direction.OUTBOUND, okHttpSettings); try { frameWriter.settings(okHttpSettings); } catch (IOException e) { transportExceptionHandler.onException(e); } } @Override public void ping(boolean ack, int payload1, int payload2) { if (ack) { frameLogger.logPingAck(OkHttpFrameLogger.Direction.OUTBOUND, ((long) payload1 << 32) | (payload2 & 0xFFFFFFFFL)); } else { frameLogger.logPing(OkHttpFrameLogger.Direction.OUTBOUND, ((long) payload1 << 32) | (payload2 & 0xFFFFFFFFL)); } try { frameWriter.ping(ack, payload1, payload2); } catch (IOException e) { transportExceptionHandler.onException(e); } } @Override public void goAway(int lastGoodStreamId, ErrorCode errorCode, byte[] debugData) { frameLogger.logGoAway(OkHttpFrameLogger.Direction.OUTBOUND, lastGoodStreamId, errorCode, ByteString.of(debugData)); try { frameWriter.goAway(lastGoodStreamId, errorCode, debugData); // Flush it since after goAway, we are likely to close this writer. frameWriter.flush(); } catch (IOException e) { transportExceptionHandler.onException(e); } } @Override public void windowUpdate(int streamId, long windowSizeIncrement) { frameLogger.logWindowsUpdate(OkHttpFrameLogger.Direction.OUTBOUND, streamId, windowSizeIncrement); try { frameWriter.windowUpdate(streamId, windowSizeIncrement); } catch (IOException e) { transportExceptionHandler.onException(e); } } @Override public void close() { try { frameWriter.close(); } catch (IOException e) { log.log(getLogLevel(e), "Failed closing connection", e); } } /** * Accepts a throwable and returns the appropriate logging level. Uninteresting exceptions * should not clutter the log. */ @VisibleForTesting static Level getLogLevel(Throwable t) { if (t.getClass().equals(IOException.class)) { return Level.FINE; } return Level.INFO; } /** A class that handles transport exception. */ interface TransportExceptionHandler { /** Handles exception. */ void onException(Throwable throwable); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy