You're seeing the release note of an old version. Check out the latest release note.
v0.97.0
December 8, 2019
🌟 New features
-
We now have a new immutable cookie API with
SameSiteattribute support, which replaces Netty's cookie API. #1567 #2286Cookie c1 = Cookie.of("foo", "bar")
Cookie c2 = Cookie.builder("alice", "bob")
.domain("foo.com")
.path("/bar")
.maxAge(3600)
.sameSite("Strict")
.build();
// Encoding
ResponseHeaders resHeaders =
ResponseHeaders.builder(HttpStatus.OK)
.add(HttpHeaderNames.SET_COOKIE,
Cookie.toSetCookieHeaders(c1, c2))
.build();
// Decoding
Cookies cookies =
Cookie.fromSetCookieHeaders(
resHeaders.getAll(HttpHeaderNames.SET_COOKIE)); -
You can now replace the request headers of
HttpRequestmore conveniently usingHttpRequest.withHeaders(RequestHeaders). #2278 #2283HttpRequest req = HttpRequest.of(HttpMethod.POST, "/post",
MediaType.PLAIN_TEXT_UTF_8,
"Hello!");
RequestHeaders newHeaders = RequestHeaders.of(HttpMethod.PUT, "/put",
MediaType.PLAIN_TEXT_UTF_8);
HttpRequest newReq = req.withHeaders(newHeaders); -
ServiceRequestContext.blockingTaskExecutor()is now aScheduledExecutorServiceinstead ofExecutorService, which means you can schedule delayed or periodic tasks. #2269// A service that sends `PING!` every second.
HttpService service = (ctx, req) -> {
HttpResponse res = HttpResponse.streaming();
res.write(ResponseHeaders.of(200));
AtomicReference<ScheduledFuture<?>> futureHolder = new AtomicReference<>();
futureHolder.set(ctx.blockingTaskExecutor().scheduleWithFixedDelay(() -> {
boolean success = res.tryWrite(HttpData.ofUtf8("PING!\r\n"));
if (!success) {
if (futureHolder.get() != null) {
futureHolder.get().cancel(false);
}
}
}, 1, TimeUnit.SECONDS));
return res;
}; -
You can now add converters and exception handlers to annotated services more conveniently using the new fluent builder methods. #2242
Server server =
Server.builder()
.annotatedService().requestConverters(converterA, converterB)
.responseConverters(converterC, converterD)
.exceptionHandlers(handlerA, handlerB)
.build(myAnnotatedService)
.build(); -
You can now configure how Armeria decides
ServiceRequestContext.clientAddress()viaServerBuilder.clientAddressMapper(). #1631 #2294Server.builder()
.clientAddressMapper(proxiedAddrs -> {
InetSocketAddress srcAddr = proxiedAddrs.sourceAddress();
List<InetSocketAddress> destAddrs = proxiedAddrs.destinationAddresses();
if (destAddrs.isEmpty()) {
// No proxy servers involved.
return srcAddr;
} else {
// When there are more than one proxy server involved,
// trust only the address given by the last proxy server.
return destAddrs.get(destAddrs.size() - 1);
}
}); -
You can now choose a different SLF4J
Loggerthan the default one when usingLoggingClientorLoggingService. #2220 #2237Logger myLogger = LoggerFactory.getLogger(MyService.class);
Server server =
Server.builder()
.service("/",
myService.decorate(LoggingService.builder()
.logger(myLogger)
.newDecorator()))
.build(); -
BraveClientnow adds connection timing information to a span. #2271 #2273connection-acquire.startandconnection-acquire.enddns-resolve.startanddns-resolve.endsocket-connect.startandsocket-connect.endconnection-reuse.startandconnection-reuse.end
-
withDeadlineAfteris now supported for gRPC client stubs. #2284 -
GrpcServicenow allows controlling whether to respect the"grpc-timeout"header sent by a gRPC client. #2284- Consider disabling this feature via
GrpcServiceBuilder.useClientTimeoutHeader()in an insecure environment.
- Consider disabling this feature via
-
THttpServiceandThriftCallServicenow supports adding more than one Thrift service at the same endpoint. #2164 #2285class MyFooService implements FooService.Iface ... {
public void foo() { ... }
}
class MyBarService implements BarService.Iface ... {
public void bar() { ... }
}
// "foo" call goes to MyFooService and
// "bar" call goes to MyBarService.
Server server =
Server.builder()
.service("/thrift",
THttpService.builder()
.addService(new MyFooService())
.addService(new MyBarService())
.build())
.build(); -
armeria-spring-boot-actuator-autoconfigurenow supports the official CORS settings. #2063# application.yml
management.endpoints.web.cors.allowed-origins: https://example.com
management.endpoints.web.cors.allowed-methods: GET,POST
📈 Improvements
- Improved routing performance. #2293 #2295
- The core JAR file is now smaller, by removing unnecessary resources such as web fonts and favicons. #2299 #2300
HttpRequest.of(RequestHeaders, Publisher)now handles the case where thePublisheris actually anHttpRequest. #2278 #2283
🔒 Security fixes
- (Moderate) CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Response Splitting')
- (Low) Multiple timing attack vulnerabilities leading to the recovery of secrets based on the use of non-constant time compare function
🛠️ Bug fixes
- The event loop threads are properly cleaned up when
Serverfailed to start. #2288 Servernow sends a redirect response correctly for the requests without a trailing slash (/) even when you bound a fallback service atprefix:/. #2116 #2292- Fixed a bug where routing cache did not work as expected, leading suboptimal routing performance. #2293
- Annotated services now accept only the first
"Cookie"header when injectingCookies, because multiple"Cookie"headers must be prohibited according to RFC 6265. #2286 GrpcServicenow respects gRPC stub deadline. #2008 #2284
🏚️ Deprecations
- Deprecated
HttpRequest.of(HttpRequest, RequestHeaders)in favor ofHttpRequest.withHeaders()#2283 - Deprecated
HttpRequest.of(AggregatedHttpRequest)andHttpResponse.of(AggregatedHttpResponse)in favor ofAggregatedHttpRequest.toHttpRequest()andAggregatedHttpResponse.toHttpResponse(). #2283- These methods were removed from
AggregatedHttpMessagesome time ago due to ambiguity, but now we are reviving them because we have separate types for requests and responses.
- These methods were removed from
Cookies.copyOf()has been deprecated in favor ofCookies.of(). #2286AnnotatedServiceBuildingBuilder.requestConverter(),responseConverter()andexceptionHandler()have been deprecated in favor ofrequestConverters(),responseConverters()andexceptionHandlers()respectively. #2242Sampler.rateLimited()has been deprecated in favor ofrateLimiting(). #2122 #2289THttpService.of()andofFormats()factory methods that require aMap<String, ?>have been deprecated. UseTHttpService.builder()and callTHttpService.addService(String, Object)multiple times instead. #2285
☢️ Breaking changes
ServerBuilder.blockingTaskExecutor()now requires aScheduledExecutorServiceinstead of anExecutorService. #2269- The behavior of automatic redirection for the case of missing trailing slash (
/) has been changed (in a good way). #2116 #2292- For example, previously, when a client sent a request to
/docs, the following server routed the request toTomcatService:Server server =
Server.builder()
.serviceUnder("/docs", new DocService())
.serviceUnder("/", TomcatSerivce.forClassPath(...))
.build(); - However, from this release, the request will not be routed to
TomcatServicebut the server will issue a redirect response to/docs/.
- For example, previously, when a client sent a request to
ProxiedAddressesclass has been redesigned to handle the case of more than one intermediary proxy server. #1631 #2294Cookiesnow uses Armeria's ownCookie. #2286Cookiesnow may contain the cookies with the same name. #2286- Note that RFC does not prohibit duplicate names at all, so this is correct behavior.
- Annotated services now accept only the first
"Cookie"header when decoding cookies. Sending multiple"Cookie"headers was a violation of RFC 6265 anyway. #2286 - The
ThriftCallServicefactory method with signatureof(Map<String, ? extends Iterable<?>>)has been changed toof(Map<String, ? extends Iterable<?>>)#2285
⛓ Dependencies
- Brave 1.3.1
- Jetty 9.4.22 -> 9.4.24
- Micrometer 1.3.1 -> 1.3.2
- Netty TCNative BoringSSL 2.0.27 -> 2.0.26
- Project Reactor 3.3.0 -> 3.3.1
- RxJava2 2.2.14 -> 2.2.15
- Spring Boot 2.1.10 -> 2.2.1
- Tomcat 9.0.27 -> 9.0.29, 8.5.47 -> 8.5.49
🙇 Thank you
This release was possible thanks to the following contributors who shared their brilliant ideas and awesome pull requests:















