Handling HTTP Requests

    Also, the call itself has some useful convenience properties and methods that rely on the request.

    Table of contents:

    When using the feature, or when intercepting requests, you can accessthe call property inside handlers. That call includes a request property with relevant information about the request:

    Request information

    As part of the request, you can get access to its internal context:

    1. val call: ApplicationCall = request.call
    2. val pipeline: ApplicationReceivePipeline = request.pipeline
    1. val version: String = request.httpVersion // "HTTP/1.1"
    2. val uri: String = request.uri // Short cut for `origin.uri`
    3. val scheme: String = request.origin.scheme // "http" or "https"
    4. val host: String? = request.host() // The host part without the port
    5. val port: Int = request.port() // Port of request
    6. val path: String = request.path() // The uri without the query string
    7. val document: String = request.document() // The last component after '/' of the uri
    8. val remoteHost: String = request.origin.remoteHost // The IP address of the client doing the request

    Reverse proxy support: origin and local

    When behind a reverse-proxy (for example an nginx or a load balancer), the received request is not performed by the end-user, but that reverse proxy.That means that the client IP address of the connection would be the one of the proxy instead of the client.Also the reverse proxy might be serving via HTTPS and requesting to your server via HTTP.Popular reverse proxies send X-Forwarded- headers to be able to access this information.

    Note that for this to work when under a reverse-proxy you have to install the XForwardedHeaderSupport feature.

    As part of the request object, there are two properties local and origin that allows to get information of the original requestor the local/proxied one.

    1. val local : RequestConnectionPoint = request.local // Local information
    2. val origin: RequestConnectionPoint = request.origin // Local / Origin if XForwardedHeaderSupport feature is installed.

    The local/origin information you can get:

    1. interface RequestConnectionPoint {
    2. val scheme: String // "http" or "https": The provided protocol (local) or `X-Forwarded-Proto`
    3. val version: String // "HTTP/1.1"
    4. val port: Int
    5. val host: String // The provided host (local) or `X-Forwarded-Host`
    6. val uri: String
    7. val method: HttpMethod
    8. val remoteHost: String // The client IP (the direct ip for `local`, or the redirected one `X-Forwarded-For`)
    9. }

    You can also access the raw queryString (param1=value&param2=value):

    1. val queryString: String = request.queryString()

    POST, PUT and PATCH

    POST, PUT and PATCH requests has an associated request body (the payload).That payload is usually encoded.

    All the receive methods consume the whole payload sent by the client so an attempt to receive a request body twicewill lead to RequestAlreadyConsumedException error unless you have DoubleReceive feature installed.

    To access the raw bits of the payload, you can use receiveChannel, but it isdirectly part of the call instead of call.request:

    1. val channel: ByteReadChannel = call.receiveChannel()

    And it provide some convenience methods for common types:

    1. val channel: ByteReadChannel = call.receiveChannel()
    2. val text: String = call.receiveText()
    3. val inputStream: InputStream = call.receiveStream() // NOTE: InputStream is synchronous and blocks the thread
    4. val multipart: MultiPartData = call.receiveMultipart()

    All those receive* methods are aliases of call.receive<T> with the specified type.The types ByteReadChannel, ByteArray, InputStream, MultiPartData, String and Parameters are handled byApplicationReceivePipeline.installDefaultTransformations that is installed by default.

    Form Parameters (urlencoded or multipart)

    To parse a form urlencoded or with multipart, you can use receiveParameters or receive<Parameters>:

    1. val postParameters: Parameters = call.receiveParameters()

    The call also supports receiving generic objects:

    1. install(ContentNegotiation) {
    2. gson {
    3. setDateFormat(DateFormat.LONG)
    4. setPrettyPrinting()

    If you configure the ContentNegotiation to use gson,you will need to include the ktor-gson artifact:

    1. compile("io.ktor:ktor-gson:$ktor_version")

    Then you can, as an example, do:

    1. data class HelloWorld(val hello: String)
    2. routing {
    3. post("/route") {
    4. val helloWorld = call.receive<HelloWorld>()
    5. }
    6. }

    Remember that your classes must be defined top level (outside of any other class or function) to be recognized by Gson.

    Multipart, Files and Uploads

    Check the section.

    You can create custom transformers by callingapplication.receivePipeline.intercept(ApplicationReceivePipeline.Transform) { query ->and then calling proceedWith(ApplicationReceiveRequest(query.type, transformed)) as does the ContentNegotiation feature.

    There is a cookies property to access the Cookie headers sent by the client,just as if it was a collection:

    1. val cookies: RequestCookies = request.cookies
    2. val mycookie: String? = request.cookies["mycookie"]

    To handle sessions using cookies, have a look to the feature.

    Headers

    To access the headers the request objects has a headers: Headers property.It implements the StringValues interface where each key can have a list of Strings associated with it.

    1. val contentType: ContentType = request.contentType() // Parsed Content-Tpe
    2. val contentCharset: Charset? = request.contentCharset() // Content-Type JVM charset
    3. val authorization: String? = request.authorization() // Authorization header
    4. val location: String? = request.location() // Location header
    5. val accept: String? = request.accept() // Accept header
    6. val acceptItems: List<HeaderValue> = request.acceptItems() // Parsed items of Accept header
    7. val acceptEncoding: String? = request.acceptEncoding() // Accept-Encoding header
    8. val acceptEncodingItems: List<HeaderValue> = request.acceptEncodingItems() // Parsed Accept-Encoding items
    9. val acceptLanguage: String? = request.acceptLanguage() // Accept-Language header
    10. val acceptLanguageItems: List<HeaderValue> = request.acceptLanguageItems() // Parsed Accept-Language items
    11. val acceptCharset: String? = request.acceptCharset() // Accept-Charset header
    12. val acceptCharsetItems: List<HeaderValue> = request.acceptCharsetItems() // Parsed Accept-Charset items
    13. val userAgent: String? = request.userAgent() // User-Agent header
    14. val cacheControl: String? = request.cacheControl() // Cache-Control header
    15. val ranges: RangesSpecifier? = request.ranges() // Parsed Ranges header
    16. val isMultipart: Boolean = request.isMultipart() // Content-Type matches Multipart