下面列出了 io.netty.handler.codec.http2.HttpConversionUtil.ExtensionHeaderNames #com.linecorp.armeria.common.HttpHeaders 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public HttpResponse convertResponse(ServiceRequestContext ctx, ResponseHeaders headers,
@Nullable Object resObj,
HttpHeaders trailingHeaders) throws Exception {
try {
final HttpRequest request = RequestContext.current().request();
final HttpData httpData =
resObj != null &&
resObj.getClass() == Object.class ? EMPTY_RESULT
: HttpData.wrap(Jackson.writeValueAsBytes(resObj));
final ResponseHeadersBuilder builder = headers.toBuilder();
if (HttpMethod.POST == request.method()) {
builder.status(HttpStatus.CREATED);
}
if (builder.contentType() == null) {
builder.contentType(MediaType.JSON_UTF_8);
}
return HttpResponse.of(builder.build(), httpData, trailingHeaders);
} catch (JsonProcessingException e) {
return HttpApiUtil.newResponse(ctx, HttpStatus.INTERNAL_SERVER_ERROR, e);
}
}
@Override
public void beforeMethod(final EnhancedInstance objInst, final Method method, final Object[] allArguments,
final Class<?>[] argumentsTypes, final MethodInterceptResult result) {
DefaultHttpRequest httpRequest = (DefaultHttpRequest) allArguments[1];
HttpHeaders headers = httpRequest.headers();
ContextCarrier carrier = new ContextCarrier();
for (CarrierItem item = carrier.items(); item.hasNext(); ) {
item = item.next();
item.setHeadValue(headers.get(AsciiString.of(item.getHeadKey())));
}
AbstractSpan entrySpan = ContextManager.createEntrySpan(httpRequest.path(), carrier);
entrySpan.setComponent(ComponentsDefine.ARMERIA);
entrySpan.setLayer(SpanLayer.HTTP);
entrySpan.setPeer(httpRequest.authority());
Tags.URL.set(entrySpan, httpRequest.path());
Tags.HTTP.METHOD.set(entrySpan, httpRequest.method().name());
}
private static Function<? super HttpClient, ContentPreviewingClient> decodingContentPreviewDecorator() {
final BiPredicate<? super RequestContext, ? super HttpHeaders> previewerPredicate =
(requestContext, headers) -> "gzip".equals(headers.get(HttpHeaderNames.CONTENT_ENCODING));
final BiFunction<HttpHeaders, ByteBuf, String> producer = (headers, data) -> {
final byte[] bytes = new byte[data.readableBytes()];
data.getBytes(0, bytes);
final byte[] decoded;
try (GZIPInputStream unzipper = new GZIPInputStream(new ByteArrayInputStream(bytes))) {
decoded = ByteStreams.toByteArray(unzipper);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
return new String(decoded, StandardCharsets.UTF_8);
};
final ContentPreviewerFactory factory =
ContentPreviewerFactory.builder()
.maxLength(100)
.binary(producer, previewerPredicate)
.build();
return ContentPreviewingClient.newDecorator(factory);
}
@Test
void excludeBlacklistHeadersWhileHttp2ToHttp1() {
final HttpHeaders in = HttpHeaders.builder()
.add(HttpHeaderNames.TRAILER, "foo")
.add(HttpHeaderNames.HOST, "bar")
.add(HttpHeaderNames.PATH, "dummy")
.add(HttpHeaderNames.METHOD, "dummy")
.add(HttpHeaderNames.SCHEME, "dummy")
.add(HttpHeaderNames.STATUS, "dummy")
.add(HttpHeaderNames.TRANSFER_ENCODING, "dummy")
.add(ExtensionHeaderNames.STREAM_ID.text(), "dummy")
.add(ExtensionHeaderNames.SCHEME.text(), "dummy")
.add(ExtensionHeaderNames.PATH.text(), "dummy")
.build();
final io.netty.handler.codec.http.HttpHeaders out =
new DefaultHttpHeaders();
toNettyHttp1ServerHeader(in, out);
assertThat(out).isEqualTo(new DefaultHttpHeaders()
.add(io.netty.handler.codec.http.HttpHeaderNames.TRAILER, "foo")
.add(io.netty.handler.codec.http.HttpHeaderNames.HOST, "bar"));
}
private Function<? super HttpService, ContentPreviewingService> decodingContentPreviewDecorator() {
final BiPredicate<? super RequestContext, ? super HttpHeaders> previewerPredicate =
(requestContext, headers) -> "gzip".equals(headers.get(HttpHeaderNames.CONTENT_ENCODING));
final BiFunction<HttpHeaders, ByteBuf, String> producer = (headers, data) -> {
final byte[] bytes = new byte[data.readableBytes()];
data.getBytes(0, bytes);
final byte[] decoded;
try (GZIPInputStream unzipper = new GZIPInputStream(new ByteArrayInputStream(bytes))) {
decoded = ByteStreams.toByteArray(unzipper);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
return new String(decoded, StandardCharsets.UTF_8);
};
final ContentPreviewerFactory factory =
ContentPreviewerFactory.builder()
.maxLength(100)
.binary(producer, previewerPredicate)
.build();
return ContentPreviewingService.newDecorator(factory);
}
@Test
public void httpResponseHeaderContainsFoo() throws TException {
final Iface client =
Clients.builder(server.httpUri(BINARY) + "/hello")
.decorator((delegate, ctx, req) -> {
final HttpResponse res = delegate.execute(ctx, req);
return new FilteredHttpResponse(res) {
@Override
protected HttpObject filter(HttpObject obj) {
if (obj instanceof HttpHeaders) {
final HttpHeaders headers = (HttpHeaders) obj;
assertThat(headers.get("foo")).isEqualTo("bar");
}
return obj;
}
};
})
.build(Iface.class);
try (SafeCloseable ignored = Clients.withHttpHeader(AUTHORIZATION, SECRET)) {
assertThat(client.hello("trustin")).isEqualTo("Hello, trustin!");
}
}
@Override
public void beforeMethod(final EnhancedInstance objInst, final Method method, final Object[] allArguments,
final Class<?>[] argumentsTypes, final MethodInterceptResult result) throws Throwable {
DefaultHttpRequest httpRequest = (DefaultHttpRequest) allArguments[1];
HttpHeaders headers = httpRequest.headers();
ContextCarrier carrier = new ContextCarrier();
for (CarrierItem item = carrier.items(); item.hasNext(); ) {
item = item.next();
item.setHeadValue(headers.get(AsciiString.of(item.getHeadKey())));
}
AbstractSpan entrySpan = ContextManager.createEntrySpan(httpRequest.path(), carrier);
entrySpan.setComponent(ComponentsDefine.ARMERIA);
entrySpan.setLayer(SpanLayer.HTTP);
entrySpan.setPeer(httpRequest.authority());
Tags.URL.set(entrySpan, httpRequest.path());
Tags.HTTP.METHOD.set(entrySpan, httpRequest.method().name());
}
@Test
void proxiedAddresses_X_Forwarded_For() {
final ProxiedAddresses proxiedAddresses = ProxiedAddresses.of(
new InetSocketAddress("10.1.0.1", 80),
new InetSocketAddress("10.1.0.2", 443));
assertThat(HttpHeaderUtil.determineProxiedAddresses(
HttpHeaders.of(HttpHeaderNames.X_FORWARDED_FOR, "10.1.0.1:80,10.1.0.2:443"),
ClientAddressSource.DEFAULT_SOURCES, null, remoteAddr, ACCEPT_ANY))
.isEqualTo(proxiedAddresses);
assertThat(HttpHeaderUtil.determineProxiedAddresses(
HttpHeaders.of(HttpHeaderNames.FORWARDED, "for=10.0.0.1,for=10.0.0.2",
HttpHeaderNames.X_FORWARDED_FOR, "10.1.0.1:80,10.1.0.2:443"),
ImmutableList.of(ofHeader(HttpHeaderNames.X_FORWARDED_FOR)),
null, remoteAddr, ACCEPT_ANY))
.isEqualTo(proxiedAddresses);
}
private static void toNettyHttp1Server(
HttpHeaders inputHeaders, io.netty.handler.codec.http.HttpHeaders outputHeaders,
boolean isTrailer) {
for (Entry<AsciiString, String> entry : inputHeaders) {
final AsciiString name = entry.getKey();
final String value = entry.getValue();
if (HTTP2_TO_HTTP_HEADER_BLACKLIST.contains(name)) {
continue;
}
if (isTrailer && isTrailerBlacklisted(name)) {
continue;
}
outputHeaders.add(name, value);
}
}
@Nullable
private SerializationFormat determineSerializationFormat(HttpRequest req) {
final HttpHeaders headers = req.headers();
final MediaType contentType = headers.contentType();
final SerializationFormat serializationFormat;
if (contentType != null) {
serializationFormat = findSerializationFormat(contentType);
if (serializationFormat == null) {
// Browser clients often send a non-Thrift content type.
// Choose the default serialization format for some vague media types.
if (!("text".equals(contentType.type()) &&
"plain".equals(contentType.subtype())) &&
!("application".equals(contentType.type()) &&
"octet-stream".equals(contentType.subtype()))) {
return null;
}
} else {
return serializationFormat;
}
}
return defaultSerializationFormat();
}
private void convertHeaders(HttpHeaders inHeaders, io.netty.handler.codec.http.HttpHeaders outHeaders,
boolean isTrailersEmpty) {
ArmeriaHttpUtil.toNettyHttp1ServerHeader(inHeaders, outHeaders);
if (!isTrailersEmpty && outHeaders.contains(HttpHeaderNames.CONTENT_LENGTH)) {
// We don't apply chunked encoding when the content-length header is set, which would
// prevent the trailers from being sent so we go ahead and remove content-length to
// force chunked encoding.
outHeaders.remove(HttpHeaderNames.CONTENT_LENGTH);
}
if (enableServerHeader && !outHeaders.contains(HttpHeaderNames.SERVER)) {
outHeaders.add(HttpHeaderNames.SERVER, ArmeriaHttpUtil.SERVER_HEADER);
}
if (enableDateHeader && !outHeaders.contains(HttpHeaderNames.DATE)) {
outHeaders.add(HttpHeaderNames.DATE, HttpTimestampSupplier.currentTime());
}
}
/**
* Sets the specified {@link BiPredicate} to produce the text preview when the predicate
* returns {@code true}.
*/
public ContentPreviewerFactoryBuilder text(
BiPredicate<? super RequestContext, ? super HttpHeaders> predicate) {
requireNonNull(predicate, "predicate");
previewSpecsBuilder.add(new PreviewSpec(predicate, PreviewMode.TEXT, null));
return this;
}
private ContentPreviewer contentPreviewer(RequestContext ctx, HttpHeaders headers) {
for (PreviewSpec previewSpec : previewSpecs) {
if (previewSpec.predicate().test(ctx, headers)) {
switch (previewSpec.mode()) {
case TEXT:
final Charset charset = charset(headers);
return new TextContentPreviewer(maxLength, charset);
case BINARY:
final BiFunction<? super HttpHeaders, ? super ByteBuf, String> producer =
previewSpec.producer();
assert producer != null;
return new ProducerBasedContentPreviewer(maxLength, headers, producer);
case DISABLED:
return ContentPreviewer.disabled();
}
}
}
final MediaType contentType = headers.contentType();
if (contentType != null) {
final Charset charset = contentType.charset();
if (charset != null) {
return new TextContentPreviewer(maxLength, charset);
}
if ("text".equals(contentType.type()) ||
textSubTypes.contains(contentType.subtype()) ||
textSubTypeSuffixes.stream().anyMatch(contentType.subtype()::endsWith) ||
contentType.is(MediaType.FORM_DATA)) {
return new TextContentPreviewer(maxLength, defaultCharset);
}
}
return ContentPreviewer.disabled();
}
@Override
public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding,
boolean endOfStream) throws Http2Exception {
keepAliveChannelRead();
final HttpResponseWrapper res = getResponse(streamIdToId(streamId), endOfStream);
if (res == null) {
if (conn.streamMayHaveExisted(streamId)) {
if (logger.isDebugEnabled()) {
logger.debug("{} Received a late HEADERS frame for a closed stream: {}",
ctx.channel(), streamId);
}
return;
}
throw connectionError(PROTOCOL_ERROR, "received a HEADERS frame for an unknown stream: %d",
streamId);
}
res.logResponseFirstBytesTransferred();
final HttpHeaders converted = ArmeriaHttpUtil.toArmeria(headers, false, endOfStream);
try {
res.initTimeout();
res.write(converted);
} catch (Throwable t) {
res.close(t);
throw connectionError(INTERNAL_ERROR, t, "failed to consume a HEADERS frame");
}
if (endOfStream) {
res.close();
}
}
/**
* Returns a new {@link HttpResponseWriter} which has a content converted from the collected objects.
*
* @param stream a sequence of objects
* @param headers to be written to the returned {@link HttpResponseWriter}
* @param trailers to be written to the returned {@link HttpResponseWriter}
* @param contentConverter converts the collected objects into a content of the response
* @param executor executes the collecting job
*/
public static HttpResponseWriter aggregateFrom(Stream<?> stream,
ResponseHeaders headers, HttpHeaders trailers,
Function<Object, HttpData> contentConverter,
Executor executor) {
requireNonNull(stream, "stream");
requireNonNull(headers, "headers");
requireNonNull(trailers, "trailers");
requireNonNull(contentConverter, "contentConverter");
requireNonNull(executor, "executor");
return aggregateFrom(collectFrom(stream, executor), headers, trailers, contentConverter);
}
@Override
public HttpResponse convertResponse(ServiceRequestContext ctx,
ResponseHeaders headers,
@Nullable Object result,
HttpHeaders trailers) throws Exception {
if (result == null) {
return HttpResponse.of(HttpStatus.OK);
}
return ResponseConverterFunction.fallthrough();
}
/**
* Converts the specified Armeria HTTP/2 request headers into Netty HTTP/2 headers.
*
* @param inputHeaders the HTTP/2 request headers to convert.
*/
public static Http2Headers toNettyHttp2ClientHeader(HttpHeaders inputHeaders) {
final int headerSizeHint = inputHeaders.size() + 3; // User_Agent, :scheme and :authority.
final Http2Headers outputHeaders = new DefaultHttp2Headers(false, headerSizeHint);
toNettyHttp2Client(inputHeaders, outputHeaders, false);
return outputHeaders;
}
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) throws Exception {
final Supplier<RequestId> requestIdGenerator = () -> () -> "1";
return Stream.of(
arguments(FACTORY,
ClientFactory.builder().option(ClientFactoryOption.IDLE_TIMEOUT_MILLIS, 100L)
.build()),
arguments(WRITE_TIMEOUT_MILLIS, 10),
arguments(RESPONSE_TIMEOUT_MILLIS, 20),
arguments(MAX_RESPONSE_LENGTH, 123),
arguments(HTTP_HEADERS, HttpHeaders.of(HttpHeaderNames.USER_AGENT, "armeria")),
arguments(DECORATION, ClientDecoration.of(LoggingClient.newDecorator())),
arguments(REQUEST_ID_GENERATOR, requestIdGenerator),
arguments(ENDPOINT_REMAPPER, Function.identity()));
}
@Test
void outboundCookiesMustBeSplitForHttp2() {
final HttpHeaders in = HttpHeaders.builder()
.add(HttpHeaderNames.COOKIE, "a=b; c=d")
.add(HttpHeaderNames.COOKIE, "e=f;g=h")
.addObject(HttpHeaderNames.CONTENT_TYPE, MediaType.PLAIN_TEXT_UTF_8)
.add(HttpHeaderNames.COOKIE, "i=j")
.add(HttpHeaderNames.COOKIE, "k=l;")
.build();
final Http2Headers out = toNettyHttp2ClientHeader(in);
assertThat(out.getAll(HttpHeaderNames.COOKIE))
.containsExactly("a=b", "c=d", "e=f", "g=h", "i=j", "k=l");
}
@ParameterizedTest
@ArgumentsSource(ClientAndProtocolProvider.class)
void testAdditionalTrailersNoEndOfStream(WebClient client, SessionProtocol protocol) {
assumeThat(protocol.isMultiplex()).isTrue();
final HttpHeaders trailers = client.get("/additional-trailers-no-eos")
.aggregate().join().trailers();
assertThat(trailers.get(HttpHeaderNames.of("additional-trailer"))).isEqualTo("value2");
}
private ServiceInfo addServiceExamples(ServiceInfo service) {
final ListMultimap<String, HttpHeaders> exampleHttpHeaders =
this.exampleHttpHeaders.getOrDefault(service.name(), ImmutableListMultimap.of());
final ListMultimap<String, String> exampleRequests =
this.exampleRequests.getOrDefault(service.name(), ImmutableListMultimap.of());
final ListMultimap<String, String> examplePaths =
this.examplePaths.getOrDefault(service.name(), ImmutableListMultimap.of());
final ListMultimap<String, String> exampleQueries =
this.exampleQueries.getOrDefault(service.name(), ImmutableListMultimap.of());
// Reconstruct ServiceInfo with the examples.
return new ServiceInfo(
service.name(),
// Reconstruct MethodInfos with the examples.
service.methods().stream().map(m -> new MethodInfo(
m.name(), m.returnTypeSignature(), m.parameters(), m.exceptionTypeSignatures(),
m.endpoints(),
// Show the examples added via `DocServiceBuilder` before the examples
// generated by the plugin.
concatAndDedup(exampleHttpHeaders.get(m.name()), m.exampleHttpHeaders()),
concatAndDedup(exampleRequests.get(m.name()), m.exampleRequests()),
examplePaths.get(m.name()),
exampleQueries.get(m.name()),
m.httpMethod(), m.docString()))::iterator,
Iterables.concat(service.exampleHttpHeaders(),
exampleHttpHeaders.get("")),
service.docString());
}
@Test(timeout = 10000)
public void testMessageLogsForException() throws Exception {
try (TTransport transport = newTransport("http", "/exception")) {
final HelloService.Client client =
new HelloService.Client.Factory().getClient(
ThriftProtocolFactories.BINARY.getProtocol(transport));
recordMessageLogs = true;
assertThatThrownBy(() -> client.hello("Trustin")).isInstanceOf(TApplicationException.class);
}
final RequestLog log = takeLog();
assertThat(log.requestHeaders()).isInstanceOf(HttpHeaders.class);
assertThat(log.requestContent()).isInstanceOf(RpcRequest.class);
assertThat(log.rawRequestContent()).isInstanceOf(ThriftCall.class);
final RpcRequest request = (RpcRequest) log.requestContent();
assertThat(request.serviceType()).isEqualTo(HelloService.AsyncIface.class);
assertThat(request.method()).isEqualTo("hello");
assertThat(request.params()).containsExactly("Trustin");
final ThriftCall rawRequest = (ThriftCall) log.rawRequestContent();
assertThat(rawRequest.header().type).isEqualTo(TMessageType.CALL);
assertThat(rawRequest.header().name).isEqualTo("hello");
assertThat(rawRequest.args()).isInstanceOf(HelloService.hello_args.class);
assertThat(((HelloService.hello_args) rawRequest.args()).getName()).isEqualTo("Trustin");
assertThat(log.responseHeaders()).isInstanceOf(HttpHeaders.class);
assertThat(log.responseContent()).isInstanceOf(RpcResponse.class);
assertThat(log.rawResponseContent()).isInstanceOf(ThriftReply.class);
final RpcResponse response = (RpcResponse) log.responseContent();
assertThat(response.cause()).isNotNull();
final ThriftReply rawResponse = (ThriftReply) log.rawResponseContent();
assertThat(rawResponse.header().type).isEqualTo(TMessageType.EXCEPTION);
assertThat(rawResponse.header().name).isEqualTo("hello");
assertThat(rawResponse.exception()).isNotNull();
}
@Override
public HttpResponse convertResponse(ServiceRequestContext ctx,
ResponseHeaders headers,
@Nullable Object result,
HttpHeaders trailers) throws Exception {
if (result instanceof String && "hello foo".equals(result)) {
assertThat(responseCounter.getAndIncrement()).isOne();
}
return ResponseConverterFunction.fallthrough();
}
@Override
public String toStringRequestOnly(
BiFunction<? super RequestContext, ? super RequestHeaders, ?> headersSanitizer,
BiFunction<? super RequestContext, Object, ?> contentSanitizer,
BiFunction<? super RequestContext, ? super HttpHeaders, ?> trailersSanitizer) {
return DefaultRequestLog.this.toStringRequestOnly(
headersSanitizer, contentSanitizer, trailersSanitizer);
}
private static BiPredicate<? super RequestContext, ? super HttpHeaders> previewerPredicate(
MediaTypeSet mediaTypeSet) {
requireNonNull(mediaTypeSet, "mediaTypesSet");
return (ctx, headers) -> {
final MediaType contentType = headers.contentType();
if (contentType == null) {
return false;
}
return mediaTypeSet.match(contentType) != null;
};
}
@Override
public HttpResponse convertResponse(ServiceRequestContext ctx,
ResponseHeaders headers,
@Nullable Object result,
HttpHeaders trailers) throws Exception {
if (result instanceof Number) {
return httpResponse(HttpData.ofUtf8("Number[%s]", result));
}
return ResponseConverterFunction.fallthrough();
}
/**
* Adds example HTTP headers for the specified method.
*
* @deprecated Use {@link DocServiceBuilder#exampleHttpHeaders(String, String, Iterable)} via
* {@link DocServiceConfigurator}.
*/
@Deprecated
public GrpcServiceRegistrationBean addExampleHeaders(
String serviceName, String methodName, @NotNull Iterable<? extends HttpHeaders> exampleHeaders) {
exampleHeaders.forEach(h -> addExampleHeaders(serviceName, methodName, h));
return this;
}
@Test
void stripTEHeadersAccountsForOWS() {
final io.netty.handler.codec.http.HttpHeaders in = new DefaultHttpHeaders();
in.add(HttpHeaderNames.TE, " " + HttpHeaderValues.TRAILERS + ' ');
final HttpHeadersBuilder out = HttpHeaders.builder();
toArmeria(in, out);
assertThat(out.get(HttpHeaderNames.TE)).isEqualTo(HttpHeaderValues.TRAILERS.toString());
}
@Override
public HttpResponse convertResponse(
ServiceRequestContext ctx, ResponseHeaders headers,
@Nullable Object result, HttpHeaders trailers) throws Exception {
if (result instanceof Response) {
final Response response = (Response) result;
final HttpData body = HttpData.ofUtf8(response.result() + ':' + response.from());
return HttpResponse.of(headers, body, trailers);
}
return ResponseConverterFunction.fallthrough();
}
@Override
public HttpResponse convertResponse(ServiceRequestContext ctx,
ResponseHeaders headers,
@Nullable Object result,
HttpHeaders trailers) throws Exception {
final MediaType mediaType = headers.contentType();
if (mediaType != null) {
// @Produces("text/plain") or @ProducesText is specified.
if (mediaType.is(MediaType.ANY_TEXT_TYPE)) {
// Use 'utf-8' charset by default.
final Charset charset = mediaType.charset(ArmeriaHttpUtil.HTTP_DEFAULT_CONTENT_CHARSET);
// To avoid sending an unfinished text to the client, always aggregate the published strings.
if (result instanceof Publisher) {
return aggregateFrom((Publisher<?>) result, headers, trailers, o -> toHttpData(o, charset));
}
if (result instanceof Stream) {
return aggregateFrom((Stream<?>) result, headers, trailers,
o -> toHttpData(o, charset), ctx.blockingTaskExecutor());
}
return HttpResponse.of(headers, toHttpData(result, charset), trailers);
}
} else if (result instanceof CharSequence) {
return HttpResponse.of(headers.toBuilder().contentType(MediaType.PLAIN_TEXT_UTF_8).build(),
HttpData.ofUtf8(((CharSequence) result).toString()),
trailers);
}
return ResponseConverterFunction.fallthrough();
}