下面列出了怎么用io.grpc.InternalStatus的API类实例代码及写法,或者点击链接到github查看源代码。
private void respondWithHttpError(
ChannelHandlerContext ctx, int streamId, int code, Status.Code statusCode, String msg) {
Metadata metadata = new Metadata();
metadata.put(InternalStatus.CODE_KEY, statusCode.toStatus());
metadata.put(InternalStatus.MESSAGE_KEY, msg);
byte[][] serialized = InternalMetadata.serialize(metadata);
Http2Headers headers = new DefaultHttp2Headers(true, serialized.length / 2)
.status("" + code)
.set(CONTENT_TYPE_HEADER, "text/plain; encoding=utf-8");
for (int i = 0; i < serialized.length; i += 2) {
headers.add(new AsciiString(serialized[i], false), new AsciiString(serialized[i + 1], false));
}
encoder().writeHeaders(ctx, streamId, headers, 0, false, ctx.newPromise());
ByteBuf msgBuf = ByteBufUtil.writeUtf8(ctx.alloc(), msg);
encoder().writeData(ctx, streamId, msgBuf, 0, true, ctx.newPromise());
}
@Test
public void headersWithInvalidContentTypeShouldFail() throws Exception {
manualSetUp();
Http2Headers headers = new DefaultHttp2Headers()
.method(HTTP_METHOD)
.set(CONTENT_TYPE_HEADER, new AsciiString("application/bad", UTF_8))
.set(TE_HEADER, TE_TRAILERS)
.path(new AsciiString("/foo/bar"));
ByteBuf headersFrame = headersFrame(STREAM_ID, headers);
channelRead(headersFrame);
Http2Headers responseHeaders = new DefaultHttp2Headers()
.set(InternalStatus.CODE_KEY.name(), String.valueOf(Code.INTERNAL.value()))
.set(InternalStatus.MESSAGE_KEY.name(), "Content-Type 'application/bad' is not supported")
.status("" + 415)
.set(CONTENT_TYPE_HEADER, "text/plain; encoding=utf-8");
verifyWrite().writeHeaders(eq(ctx()), eq(STREAM_ID), eq(responseHeaders), eq(0),
eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), any(ChannelPromise.class));
}
@Test
public void headersWithInvalidMethodShouldFail() throws Exception {
manualSetUp();
Http2Headers headers = new DefaultHttp2Headers()
.method(HTTP_FAKE_METHOD)
.set(CONTENT_TYPE_HEADER, CONTENT_TYPE_GRPC)
.path(new AsciiString("/foo/bar"));
ByteBuf headersFrame = headersFrame(STREAM_ID, headers);
channelRead(headersFrame);
Http2Headers responseHeaders = new DefaultHttp2Headers()
.set(InternalStatus.CODE_KEY.name(), String.valueOf(Code.INTERNAL.value()))
.set(InternalStatus.MESSAGE_KEY.name(), "Method 'FAKE' is not supported")
.status("" + 405)
.set(CONTENT_TYPE_HEADER, "text/plain; encoding=utf-8");
verifyWrite().writeHeaders(eq(ctx()), eq(STREAM_ID), eq(responseHeaders), eq(0),
eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), any(ChannelPromise.class));
}
@Test
public void headersWithMissingPathShouldFail() throws Exception {
manualSetUp();
Http2Headers headers = new DefaultHttp2Headers()
.method(HTTP_METHOD)
.set(CONTENT_TYPE_HEADER, CONTENT_TYPE_GRPC);
ByteBuf headersFrame = headersFrame(STREAM_ID, headers);
channelRead(headersFrame);
Http2Headers responseHeaders = new DefaultHttp2Headers()
.set(InternalStatus.CODE_KEY.name(), String.valueOf(Code.UNIMPLEMENTED.value()))
.set(InternalStatus.MESSAGE_KEY.name(), "Expected path but is missing")
.status("" + 404)
.set(CONTENT_TYPE_HEADER, "text/plain; encoding=utf-8");
verifyWrite().writeHeaders(eq(ctx()), eq(STREAM_ID), eq(responseHeaders), eq(0),
eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), any(ChannelPromise.class));
}
@Test
public void headersWithInvalidPathShouldFail() throws Exception {
manualSetUp();
Http2Headers headers = new DefaultHttp2Headers()
.method(HTTP_METHOD)
.set(CONTENT_TYPE_HEADER, CONTENT_TYPE_GRPC)
.path(new AsciiString("foo/bar"));
ByteBuf headersFrame = headersFrame(STREAM_ID, headers);
channelRead(headersFrame);
Http2Headers responseHeaders = new DefaultHttp2Headers()
.set(InternalStatus.CODE_KEY.name(), String.valueOf(Code.UNIMPLEMENTED.value()))
.set(InternalStatus.MESSAGE_KEY.name(), "Expected path to start with /: foo/bar")
.status("" + 404)
.set(CONTENT_TYPE_HEADER, "text/plain; encoding=utf-8");
verifyWrite().writeHeaders(eq(ctx()), eq(STREAM_ID), eq(responseHeaders), eq(0),
eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), any(ChannelPromise.class));
}
/**
* Extract the response status from trailers.
*/
private Status statusFromTrailers(Metadata trailers) {
Status status = trailers.get(InternalStatus.CODE_KEY);
if (status != null) {
return status.withDescription(trailers.get(InternalStatus.MESSAGE_KEY));
}
// No status; something is broken. Try to provide a resonanable error.
if (headersReceived) {
return Status.UNKNOWN.withDescription("missing GRPC status in response");
}
Integer httpStatus = trailers.get(HTTP2_STATUS);
if (httpStatus != null) {
status = GrpcUtil.httpStatusToGrpcStatus(httpStatus);
} else {
status = Status.INTERNAL.withDescription("missing HTTP status code");
}
return status.augmentDescription(
"missing GRPC status, inferred error from HTTP status code");
}
@Test
public void close_sendTrailersClearsReservedFields() {
// stream actually mutates trailers, so we can't check that the fields here are the same as
// the captured ones.
Metadata trailers = new Metadata();
trailers.put(InternalStatus.CODE_KEY, Status.OK);
trailers.put(InternalStatus.MESSAGE_KEY, "Everything's super.");
Status closeStatus = Status.INTERNAL.withDescription("bad");
stream.close(closeStatus, trailers);
verify(sink).writeTrailers(metadataCaptor.capture(), eq(false), eq(closeStatus));
assertEquals(
Status.Code.INTERNAL, metadataCaptor.getValue().get(InternalStatus.CODE_KEY).getCode());
assertEquals("bad", metadataCaptor.getValue().get(InternalStatus.MESSAGE_KEY));
}
@Test
void copyFromHeadersTest() {
final HttpHeaders trailers =
ResponseHeaders.builder()
.endOfStream(true)
.add(HttpHeaderNames.STATUS, HttpStatus.OK.codeAsText())
.add(HttpHeaderNames.CONTENT_TYPE, "application/grpc+proto")
.add(GrpcHeaderNames.GRPC_STATUS, "3")
.add(GrpcHeaderNames.GRPC_MESSAGE, "test_grpc_message")
.add(TEST_ASCII_KEY.originalName(), "test_message")
.add(GrpcHeaderNames.ARMERIA_GRPC_THROWABLEPROTO_BIN,
Base64.getEncoder().encodeToString(THROWABLE_PROTO.toByteArray()))
.build();
final Metadata metadata = MetadataUtil.copyFromHeaders(trailers);
assertThat(metadata.get(TEST_ASCII_KEY)).isEqualTo("test_message");
// MUST not copy values of :status, grpc-status, grpc-message, armeria.grpc.ThrowableProto-bin
assertThat(metadata.get(STATUS_KEY)).isNull();
assertThat(metadata.get(InternalStatus.CODE_KEY)).isNull();
assertThat(metadata.get(InternalStatus.MESSAGE_KEY)).isNull();
assertThat(metadata.get(THROWABLE_PROTO_METADATA_KEY)).isNull();
}
private void respondWithHttpError(
ChannelHandlerContext ctx, int streamId, int code, Status.Code statusCode, String msg) {
Metadata metadata = new Metadata();
metadata.put(InternalStatus.CODE_KEY, statusCode.toStatus());
metadata.put(InternalStatus.MESSAGE_KEY, msg);
byte[][] serialized = InternalMetadata.serialize(metadata);
Http2Headers headers = new DefaultHttp2Headers(true, serialized.length / 2)
.status("" + code)
.set(CONTENT_TYPE_HEADER, "text/plain; encoding=utf-8");
for (int i = 0; i < serialized.length; i += 2) {
headers.add(new AsciiString(serialized[i], false), new AsciiString(serialized[i + 1], false));
}
encoder().writeHeaders(ctx, streamId, headers, 0, false, ctx.newPromise());
ByteBuf msgBuf = ByteBufUtil.writeUtf8(ctx.alloc(), msg);
encoder().writeData(ctx, streamId, msgBuf, 0, true, ctx.newPromise());
}
@Test
public void headersWithInvalidContentTypeShouldFail() throws Exception {
manualSetUp();
Http2Headers headers = new DefaultHttp2Headers()
.method(HTTP_METHOD)
.set(CONTENT_TYPE_HEADER, new AsciiString("application/bad", UTF_8))
.set(TE_HEADER, TE_TRAILERS)
.path(new AsciiString("/foo/bar"));
ByteBuf headersFrame = headersFrame(STREAM_ID, headers);
channelRead(headersFrame);
Http2Headers responseHeaders = new DefaultHttp2Headers()
.set(InternalStatus.CODE_KEY.name(), String.valueOf(Code.INTERNAL.value()))
.set(InternalStatus.MESSAGE_KEY.name(), "Content-Type 'application/bad' is not supported")
.status("" + 415)
.set(CONTENT_TYPE_HEADER, "text/plain; encoding=utf-8");
verifyWrite()
.writeHeaders(
eq(ctx()),
eq(STREAM_ID),
eq(responseHeaders),
eq(0),
eq(false),
any(ChannelPromise.class));
}
@Test
public void headersWithInvalidMethodShouldFail() throws Exception {
manualSetUp();
Http2Headers headers = new DefaultHttp2Headers()
.method(HTTP_FAKE_METHOD)
.set(CONTENT_TYPE_HEADER, CONTENT_TYPE_GRPC)
.path(new AsciiString("/foo/bar"));
ByteBuf headersFrame = headersFrame(STREAM_ID, headers);
channelRead(headersFrame);
Http2Headers responseHeaders = new DefaultHttp2Headers()
.set(InternalStatus.CODE_KEY.name(), String.valueOf(Code.INTERNAL.value()))
.set(InternalStatus.MESSAGE_KEY.name(), "Method 'FAKE' is not supported")
.status("" + 405)
.set(CONTENT_TYPE_HEADER, "text/plain; encoding=utf-8");
verifyWrite()
.writeHeaders(
eq(ctx()),
eq(STREAM_ID),
eq(responseHeaders),
eq(0),
eq(false),
any(ChannelPromise.class));
}
@Test
public void headersWithMissingPathShouldFail() throws Exception {
manualSetUp();
Http2Headers headers = new DefaultHttp2Headers()
.method(HTTP_METHOD)
.set(CONTENT_TYPE_HEADER, CONTENT_TYPE_GRPC);
ByteBuf headersFrame = headersFrame(STREAM_ID, headers);
channelRead(headersFrame);
Http2Headers responseHeaders = new DefaultHttp2Headers()
.set(InternalStatus.CODE_KEY.name(), String.valueOf(Code.UNIMPLEMENTED.value()))
.set(InternalStatus.MESSAGE_KEY.name(), "Expected path but is missing")
.status("" + 404)
.set(CONTENT_TYPE_HEADER, "text/plain; encoding=utf-8");
verifyWrite()
.writeHeaders(
eq(ctx()),
eq(STREAM_ID),
eq(responseHeaders),
eq(0),
eq(false),
any(ChannelPromise.class));
}
@Test
public void headersWithInvalidPathShouldFail() throws Exception {
manualSetUp();
Http2Headers headers = new DefaultHttp2Headers()
.method(HTTP_METHOD)
.set(CONTENT_TYPE_HEADER, CONTENT_TYPE_GRPC)
.path(new AsciiString("foo/bar"));
ByteBuf headersFrame = headersFrame(STREAM_ID, headers);
channelRead(headersFrame);
Http2Headers responseHeaders = new DefaultHttp2Headers()
.set(InternalStatus.CODE_KEY.name(), String.valueOf(Code.UNIMPLEMENTED.value()))
.set(InternalStatus.MESSAGE_KEY.name(), "Expected path to start with /: foo/bar")
.status("" + 404)
.set(CONTENT_TYPE_HEADER, "text/plain; encoding=utf-8");
verifyWrite()
.writeHeaders(
eq(ctx()),
eq(STREAM_ID),
eq(responseHeaders),
eq(0),
eq(false),
any(ChannelPromise.class));
}
/**
* Extract the response status from trailers.
*/
private Status statusFromTrailers(Metadata trailers) {
Status status = trailers.get(InternalStatus.CODE_KEY);
if (status != null) {
return status.withDescription(trailers.get(InternalStatus.MESSAGE_KEY));
}
// No status; something is broken. Try to provide a resonanable error.
if (headersReceived) {
return Status.UNKNOWN.withDescription("missing GRPC status in response");
}
Integer httpStatus = trailers.get(HTTP2_STATUS);
if (httpStatus != null) {
status = GrpcUtil.httpStatusToGrpcStatus(httpStatus);
} else {
status = Status.INTERNAL.withDescription("missing HTTP status code");
}
return status.augmentDescription(
"missing GRPC status, inferred error from HTTP status code");
}
@Test
public void close_sendTrailersClearsReservedFields() {
// stream actually mutates trailers, so we can't check that the fields here are the same as
// the captured ones.
Metadata trailers = new Metadata();
trailers.put(InternalStatus.CODE_KEY, Status.OK);
trailers.put(InternalStatus.MESSAGE_KEY, "Everything's super.");
Status closeStatus = Status.INTERNAL.withDescription("bad");
stream.close(closeStatus, trailers);
verify(sink).writeTrailers(metadataCaptor.capture(), eq(false), eq(closeStatus));
assertEquals(
Status.Code.INTERNAL, metadataCaptor.getValue().get(InternalStatus.CODE_KEY).getCode());
assertEquals("bad", metadataCaptor.getValue().get(InternalStatus.MESSAGE_KEY));
}
private List<Header> grpcResponseTrailers() {
return ImmutableList.of(
new Header(InternalStatus.CODE_KEY.name(), "0"),
// Adding Content-Type and :status for testing responses with only a single HEADERS frame.
new Header(":status", "200"),
CONTENT_TYPE_HEADER);
}
private void addStatusToTrailers(Metadata trailers, Status status) {
trailers.discardAll(InternalStatus.CODE_KEY);
trailers.discardAll(InternalStatus.MESSAGE_KEY);
trailers.put(InternalStatus.CODE_KEY, status);
if (status.getDescription() != null) {
trailers.put(InternalStatus.MESSAGE_KEY, status.getDescription());
}
}
@Test
void fillHeadersTest() {
final HttpHeadersBuilder trailers =
ResponseHeaders.builder()
.endOfStream(true)
.add(HttpHeaderNames.STATUS, HttpStatus.OK.codeAsText())
.add(HttpHeaderNames.CONTENT_TYPE, "application/grpc+proto")
.add(GrpcHeaderNames.GRPC_STATUS, "3")
.add(GrpcHeaderNames.GRPC_MESSAGE, "test_grpc_message");
final Metadata metadata = new Metadata();
// be copied into HttpHeaderBuilder trailers
metadata.put(TEST_ASCII_KEY, "metadata_test_string");
metadata.put(TEST_BIN_KEY, "metadata_test_string".getBytes());
// must not be copied into HttpHeaderBuilder trailers
metadata.put(STATUS_KEY, "200");
metadata.put(InternalStatus.CODE_KEY, Status.OK);
metadata.put(InternalStatus.MESSAGE_KEY, "grpc_message_must_not_be_copied");
metadata.put(THROWABLE_PROTO_METADATA_KEY, THROWABLE_PROTO);
MetadataUtil.fillHeaders(metadata, trailers);
assertThat(trailers.getAll(TEST_ASCII_KEY.originalName())).containsExactly("metadata_test_string");
assertThat(Base64.getDecoder().decode(trailers.get(TEST_BIN_KEY.originalName())))
.containsExactly("metadata_test_string".getBytes());
assertThat(trailers.getAll(HttpHeaderNames.STATUS)).containsExactly(HttpStatus.OK.codeAsText());
assertThat(trailers.getAll(HttpHeaderNames.CONTENT_TYPE)).containsExactly("application/grpc+proto");
assertThat(trailers.getAll(GrpcHeaderNames.GRPC_STATUS)).containsExactly("3");
assertThat(trailers.getAll(GrpcHeaderNames.GRPC_MESSAGE)).containsOnly("test_grpc_message");
assertThat(trailers.getAll(GrpcHeaderNames.ARMERIA_GRPC_THROWABLEPROTO_BIN)).isEmpty();
}
private List<Header> grpcResponseTrailers() {
return ImmutableList.of(
new Header(InternalStatus.CODE_KEY.name(), "0"),
// Adding Content-Type and :status for testing responses with only a single HEADERS frame.
new Header(":status", "200"),
CONTENT_TYPE_HEADER);
}
private void addStatusToTrailers(Metadata trailers, Status status) {
trailers.discardAll(InternalStatus.CODE_KEY);
trailers.discardAll(InternalStatus.MESSAGE_KEY);
trailers.put(InternalStatus.CODE_KEY, status);
if (status.getDescription() != null) {
trailers.put(InternalStatus.MESSAGE_KEY, status.getDescription());
}
}
private Http2Headers grpcResponseTrailers(Status status) {
Metadata trailers = new Metadata();
trailers.put(InternalStatus.CODE_KEY, status);
return Utils.convertTrailers(trailers, true);
}
/**
* Strip HTTP transport implementation details so they don't leak via metadata into
* the application layer.
*/
private static void stripTransportDetails(Metadata metadata) {
metadata.discardAll(HTTP2_STATUS);
metadata.discardAll(InternalStatus.CODE_KEY);
metadata.discardAll(InternalStatus.MESSAGE_KEY);
}
public static void main(String[] args) {
System.out.println(InternalStatus.MESSAGE_KEY);
System.out.println(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
}
private Http2Headers grpcResponseTrailers(Status status) {
Metadata trailers = new Metadata();
trailers.put(InternalStatus.CODE_KEY, status);
return Utils.convertTrailers(trailers, true);
}
/**
* Strip HTTP transport implementation details so they don't leak via metadata into
* the application layer.
*/
private static void stripTransportDetails(Metadata metadata) {
metadata.discardAll(HTTP2_STATUS);
metadata.discardAll(InternalStatus.CODE_KEY);
metadata.discardAll(InternalStatus.MESSAGE_KEY);
}