Table of contents:
This is the third beta of Ktor. And the first version of Ktor using Kotlin 1.3.0 and kotlinx.coroutines 1.0.0 final versions!
Published 29 Oct 2018
Version bumps:
Kotlin: 1.3.0-rc-146 -> 1.3.0
Kotlinx IO: 0.1.0-alpha-25-rc13 -> 0.1.0-beta-1
Kotlinx Coroutines: 1.0.0-RC1 -> 1.0.0
Kotlinx Serialization: 0.8.2-rc13 -> 0.9.0
AtomicFU: 0.11.11 -> 0.11.12
Improvements:
Fixes:
Minor:
You need to use Kotlin 1.3.0
or later. That version should be available at Maven Central and jcenter:
buildscript {
ext.kotlin_version = '1.3.0'
}
You will also need to use the Kotlin 1.3 inside IntelliJ IDEA.
This is the second beta of Ktor.
Published 24 Oct 2018
Version bumps:
Kotlin: 1.3.0-rc-131 -> 1.3.0-rc-146
Kotlinx IO: 0.1.0-alpha-19-rc13 -> 0.1.0-alpha-25-rc13
Kotlinx Coroutines: 0.30.2-eap13 -> 1.0.0-RC1
AtomicFU: 0.11.10-eap13 -> 0.11.11
Major changes:
Marked as experimental:
Deprecations:
Added:
Minor changes:
Improvements:
Fixes:
Removed:
You need to include kotlin-eap
repository and use Kotlin 1.3.0-rc-146
or later:
buildscript {
ext.kotlin_version = '1.3.0-rc-146'
repositories {
// ...
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
}
}
repositories {
// ...
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
maven { url 'https://dl.bintray.com/kotlin/kotlinx' }
maven { url 'https://dl.bintray.com/kotlin/ktor' }
jcenter()
}
You will also need to use the Early Access Preview 1.3 inside IntelliJ IDEA.
To do so, Tools -> Kotlin -> Configure Kotlin Updates
and as Update Channel, select Early Access Preview 1.3
and install that version of the plugin.
DevelopmentEngine
to EngineMain
We have renamed the DevelopmentEngine
classes to EngineMain
, and you will have to update your application.conf
configuration files.
The DevelopmentEngine
classes were used as entry point for Ktor applications. It loaded the application.conf
and parsed CLI parameters, in addition to
create an embedded server and loading the specified module.
The problem with DevelopmentEngine
was that it was confusing since some people identified Development
as opposed to Production
.
The new name reflects that it serves as entry point of the application, and that it is independent on the environment being suitable for both: development and production.
This is the first beta of Ktor! This page includes changes from the alpha-2, alpha-3 and beta-1.
Published 15 Oct 2018
Version bumps:
Kotlinx IO: 0.1.0-alpha-17-rc13 -> 0.1.0-alpha-19-rc13
Additions:
Improvements:
Fixes:
Performance improvements:
Documentation:
Minor and cleanups:
You need to include kotlin-eap
repository and use Kotlin 1.3.0-rc-131
or later:
buildscript {
ext.kotlin_version = '1.3.0-rc-131'
repositories {
// ...
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
}
}
repositories {
// ...
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
maven { url 'https://dl.bintray.com/kotlin/kotlinx' }
maven { url 'https://dl.bintray.com/kotlin/ktor' }
jcenter()
}
You will also need to use the Early Access Preview 1.3 inside IntelliJ IDEA.
To do so, Tools -> Kotlin -> Configure Kotlin Updates
and as Update Channel, select Early Access Preview 1.3
and install that version of the plugin.
Ktor 1.0.0-alpha-1
is the initial pre-release version that preludes the 1.0.
This version is the first one using Kotlin 1.3.0-rc-131
, and bumps the kotlinx.coroutines
version to 0.30.2-eap13
.
As an important change, Ktor now uses the structured concurrency from kotlinx.coroutines
.
In addition it adds
Published 9 Oct 2018
Version Bumps:
Kotlin: 1.2.70 -> 1.3.0-rc-131
Kotlinx IO: 0.1.0-alpha-4 -> 0.1.0-alpha-17-rc13
Kotlinx Coroutines: 0.25.0 -> 0.30.2-eap13
Atomic FU: 0.11.3 -> 0.11.10-eap13
Major changes:
Deprecations, renames and API changes:
ByteBufferBuilder
RoutingException
-> LocationRoutingException
HttpMessageBuilder.contentLength()
and HttpMessage.contentLength()
now return LongWebSocketInternalAPI
)AndroidClientEngine
is now @UseExperimental(InternalAPI::class)
ApacheBackend
typealias for Apache
engineFixes:
Cookie.matches
ignore a leading dot in the domainAdditions:
TestApplicationEngine.cookiesSession
https://github.com/ktorio/ktor/commit/1af97b8fcb3096cb390480508c4abd49c13a34deContentTypes.CSV
#613IosClientEngineConfig
Added call.responseConfig.defaultCharset |
HttpResponseConfig |
Improvements:
Minor changes:
kotlin.code.style=official
Since 1.0.0-alpha-1, Ktor is using the latest kotlinx.coroutines version that is using structured concurrency.
Now each request has its own CoroutineScope
and you can also use the GlobalScope
.
For more information: https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/basics.md#structured-concurrency
Ktor 0.9.5 is a minor update, fixing some bugs, bumping some versions, and adding some minor stuff.
Published 19 Sep 2018
Version Bumps:
Kotlin: 1.2.61 -> 1.2.70
Minor potential breaking changes:
CookiesStorage.get
, CookiesStorage.addCookie
and HttpCookies.get
now accepts the requestUrl
instead of the host. Now the get returns a list of cookies.HttpRequest.takeFrom(builder: HttpRequestBuilder): HttpRequestBuilder
. Now also sets the typed call attributes from the builder
.
into a member method. Shouldn’t be a source compatibility problem when using star imports *
since it is in the same package.Fixes:
HttpClient.config
was not preserving the base configuration (#559)URLBuilder
(#577).Additions:
CallId
featureMDC
support to CallLogging
featureAPI Improvements:
HEAD
, OPTIONS
, PATCH
and DELETE
methods (#562)List<Cookie>.get(name: String): Cookie?
shortcut.fun FormBuilder.append(key: String, filename: String, block: BytePacketBuilder.() -> Unit)
to the FORM DSL.respondOutputStream { }
response functionInfrastructure
phase into Monitoring
and Features
phasesInternal:
AcceptAllCookiesStorage
be the same for all the implementations.Before 0.9.5, when using the HTTP client and wanting to make a HEAD
, OPTIONS
, PATCH
or DELETE
request,
you had to either use the HttpClient.request
or the HttpClient.call
.
As for 0.9.5, in addition to HttpClient.get
and HttpClient.post
there are now four more convenience methods
HttpClient.head
, HttpClient.options
, HttpClient.patch
and HttpClient.delete
HTTP verbs.
Infrastructure
phase into Monitoring
and Features
phasesIn most of the cases, you should use the Features
phase instead of the Infrastructure
one:
intercept(ApplicationCallPipeline.Infrastructure) {
// ...
}
would become:
intercept(ApplicationCallPipeline.Features) {
// ...
}
The CallLogging feature have been updated to allow to specify MDC (Mapped Diagnostic Context) keys + providers to be associated to a specific call/request regardless of the ThreadScheduler. The feature is implemented using kotlinx.coroutines ThreadContextElement, so it is transparent and works well with slf4j.
0.9.5 includes a new CallId
feature that allows to identify calls from an ID. It allows to provide several methods
for receiving or generating that Call Identifier, and also optionally allows to include the id as part of the response,
for example as a header. The CallId is also associated to the MDC of the call, so the logs for a specific call can be
identified and grouped together.
Ktor 0.9.4 fixes some bugs, bumps some versions, moves a few classes, improves the overall performance of the server. This version deprecate some APIs, introduce new ones, and includes a new multiplatform HTTP client (initially supporting JVM, iOS and Android).
This version is expected to be mostly source-code compatible with 0.9.3 except for the deprecate APIs.
https://github.com/ktorio/ktor/compare/0.9.3...0.9.4
Published 29 Aug 2018
Version Bumps:
Kotlin: 1.2.50 -> 1.2.61
kotlin-native -> 0.8.2
jetty_alpn_boot_version: 8.1.11.v20170118 -> 8.1.12.v20180117
coroutines_version: 0.23.3 -> 0.25.0
atomic_fu_version: -> 0.11.3
kotlinx_io_version: -> 0.1.0-alpha-4
Deprecations:
response.contentType
and response.contentLength
extensions (UnsafeHeaderException: Header Content is controlled by the engine and cannot be set explicitly
)IncomingContent
deprecation, prepare for complete removalXForwardedHeadersSupport
to XForwardedHeaderSupport
(#547)Minor potentially breaking changes:
io.ktor:ktor-client-json
artifact has been renamed to io.ktor:io.ktor:ktor-client-gson
(to support a new JacksonSerializer)ktor-client-json
, ktor-client-gson
and ktor-client-jackson
) artifacts require the kotlinx.serialization
and thus require the maven { url "https://kotlin.bintray.com/kotlinx" }
repo to be includedDate
to GMTDate
in some specific internal placesHttpRequest
, HttpResponse
and HttpRequestData
changesio.ktor.content
moved to io.ktor.http.content
encodeURLQueryComponent
method is now a extension method of String fun String.encodeURLQueryComponent()
PartData.FileItem
now requires a lambda with an Input
, instead of an InputStream
PartData
has a new element PartData.BinaryItem
, thus might require an additional branch or an else to be exhaustive when used in a expressionFixes:
CharBufferBuilder
issue: CIO Responses with more than 2048 characters in header result in IndexOutOfBoundsException
(#419)TestApplicationRequest.setBody
StringIndexOutOfBoundsException
in static resource resolution (#493)-config=<filename>
, environment variables are not resolved (#374)AsyncContext
errorSessionTransportTransformerEncrypt
return null on failureOptimizations:
HttpClient
instantiation, provide better error messageImprovements to existing APIs:
Testing: Add advanced test exception logging
Add HttpStatusCode
constants for the status codes defined in RFC 2518 (WebDAV)
ChannelIOException
Wrap client exception from response pipeline with request and typeInfo
Add utility to append header value (such as content type)
New features:
EngineAPI
marker annotationJacksonSerializer
to HTTP ClientHttpResponse.receive
methodInternal changes:
Starting with Ktor 0.9.4, there is a MPP HTTP Client included with Ktor.
In 0.9.4, the client is implemented for the JVM, Android and iOS.
We provide a sample of this feature as part of the ktor-samples repo: ktor-samples/client-mpp
You can read more about this feature in the Multiplatform HTTP Client page.
Prior to 0.9.4, you had to configure the HttpClient Engine by:
HttpClient(MyEngine.config {
// ... config ...
}) {
install {
}
}
Since 0.9.4, HttpClientConfig
provides an engine
method to reconfigure or configure the HttpClientEngineConfig
:
HttpClient(MyEngine) {
engine {
// ... config ...
}
install {
}
}
Since 0.9.4, and after a period of deprecation, Ktor started to completely forbid to set contentType
and contentLength
headers directly.
This is because those are bound to the OutgoingContent
instances, that is the object describing the body of the response.
The respondText
, respondBytes
and other methods, allow you to set the Content-Type as an optional argument.
And when using any subtype of OutgoingContent
, you can set the contentType
there.
For more information about this topic, check the Generating HTTP Responses page.
In some places (like Client HttpResponse
) we were using Java’s Date
class. Now we are using GMTDate
instead.
HttpRequest
, HttpResponse
and HttpRequestData
changesPreviously the HttpRequestData
, had an attributes method to build an Attributes
instance from another.
Now it is a property instead. Attributes().apply { data.attributes(this) }
would become data.attributes
.
This change, affects, for example when implementing a HttpRequest
:
override val attributes: Attributes = Attributes().apply { data.attributes(this) }
// -->
//override val attributes: Attributes = data.attributes
And the HttpResponse
changed its requestTime
and responseTime
from java’s Date
to io.ktor.util.date.GMTDate
.
Ktor 0.9.3 fixes some bugs, bumps some versions, improves the overall performance of the server, and introduces new APIs and changes for some of them.
This version is expected to be mostly source-code compatible with 0.9.2
except for advanced use-cases related with kotlinx.coroutines
and Ktor Raw sockets.
kotlinx.coroutines
.ktor raw sockets
.https://github.com/ktorio/ktor/compare/0.9.2...0.9.3
Published 26 Jun 2018
Now webSocketSession
and webSocketRawSession
return DefaultClientWebSocketSession
and webSocket
, ws
and wss
methods also receives a DefaultClientWebSocketSession
and other methods
return a ClientWebSocketSession
.
This prevents having to cast to access some properties from the client session:
var DefaultWebSocketSession.pingInterval: Duration?
var DefaultWebSocketSession.timeout: Duration
val DefaultWebSocketSession.closeReason: Deferred<CloseReason?>
var DefaultClientWebSocketSession.masking: Boolean
We had a MockEngine
available internally for our tests for creating an HttpClient that was able to respond
from our code programmatically without actually performing any request.
We have now exposed it in the io.ktor:ktor-client-mock
artifact.
For example:
val mockEngine = MockEngine { call -> // suspend HttpRequest.(call: HttpClientCall) -> MockHttpResponse
assertEquals("*/*", headers[HttpHeaders.Accept])
MockHttpResponse(call, HttpStatusCode.OK, writer(ioCoroutineDispatcher) { channel.writeStringUtf8("HELLO") }.channel, headersOf(
"X-Custom-Header" to listOf("value")
))
}
val client = HttpClient(mockEngine)
Inside the MockEngine block, you can assert things from the request, or decide how to generate a response based on the request.
Now you can instantiate a HttpClient by just HttpClient()
without providing an engine.
In that case it will use a ServiceLoader
to find a suitable implementation based on the artifacts you have included.
Now you can use the new client HttpRedirect feature to follow HTTP Location
-based redirections.
Read the documentation for more information.
Now the HttpClient sends cookies in a standard way with one single header separating cookies by ;
.
Reading an empty body as String with an Httpclient (HttpClient.get<String>
) was causing a
No transformation found: class io.ktor.client.engine.apache.ApacheHttpResponse -> class kotlin.String
exception.
HttpClientEngine now has a config
field. So you will have to provide it in the case you have a custom engine.
Now the HttpClient sends an Accept
header. If you have a test checking all the headers, you will need to update them.
Ktor implements secure sockets using CIO, and the TLS available before 0.9.3 missed some cypher suites and encryption methods. We have updated it to support more required stuff.
Some errors you could encounter that now might be fixed:
Exception in thread "io-thread-1" io.ktor.network.tls.TLSException: Received alert during handshake. Level: FATAL, code: HandshakeFailure
Exception in thread "io-thread-2" io.ktor.network.tls.TLSException: Unsupported TLS handshake type CertificateRequest
aSocket
now requires a SelectorManager to be provided.
For example:
aSocket(ActorSelectorManager(ioCoroutineDispatcher))
Of course, you can reuse the SelectorManager:
val mySocketSelector = ActorSelectorManager(ioCoroutineDispatcher)
val socket = aSocket(mySocketSelector).tcp()
Before 0.9.3, when a WS request was made without the Sec-WebSocket-Key
header,
an IllegalArgumentException
was thrown. Now it is optional.
Now it is possible to define a set of routes where you can provide authentication, but it is optional:
authenticate("method", optional = true) {
// routes
}
The authenticate behaviour:
optional=false
: challenge is performedoptional=true
: route handler is executed with principal=nullBefore 0.9.3 we had call.respondText
but missed call.respondBytes
. We have solved this.
Ktor now uses Kotlin 1.2.50
and kotlinx.coroutines 0.23.3
.
kotlinx.coroutines has some breaking changes for advanced use-cases.
We have moved the generateCertificate
function for generating self-signed certificates to the ktor-network-tls
artifact:
compile("io.ktor:ktor-network-tls:$ktor_version")
Before 0.9.3, we had several sample projects integrated directly in the ktor repository. They have grown, and we have moved them to their own repository: https://github.com/ktorio/ktor-samples
Ktor 0.9.2 fixes some bugs, improves the overall performance of the server, partially starts supporting JVM 9, and introduces new APIs and changes for some of them.
In this section, we will discuss how to convert existing code from 0.9.1 to 0.9.2.
The biggest change in this version since 0.9.1, is authentication. Which has been redesigned:
In previous versions, you had to define an authentication
block inside your Application or in a Route block,
applying that authentication to all the subroutes matching that block.
That forced you to redefine several authentication providers, or in some cases that would force you to include authentication in unexpected routes.
authentication {
basicAuthentication("ktor") { credentials ->
if (credentials.password == "${credentials.name}123") UserIdPrincipal(credentials.name) else null
}
}
In 0.9.2, all the authentication mechanisms are defined at the Application level and have an optional name associated with them. Also, the method names for defining different mechanisms have changed. Now the new name of the authentication mechanism is part of the function call, and all its old parameters are defined using a DSL instead.
For example, to define a basic authentication myauth1
, you should add this code to your application configuration:
install(Authentication) {
basic(name = "myauth1") {
realm = "Ktor Server"
validate { credentials ->
if (credentials.password == "${credentials.name}123") UserIdPrincipal(credentials.name) else null
}
}
}
And now you can create a Route node to apply the defined authentication to several routes using the authenticate
method:
routing {
authenticate("myauth1") {
get("/authenticated/route1") {
// ...
}
get("/other/route2") {
// ...
}
}
get("/") {
// ...
}
}
Authentication method name changes:
basicAuthentication
→ basic
formAuthentication
→ form
digestAuthentication
→ digest
jwtAuthentication
→ jwt
oauthAuthentication
→ oauth
You can read the new authentication page to see in detail how to use the new methods.
The body
property from TestApplicationRequest
builder has been changed to a suspend setBody
method:
handleRequest(HttpMethod.Post, "/") {
addHeader("Accept", "text/plain")
addHeader("Content-Type", "application/json")
//body = """{"id":1,"title":"Hello, World!"}"""
setBody("""{"id":1,"title":"Hello, World!"}""")
}.response.let { response ->
// ...
}
Before 0.9.2, you had to call the method awaitCompletion
in the response in the case the request
was not generating the response body synchronously. In 0.9.2, the awaitCompletion
method doesn’t exist,
and it awaits completion automatically before returning the response.
If you are using call.request.receiveContent().readChannel()
, call.request.receiveContent().multiPartData()
or call.request.receiveContent().inputStream()
, you should consider changing it to
call.receive<ByteReadChannel>()
, call.receive<MultiPartData>()
and/or call.receive<InputStream>()
since it is deprecated and will be removed in future versions of Ktor.
Also, remember that InputStream
is a synchronous API, so you should avoid it if possible.
In order to support WebSockets at the client side, we have changed some of the transitive dependencies
and moved some classes: now there is a transitive dependency called ktor-http-cio
that includes common
WebSockets code among other things, which the ktor-websockets
server feature depends on.
But since it is a transitive dependency, that should be transparent to you.
Classes like WebSocketSession
and Frame
have been moved from the io.ktor.websocket
package to the
io.ktor.http.cio.websocket
package.
import io.ktor.websocket.*
→
import io.ktor.http.cio.websocket.*
When building a new CIO HttpClient, while configuring the endpoint
(it has been renamed from endpointConfig
to endpoint
, and now the property is immutable,
so you have to mutate its contents):
Prior to 0.9.2:
val client = HttpClient(CIO.config {
endpointConfig = EndpointConfig().apply {
}
})
After 0.9.2:
val client = HttpClient(CIO.config {
endpoint.apply {
// ...
}
})