Migrating 0.9.3 → 0.9.4

Estimated reading time: 6 minutes


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.



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


Minor potentially breaking changes:

  • URL building: Set the default port too when changing the protocol
  • Prohibit appending unsafe headers to request headers
  • Client: the io.ktor:ktor-client-json artifact has been renamed to io.ktor:io.ktor:ktor-client-gson (to support a new JacksonSerializer)
  • Now all the Client JSON-related (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 included
  • Changed Date to GMTDate in some specific internal places
  • Internal Client HttpRequest, HttpResponse and HttpRequestData changes
  • Package io.ktor.content moved to io.ktor.http.content
  • Top-level 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
  • Now PartData has a new element PartData.BinaryItem, thus might require an additional branch or an else to be exhaustive when used in a expression


  • Netty: fix write pipeline to not drop connection too early. Large responses are not completely sent with ‘Connection: close’ (#534)
  • Fixes CharBufferBuilder issue: CIO Responses with more than 2048 characters in header result in IndexOutOfBoundsException (#419)
  • Fix push promise headers order with Netty and HTTP/2
  • Eliminate sending transfer-encoding sending with Netty and HTTP/2
  • Fixed encoding issue with binary data in TestApplicationRequest.setBody
  • Fix native Deflater leak (#489)
  • Fix resourceResource to check for regular file to prevent failing later with folders (#490)
  • Fix StringIndexOutOfBoundsException in static resource resolution (#493)
  • Fixes: When config is passed via -config=<filename>, environment variables are not resolved (#374)
  • Fixes Client connection close in pipelining
  • TLS: Fix exception on expected channel close
  • Fix Jetty client engine response cancel
  • Compression: fix messages with predefined identity encoding
  • Fix HTTP 417 status message
  • Fix JWT error handling for missing keyId or broken token
  • CIO: fix duplicate content-length header handling
  • Fix CIO pipeline to not interrupt write pipeline. This was causing pipeline to be cancelled and 400 Bad Request response was lost
  • Fix closed byte channel error handling for WriteChannelContent
  • Fix CIO client joining
  • Fix race responding bytes that caused an empty response with Netty relates to issue #350
  • Avoid closing ServletOutputStream even in case of error
  • Suppress already completed AsyncContext error
  • Handle response cancel in Jetty client engine
  • Make SessionTransportTransformerEncrypt return null on failure
  • Fix client attributes evaluation


  • Use garbage-free headers API in Netty
  • Avoid unnecessary allocations in Pipeline#merge
  • Improve best function selection in ApplicationEngineEnvironmentReloading
  • Do not scan classpath on every HttpClient instantiation, provide better error message

Improvements to existing APIs:

  • JWK: add verify configuration with optional issuer
  • Url and URLBuilder improvements
  • Make TypeInfo a data class (#459) (#471)
  • Testing: Add advanced test exception logging

  • Add client form data and multipart support (#500)
  • Add HttpStatusCode constants for the status codes defined in RFC 2518 (WebDAV)

  • Add jetty server engine failed callback handler(http2)
  • Wrap Jetty channel fail into ChannelIOException
  • Wrap client exception from response pipeline with request and typeInfo

  • Add utility to append header value (such as content type)

  • Improve netty response pipeline for HTTP/2 case
  • Set default random algorithm from system provided

New features:

  • New multiplatform HTTP Client:
  • Add initial webjars feature (#498)
  • Add EngineAPI marker annotation
  • Add JacksonSerializer to HTTP Client
  • Client: Add HttpResponse.receive method
  • Client: Add default request configurator
  • Client: New way to configure or reconfigure the HttpClient Engine

Internal changes:

  • Internal: Update modules layout

New multiplatform HTTP Client

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.

Reconfiguring the HttpClientEngineConfig

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.

Client HttpRequest, HttpResponse and HttpRequestData changes

Previously 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.