All notable changes to Riposte
will be documented in this file. Riposte
adheres to Semantic Versioning.
Riposte is used heavily and is stable internally at Nike, however the wider community may have needs or use cases that we haven't considered. Therefore Riposte will live at a sub-1.0 version for a short time after its initial open source release to give it time to respond quickly to the open source community without ballooning the version numbers. Once its public APIs have stabilized again as an open source project it will be switched to the normal post-1.0 semantic versioning system.
0.14.x
Releases - 0.14.00.13.x
Releases - 0.13.1, 0.13.00.12.x
Releases - 0.12.2, 0.12.1, 0.12.00.11.x
Releases - 0.11.2, 0.11.1, 0.11.00.10.x
Releases - 0.10.1, 0.10.00.9.x
Releases - 0.9.4, 0.9.3, 0.9.2, 0.9.1, 0.9.00.8.x
Releases - 0.8.3, 0.8.2, 0.8.1, 0.8.0
Released on 2018-11-06.
- Updated Riposte to use Netty
4.1.30.Final
(up from4.0.52.Final
). Although this is a Netty 4.0 -> 4.1 jump, it should be an invisible upgrade for most Riposte users.
Released on 2018-11-06.
- Fixed the default error response body serializer to not attempt to serialize bodies that are already raw
CharSequence
s. This allows you to output HTML pages for error responses (for example), rather than being forced to use an object that is serialized to JSON.- Fixed by Nathanial Myers in pull request #108. For issue #107
Released on 2018-04-26.
Some of the changes in version 0.13.0
can affect what is returned to the caller in some situations. Although these
changes are effectively bug fixes that bring Riposte more in line with the HTTP specification, and therefore should be
invisible and fully backwards compatible changes for most Riposte users, they can technically change what callers have
been receiving for some requests/responses, so it is strongly advised that you look over the changes below to determine
what impact updating to 0.13.0
might have for your services.
- Fixed
StandardEndpoint
responses to force-remove payloads for situations where the HTTP specification forbids returning a payload, including HTTP status code 204, 205, and 304 responses, and responses to HEAD requests (see RFC 2616 Section 4.4 and RFC 2616 Section 10.2.6). Some of these were already being handled by Netty (204, 304), but now 205 and HEAD requests are included.- Fixed by Nic Munroe in pull requests #102 and #103.
- Fixed
StandardEndpoint
s to allow you to specify a non-zero content-length header for HEAD or 304 responses even though the actual payload is empty. See RFC 7230 Section 3.3.2. If you explicitly specify a content-length header in yourResponseInfo
then that will be honored, otherwise Riposte will calculate content-length from whatever payload you provide (serialized the same way Riposte would serialize a normal GET 200 response) before dropping the payload for the actual response. This allows you to simply add theHEAD
method to theMatcher
for yourGET
endpoint and you will have properHEAD
support without any further changes.- Fixed by Nic Munroe in pull requests #102 and #103.
- Fixed a bug where
ProxyRouterEndpoint
responses were adding a defaultapplication/json
content-type header if the downstream system wasn't returning a content-type.ProxyRouterEndpoint
s will no longer do this.- Fixed by Nic Munroe in pull request #102.
- Fixed
ProxyRouterEndpoint
responses to not force chunked transfer-encoding. After this change, if the downstream returns a content-length and the payload has no chunked transfer encoding applied then that's what will reach the caller. This allows callers to know how big the payload is before it arrives, enabling progress bars (for example). Between this and the previous fix for content-type, Riposte no longer makes any changes to theProxyRouterEndpoint
response from the downstream.- Fixed by Nic Munroe in pull request #102.
- Added
DelegatedErrorResponseBody
- a simple implementation ofErrorResponseBody
that allows you to delegate serialization of the error contract to a different object.
- Changed the Netty pipeline used by Riposte to use a combined
HttpServerCodec
handler rather than separateHttpRequestDecoder
andHttpResponseEncoder
handlers. This allows Netty to detect and fix more HTTP specification violations (e.g. forcing empty payloads on responses to HEAD requests) but is otherwise equivalent. You should not notice any difference with this change unless your service uses aPipelineCreateHook
that expects to find aHttpRequestDecoder
orHttpResponseEncoder
handler in the pipeline - you would need to adjust it to look for the newHttpServerCodec
instead.
Released on 2018-04-18.
- Changed error handling system to allow you to specify blank response payloads or delegate serialization to an object
other than the
ErrorResponseBody
impl when using customRiposteErrorHandler
and/orRiposteUnhandledErrorHandler
impls (specified via yourServerConfig
). See the javadocs and source forErrorResponseBody.bodyToSerialize()
, and thenRiposteApiExceptionHandler.prepareFrameworkRepresentation(...)
andRiposteUnhandledExceptionHandler.prepareFrameworkRepresentation(...)
for where you'd hook in.- Changed by Alexander Banker in pull request #99.
Released on 2018-02-27.
- Changed
TypesafeConfigServer
to allow you to override theappId
and/orenvironment
that are used to load the properties files: see the new overridableTypesafeConfigServer.getAppIdAndEnvironmentPair()
method.- Changed by jcnorman48 in pull request #96.
Released on 2018-02-14.
StandardEndpoint<InputType, OutputType>
s have been adjusted to throw a "missing expected content" HTTP status code 400 error when the caller does not send a payload andInputType
is anything other thanVoid
. Previously the endpoint would be executed and you'd have to checkRequestInfo.getContent()
manually to see if the caller had sent a payload and throw an error yourself to indicate a missing required payload. This change could result in endpoints throwing 400s to callers when they previously did not. Please double-check yourStandardEndpoint
s - if they have a non-Void
input type but you want payloads to be optional then you can override the newisRequireRequestContent()
endpoint method to returnfalse
to keep the previous behavior of the endpoint allowing missing payloads for non-Void
input types. More details about this change can be found below.
- Added
EurekaVipAddressRoundRobinWithAzAffinityService
to theriposte-service-registration-eureka
module. This service will round-robin requests to instances in the same availability zone as the current server. If there are no instances in the current availability zone, it will round-robin instances in all availability zones. Routing requests this way has the advantage of lower response times and lower data transfer costs. StandardEndpoint<InputType, OutputType>
s will now throw a "missing expected content" HTTP status code 400 error if theInputType
is notVoid
(or more specifically, if therequestContentType()
method returns something besidesnull
orVoid
). This means you no longer have to check ifRequestInfo.getContent()
isnull
for endpoints that specify an input type. i.e. after this feature addition if a caller does not send a payload to aStandardEndpoint<SomeObject, _>
endpoint then they would receive a "missing expected content" 400 error, but if the endpoint was definedStandardEndpoint<Void, _>
then the endpoint would be executed normally. If you need to change this behavior for endpoints where the payload is truly optional you can override the endpoint'sisRequireRequestContent()
method to returnfalse
.- Added by Robert Abeyta in pull request #83.
- Added ability to use
byte[]
as an input type forStandardEndpoint
, e.g.StandardEndpoint<byte[], OutputType>
. This allows you to specify that you require a payload (see previous change) but that you don't want any deserialization done, i.e. you want to handle the raw payload bytes in the endpoint yourself rather than have Riposte try to interpret it. Previously specifyingbyte[]
as an input type would result in a deserialization error.- Added by Nic Munroe in pull request #86.
- Added support for automatic gzip/deflate decompression on incoming requests. This defaults to off for
ProxyRouterEndpoint
so that proxies don't modify payloads as they pass through, but defaults to on for all other endpoint types so that payloads are decompressed beforeStandardEndpoint
s execute and payloads deserialized into whatever input type is needed for the endpoint. If you want to change the default decompression behavior for a given endpoint you can overrideEndpoint.isDecompressRequestPayloadAllowed()
to return whatever you need.- Added by Nic Munroe in pull request #84.
- Added
ServerConfig.responseCompressionThresholdBytes()
to allow you to specify the payload size threshold after which response payloads will be automatically gzip/deflate compressed (assuming the caller supports compressed responses). This feature already existed but was previously hardcoded to 500 bytes.- Added by Nic Munroe in pull request #84.
ProxyRouterEndpoint
s now have the ability to turn off the automatic subspan around the downstream call (using the newDownstreamRequestFirstChunkInfo.withPerformSubSpanAroundDownstreamCall(boolean)
method), and you can now indicate that you do not want tracing headers set on the downstream call (using the newDownstreamRequestFirstChunkInfo.withAddTracingHeadersToDownstreamCall(boolean)
method). Previously Riposte would always surround the downstream call with a subspan, and would always set tracing headers. These new options default to the previous behavior, but you can override them with the new behavior methods.- Added by Robert Abeyta in pull request #88.
- Added options to
ServerConfig
for specifying the max initial line length, max combined header line length, and max chunk size values used when decoding incoming HTTP requests. SeeServerConfig.httpRequestDecoderConfig()
for details.- Added by Nic Munroe in pull request #91.
- Added a
RequestInfo.addRequestAttribute(...)
that exposes how much time was spent waiting for the request payload to arrive (time from first chunk to last chunk), and another for how much time was spent waiting for a connection to be established to the downstream system for aProxyRouterEndpoint
request. Refer toAccessLogStartHandler.REQUEST_PAYLOAD_TRANSFER_TIME_NANOS_REQUEST_ATTR_KEY
andProxyRouterEndpointExecutionHandler.DOWNSTREAM_CALL_CONNECTION_SETUP_TIME_NANOS_REQUEST_ATTR_KEY
in your code for the request attribute keys. You may want to consider adding these to your access logs to help diagnose intermittent slow requests.- Added by Nic Munroe in pull request #94.
- Fixed
ResponseInfo.withCookies(...)
handling when sending responses to serialize the entire NettyCookie
object rather than just name and value. This means the other cookie parameters/properties are now honored and sent as expected, e.g.Max-Age
andHTTPOnly
. Previously any extra properties beyond cookie name and value were not being sent.- Fixed by Robert Abeyta in pull request #82.
- Fixed Riposte interaction with Netty
ByteBuf
when reading incoming request content to use theByteBuf.readerIndex()
rather than assuming index 0. This should have no effect currently but is the correct way to read content fromByteBuf
(future-proofing).- Fixed by Nic Munroe in pull request #85.
- Fixed some corner cases where server request/response metrics were not being updated (e.g. caller dropping their
connection in the middle of the request). In particular this was causing the
inflight_requests
metric to grow over time if these corner case calls were occurring.- Fixed by Nic Munroe in pull request #89.
- Fixed some corner cases where access logs were not being output (e.g. caller dropping their connection in the middle
of the request).
- Also removed span name from access logger output defaults - callers shouldn't be sending this and it's a waste of characters in the log message.
- Fixed by Nic Munroe in pull request #93.
- Fixed
ProxyRouterEndpoint
to no longer send aX-B3-SpanName
on downstream calls. Sending that header is not best practice.- Fixed by Nic Munroe in pull request #90.
- Fixed the Backstopper Riposte framework listener to detect exceptions for requests that have too-long headers and
map them to a 431 HTTP status code rather than a 400. Also adjusted the
error messages and metadata sent to the user in the response when HTTP decoding issues like too-long headers are
encountered to be more informative.
- Fixed by Nic Munroe in pull request #92.
- Updated Wingtips to version
0.14.1
from0.11.2
. Wingtips changelog- Updated by Nic Munroe in pull request #90.
- Updated Backstopper to version
0.11.4
from0.11.1
. Backstopper changelog- Updated by Nic Munroe in pull request #92.
- Updated to Kotlin 1.2.21. Doesn't affect anything except the Kotlin sample.
- Done by Nic Munroe in pull request #87.
Released on 2017-10-26.
- Updated Netty to version
4.0.52.Final
.- Updated by Todd Lisonbee in pull request #73.
Released on 2017-10-26.
- Added the ability to set a default
SignatureCalculator
throughAsyncHttpClientHelper
. ASignatureCalculator
is executed immediately before the HTTP request is fired, allowing last-second adjustments like creating a request signature header for auth purposes.- Added by Robert Abeyta in pull request #74.
- Added fluent style setters to
AsyncHttpClientHelper
for a defaultSignatureCalculator
andperformSubSpanAroundDownstreamCalls
value.- Added by Robert Abeyta in pull request #74.
- Added utility methods to
AsyncNettyHelper
to enable easily creatingCompletableFuture
s with distributed tracing support built-in (with optional subspans) and optional circuit breaker protection.- Added by Robert Abeyta in pull request #72.
Released on 2017-08-11.
- Added helper methods to
SignalFxAwareCodahaleMetricsCollector
for easily creating dimensioned metrics.- Added by Nic Munroe in pull request #68.
- Added Kotlin-based sample (see
samples/sample-2-kotlin-todoservice
).
- Updated Jackson dependency version to 2.8.9.
- Updated by Nic Munroe in pull request #68.
- Upgraded to Gradle 4.1.
- Done by Nic Munroe in pull request #68.
Released on 2017-07-19.
- Fixed
ProxyRouterEndpoint
processing to include the port in theHost
header for the downstream call if the port is not the default for the scheme as per the HTTP spec.- Fixed by Robert Abeyta in pull request #62.
- Added
SignalFxAwareCodahaleMetricsCollector
- aCodahaleMetricsCollector
that uses SignalFx mechanisms for creating metrics so that they will be tagged with the appropriate global/unique dimensions for your application.- Added by Nic Munroe in pull request #65.
- Upgraded to Gradle 4.0.1.
- Done by Nic Munroe in pull request #64
Released on 2017-06-12.
- Fail-fast on too-big request sizes when possible. If content-length header is larger than the configured max request size we will fail immediately without processing the full request payload.
- Reported by Nic Munroe. Fixed by Robert Abeyta in pull request #59. For issue #37.
- Added methods to
RequestBuilderWrapper
to enable a user to set the wrapped content (url and method) and then subsequently updated the wrappedAsyncHttpClient.BoundRequestBuilder
to keep the two in sync. This removed public fields and now they need to be accessed through getter/setter instead.- Reported by Robert Abeyta. Fixed by Robert Abeyta in pull request #57. For issue #56.
- Fixed more corner-case error handling related to
ProxyRouterEndpoint
endpoints.- Fixed by Nic Munroe in pull request #60
- Improved handling of invalid HTTP calls - they will now show up in access logs and metrics.
- Fixed by Nic Munroe in pull request #60
- Added
getPathTemplate
method toRequestInfo
to enable users to get the matching path template used for the request- Reported by Ferhat Sobay. Fixed by Robert Abeyta in pull request #58. For issue #55.
Released on 2017-04-26.
- Removed usage of Netty internal class (
io.netty.util.internal.OneTimeTask
). This prevented use of newer versions of Netty where that class no longer existed.- Reported by Vic Bell. Fixed by Nic Munroe in pull request #52. For issues #50 and #51.
Released on 2017-04-20.
- Fixed distributed tracing headers for the downstream call when handling
ProxyRouterEndpoint
s. The parent span's information was being passed downstream rather than the sub-span created for the downstream call. The trace ID was correct, but if the downstream call continued the trace then its span would be pointing at the wrong parent. This was fixed to correctly use the sub-span.- Fixed by Nic Munroe in pull request #47
- Fixed several issues related to
ProxyRouterEndpoint
handling:- Fixed incorrect Netty reference counting handling. This could lead to leaks or incorrect over-decrementing. If you saw
LEAK: ByteBuf.release() was not called before it's garbage-collected
orIllegalReferenceCountException
s in your logs for data handled by Riposte (i.e. not your application-specific code) then this should now be fixed. - Fixed some race conditions that could lead to requests not being processed correctly.
- Better internal corner-case error handling, leading to less log spam warnings.
- Improved logging when corner case errors do pop up. If a request is handled in an unexpected way and you have the trace ID from the response headers, then the logs should give you better insight into what happened (e.g. the caller or downstream system dropping connection partway through a request).
- Fixed by Nic Munroe in pull request #48
- Fixed incorrect Netty reference counting handling. This could lead to leaks or incorrect over-decrementing. If you saw
Released on 2017-04-18.
- Refactored the Codahale/Dropwizard metrics system (see
CodahaleMetricsListener
,CodahaleMetricsListener.Builder
,EndpointMetricsHandler
, andSignalFxEndpointMetricsHandler
for details on the following):- You can now set custom metric names and customize
Timer
/Histogram
creation (e.g. so you can use differentReservoir
s). - Endpoint metrics handling has been split out into a
EndpointMetricsHandler
interface, allowing you full flexibility for handling endpoint-specific metrics related to requests and responses. A default impl (EndpointMetricsHandlerDefaultImpl
) is used for Graphite-style conventions if you don't specify a different impl. - SignalFx support has been added via the
riposte-metrics-codahale-signalfx
module. Wire it up usingSignalFxReporterFactory
andSignalFxEndpointMetricsHandler
. - All of this should be opt-in only, i.e. existing Riposte projects using the Codahale metrics system should continue to behave the same way.
- Added by Nic Munroe in pull request #42.
- You can now set custom metric names and customize
Released on 2017-03-17.
- Fixed Riposte to honor the
ServerConfig.maxRequestSizeInBytes()
setting. You can use this to limit incoming request payload size at a global level, with the option to override on a per-endpoint basis viaEndpoint.maxRequestSizeInBytesOverride()
. Previously thisServerConfig
setting existed but was ignored and had no effect.- Fixed by Robert Abeyta in pull request #28. For issue #27.
- Fixed
ProxyRouterEndpoint
s so that they will honor any incoming content-length header rather than the previous behavior of removing content-length and replacing it with transfer-encoding=chunked.- Fixed by Robert Abeyta in pull request #30. For issue #29.
- Fixed request handling to detect when Netty marks a request chunk as a decoder failure (i.e. bad/non-HTTP spec requests). These errors will now be mapped to an appropriate HTTP status code 400 response for the caller. Previously this was incorrectly resulting in a 404-not-found response.
- Fixed by Robert Abeyta in pull request #33. For issue #32.
Released on 2017-02-28.
- Added ability for
RequestAndResponseFilter
to be executed before or after security validation depending on the value ofRequestAndResponseFilter.shouldExecuteBeforeSecurityValidation()
.- Added by Robert Abeyta in pull request #20. For issue #15.
- Added functionality to detect bad or incomplete HTTP calls and return an appropriate error to the caller in those cases. Timeout value controlled via the new
ServerConfig.incompleteHttpCallTimeoutMillis()
config option.- Added by Nic Munroe in pull request #24.
- Updated Backstopper dependency version to 0.11.1. This version added convenience constructor to
ApiErrorWithMetadata
that takes a vararg ofPair<String, Object>
so that you can inline the extra metadata without having to create and populate aMap
separately.- Updated by Nic Munroe in pull request #25.
Released on 2017-02-15.
- Updated Fastbreak dependency version to 0.10.0. This should be an invisible update for most users, however it might require a minor refactor if you used Fastbreak's manual/callback mode in your code. Now, instead of calling
throwExceptionIfCircuitBreakerIsOpen()
,handleEvent(...)
, andhandleException(...)
directly onCircuitBreaker
you must first callCircuitBreaker.newManualModeTask()
which will return aManualModeTask
interface. ThatManualModeTask
interface now contains the methods that were moved out ofCircuitBreaker
.- Updated by Nic Munroe.
Released on 2016-12-12.
- Added
Forbidden403Exception
typed exception for 403/forbidden responses.- Added by Paul Evans in pull request #7.
- Fixed request path to be URL decoded by default. This also fixes path parameters so they are URL decoded by default as well.
- Fixed by Robert Abeyta in pull request #12. For issue #11.
- Fixed
CodahaleMetricsListener
to support short circuiting non-endpoint calls (e.g. short circuiting request filters).- Fixed by Nic Munroe in pull request #13.
- Updated Backstopper dependency version to 0.11.0 (backstopper changelog).
- Updated by Nic Munroe in pull request #13.
Released on 2016-11-04.
- Updated Backstopper dependency version to 0.9.2.
- Updated by Nic Munroe.
Released on 2016-11-03.
- Initial open source code drop for Riposte.
- Added by Nic Munroe.