use of io.netty.handler.codec.http2.Http2Headers in project grpc-java by grpc.
the class NettyClientHandler method createStream.
/**
* Attempts to create a new stream from the given command. If there are too many active streams,
* the creation request is queued.
*/
private void createStream(CreateStreamCommand command, ChannelPromise promise) throws Exception {
if (lifecycleManager.getShutdownThrowable() != null) {
command.stream().setNonExistent();
// The connection is going away (it is really the GOAWAY case),
// just terminate the stream now.
command.stream().transportReportStatus(lifecycleManager.getShutdownStatus(), RpcProgress.MISCARRIED, true, new Metadata());
promise.setFailure(lifecycleManager.getShutdownThrowable());
return;
}
// Get the stream ID for the new stream.
int streamId;
try {
streamId = incrementAndGetNextStreamId();
} catch (StatusException e) {
command.stream().setNonExistent();
// Stream IDs have been exhausted for this connection. Fail the promise immediately.
promise.setFailure(e);
// Initiate a graceful shutdown if we haven't already.
if (!connection().goAwaySent()) {
logger.fine("Stream IDs have been exhausted for this connection. " + "Initiating graceful shutdown of the connection.");
lifecycleManager.notifyShutdown(e.getStatus());
close(ctx(), ctx().newPromise());
}
return;
}
if (connection().goAwayReceived()) {
Status s = abruptGoAwayStatus;
int maxActiveStreams = connection().local().maxActiveStreams();
int lastStreamId = connection().local().lastStreamKnownByPeer();
if (s == null) {
// Should be impossible, but handle pseudo-gracefully
s = Status.INTERNAL.withDescription("Failed due to abrupt GOAWAY, but can't find GOAWAY details");
} else if (streamId > lastStreamId) {
s = s.augmentDescription("stream id: " + streamId + ", GOAWAY Last-Stream-ID:" + lastStreamId);
} else if (connection().local().numActiveStreams() == maxActiveStreams) {
s = s.augmentDescription("At MAX_CONCURRENT_STREAMS limit. limit: " + maxActiveStreams);
}
if (streamId > lastStreamId || connection().local().numActiveStreams() == maxActiveStreams) {
// This should only be reachable during onGoAwayReceived, as otherwise
// getShutdownThrowable() != null
command.stream().setNonExistent();
command.stream().transportReportStatus(s, RpcProgress.MISCARRIED, true, new Metadata());
promise.setFailure(s.asRuntimeException());
return;
}
}
NettyClientStream.TransportState stream = command.stream();
Http2Headers headers = command.headers();
stream.setId(streamId);
PerfMark.startTask("NettyClientHandler.createStream", stream.tag());
PerfMark.linkIn(command.getLink());
try {
createStreamTraced(streamId, stream, headers, command.isGet(), command.shouldBeCountedForInUse(), promise);
} finally {
PerfMark.stopTask("NettyClientHandler.createStream", stream.tag());
}
}
use of io.netty.handler.codec.http2.Http2Headers in project grpc-java by grpc.
the class NettyClientStreamTest method inboundHeadersShouldCallListenerHeadersRead.
@Test
public void inboundHeadersShouldCallListenerHeadersRead() throws Exception {
stream().transportState().setId(STREAM_ID);
Http2Headers headers = grpcResponseHeaders();
stream().transportState().transportHeadersReceived(headers, false);
verify(listener).headersRead(any(Metadata.class));
}
use of io.netty.handler.codec.http2.Http2Headers in project grpc-java by grpc.
the class NettyClientStreamTest method invalidInboundContentTypeShouldCancelStream.
@Test
public void invalidInboundContentTypeShouldCancelStream() {
// Set stream id to indicate it has been created
stream().transportState().setId(STREAM_ID);
Http2Headers headers = new DefaultHttp2Headers().status(STATUS_OK).set(CONTENT_TYPE_HEADER, new AsciiString("application/bad", UTF_8));
stream().transportState().transportHeadersReceived(headers, false);
Http2Headers trailers = new DefaultHttp2Headers().set(new AsciiString("grpc-status", UTF_8), new AsciiString("0", UTF_8));
stream().transportState().transportHeadersReceived(trailers, true);
ArgumentCaptor<Status> captor = ArgumentCaptor.forClass(Status.class);
ArgumentCaptor<Metadata> metadataCaptor = ArgumentCaptor.forClass(Metadata.class);
verify(listener).closed(captor.capture(), same(PROCESSED), metadataCaptor.capture());
Status status = captor.getValue();
assertEquals(Status.Code.UNKNOWN, status.getCode());
assertTrue(status.getDescription().contains("content-type"));
assertEquals("application/bad", metadataCaptor.getValue().get(Metadata.Key.of("Content-Type", Metadata.ASCII_STRING_MARSHALLER)));
}
use of io.netty.handler.codec.http2.Http2Headers in project grpc-java by grpc.
the class NettyClientHandlerTest method bdpPingAvoidsTooManyPingsOnSpecialServers.
@Test
public void bdpPingAvoidsTooManyPingsOnSpecialServers() throws Exception {
// gRPC servers limit PINGs based on what they _send_. Some servers limit PINGs based on what is
// _received_.
createStream();
handler().setAutoTuneFlowControl(true);
Http2Headers headers = new DefaultHttp2Headers().status(STATUS_OK).set(CONTENT_TYPE_HEADER, CONTENT_TYPE_GRPC);
channelRead(headersFrame(3, headers));
channelRead(dataFrame(3, false, content()));
verifyWrite().writePing(eq(ctx()), eq(false), eq(1234L), any(ChannelPromise.class));
channelRead(pingFrame(true, 1234));
channelRead(dataFrame(3, false, content()));
verifyWrite(times(2)).writePing(eq(ctx()), eq(false), eq(1234L), any(ChannelPromise.class));
channelRead(pingFrame(true, 1234));
channelRead(dataFrame(3, false, content()));
// No ping was sent
verifyWrite(times(2)).writePing(eq(ctx()), eq(false), eq(1234L), any(ChannelPromise.class));
}
use of io.netty.handler.codec.http2.Http2Headers in project grpc-java by grpc.
the class NettyClientHandlerTest method inboundShouldForwardToStream.
@Test
public void inboundShouldForwardToStream() throws Exception {
createStream();
// Read a headers frame first.
Http2Headers headers = new DefaultHttp2Headers().status(STATUS_OK).set(CONTENT_TYPE_HEADER, CONTENT_TYPE_GRPC).set(as("magic"), as("value"));
ByteBuf headersFrame = headersFrame(3, headers);
channelRead(headersFrame);
ArgumentCaptor<Metadata> captor = ArgumentCaptor.forClass(Metadata.class);
verify(streamListener).headersRead(captor.capture());
assertEquals("value", captor.getValue().get(Metadata.Key.of("magic", Metadata.ASCII_STRING_MARSHALLER)));
streamTransportState.requestMessagesFromDeframerForTesting(1);
// Create a data frame and then trigger the handler to read it.
ByteBuf frame = grpcDataFrame(3, false, contentAsArray());
channelRead(frame);
InputStream message = streamListenerMessageQueue.poll();
assertArrayEquals(ByteBufUtil.getBytes(content()), ByteStreams.toByteArray(message));
message.close();
assertNull("no additional message expected", streamListenerMessageQueue.poll());
}
Aggregations