Skip to content

Commit

Permalink
Improve documentation, API cleanup, introduce experimental annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergey Mashkov committed Oct 11, 2018
1 parent bb58e27 commit 42ae9e7
Show file tree
Hide file tree
Showing 283 changed files with 3,578 additions and 542 deletions.
4 changes: 2 additions & 2 deletions gradle/common.gradle
Expand Up @@ -11,11 +11,11 @@ sourceSets {


compileKotlinCommon {
kotlinOptions.freeCompilerArgs += ['-Xuse-experimental=kotlin.Experimental']
kotlinOptions.freeCompilerArgs += ['-Xuse-experimental=kotlin.Experimental,io.ktor.util.KtorExperimentalAPI,io.ktor.util.InternalAPI']
}

compileTestKotlinCommon {
kotlinOptions.freeCompilerArgs += ['-Xuse-experimental=kotlin.Experimental']
kotlinOptions.freeCompilerArgs += ['-Xuse-experimental=kotlin.Experimental,io.ktor.util.KtorExperimentalAPI,io.ktor.util.InternalAPI']
}

dependencies {
Expand Down
4 changes: 2 additions & 2 deletions gradle/jvm.gradle
Expand Up @@ -77,9 +77,9 @@ jar {
}

compileKotlin {
kotlinOptions.freeCompilerArgs += ['-Xuse-experimental=kotlin.Experimental']
kotlinOptions.freeCompilerArgs += ['-Xuse-experimental=kotlin.Experimental,io.ktor.util.KtorExperimentalAPI,io.ktor.util.InternalAPI']
}

compileTestKotlin {
kotlinOptions.freeCompilerArgs += ['-Xuse-experimental=kotlin.Experimental']
kotlinOptions.freeCompilerArgs += ['-Xuse-experimental=kotlin.Experimental,io.ktor.util.KtorExperimentalAPI,io.ktor.util.InternalAPI']
}
4 changes: 2 additions & 2 deletions gradle/native.gradle
Expand Up @@ -5,14 +5,14 @@ sourceSets {
component {
targets = ['ios_arm64', 'ios_x64', 'macos_x64']
outputKinds = [KLIBRARY]
extraOpts '--disable', 'devirtualization'
extraOpts '--disable', 'devirtualization', '-Xuse-experimental', 'io.ktor.util.KtorExperimentalAPI,io.ktor.util.InternalAPI'
}
}
test {
kotlin.srcDir 'test'
component {
targets = ['ios_arm64', 'ios_x64', 'macos_x64']
extraOpts '--disable', 'devirtualization'
extraOpts '--disable', 'devirtualization', '-Xuse-experimental', 'io.ktor.util.KtorExperimentalAPI,io.ktor.util.InternalAPI'
}
}
}
Expand Down
Expand Up @@ -18,7 +18,6 @@ import kotlin.coroutines.*
/**
* Android client engine
*/
@UseExperimental(InternalAPI::class)
class AndroidClientEngine(override val config: AndroidEngineConfig) : HttpClientJvmEngine("ktor-android") {

override suspend fun execute(
Expand Down
@@ -1,11 +1,9 @@
package io.ktor.client.engine

import io.ktor.util.*
import kotlinx.coroutines.*
import kotlinx.coroutines.scheduling.*
import kotlin.coroutines.*

@UseExperimental(InternalAPI::class)
abstract class HttpClientJvmEngine(engineName: String) : HttpClientEngine {
private val supervisor = SupervisorJob()

Expand Down
@@ -1,24 +1,31 @@
package io.ktor.client.utils

import io.ktor.network.util.*
import io.ktor.util.*
import kotlinx.coroutines.*
import kotlinx.io.pool.*
import java.nio.*

private val cpuCount: Int = Runtime.getRuntime().availableProcessors()

@Deprecated(
"HTTP_CLIENT_THREAD_COUNT is deprecated. Use [HttpClientEngineConfig.threadsCount] instead.",
level = DeprecationLevel.ERROR
)
actual val HTTP_CLIENT_THREAD_COUNT: Int = maxOf(2, (cpuCount * 2 / 3))

actual val HTTP_CLIENT_DEFAULT_DISPATCHER: CoroutineDispatcher by lazy {
IOCoroutineDispatcher(HTTP_CLIENT_THREAD_COUNT)
}
@Deprecated(
"HTTP_CLIENT_DEFAULT_DISPATCHER is deprecated. Use HttpClient.coroutineContext instead.",
level = DeprecationLevel.ERROR
)
actual val HTTP_CLIENT_DEFAULT_DISPATCHER: CoroutineDispatcher get() = Dispatchers.IO

/**
* Singleton pool of [ByteBuffer] objects used for [HttpClient].
*/

val HttpClientDefaultPool = ByteBufferPool()

@InternalAPI
class ByteBufferPool : DefaultPool<ByteBuffer>(DEFAULT_HTTP_POOL_SIZE) {
override fun produceInstance(): ByteBuffer = ByteBuffer.allocate(DEFAULT_HTTP_BUFFER_SIZE)!!

Expand Down
Expand Up @@ -4,6 +4,7 @@ import io.ktor.client.*
import io.ktor.client.features.*
import io.ktor.client.request.*
import io.ktor.client.response.*
import io.ktor.util.*
import kotlinx.atomicfu.*
import kotlinx.coroutines.*
import kotlinx.io.core.*
Expand Down Expand Up @@ -97,13 +98,14 @@ suspend inline fun <reified T> HttpResponse.receive(): T = call.receive(typeInfo
* Exception representing that the response payload has already been received.
*/
class DoubleReceiveException(call: HttpClientCall) : IllegalStateException() {
override val message: String = "Request already received: $call"
override val message: String = "Response already received: $call"
}

/**
* Exception representing fail of the response pipeline
* [cause] contains origin pipeline exception
*/
@KtorExperimentalAPI
class ReceivePipelineFail(
val request: HttpClientCall,
val info: TypeInfo,
Expand Down
Expand Up @@ -11,4 +11,7 @@ expect interface Type
*/
data class TypeInfo(val type: KClass<*>, val reifiedType: Type)

/**
* Returns [TypeInfo] for the specified type [T]
*/
expect inline fun <reified T> typeInfo(): TypeInfo
@@ -1,6 +1,7 @@
package io.ktor.client.engine

import io.ktor.client.response.*
import io.ktor.util.*
import kotlinx.coroutines.*

/**
Expand All @@ -19,6 +20,7 @@ open class HttpClientEngineConfig {
/**
* Network threads count
*/
@KtorExperimentalAPI
var threadsCount: Int = 4

/**
Expand Down
Expand Up @@ -3,10 +3,12 @@ package io.ktor.client.engine
import io.ktor.client.utils.*
import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.util.*

/**
* Merge headers from [content] and [requestHeaders] according to [OutgoingContent] properties
*/
@InternalAPI
fun mergeHeaders(
requestHeaders: Headers,
content: OutgoingContent,
Expand Down
Expand Up @@ -5,9 +5,15 @@ import io.ktor.client.request.*
import io.ktor.client.response.*
import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.util.*
import kotlinx.coroutines.io.*
import kotlinx.io.core.*

/**
* Install default transformers.
* Usually installed by default so there is no need to use it
* unless you have disabled it via [HttpClientConfig.useDefaultTransformers].
*/
fun HttpClient.defaultTransformers() {
requestPipeline.intercept(HttpRequestPipeline.Render) { body ->

Expand Down
Expand Up @@ -26,7 +26,7 @@ class HttpPlainText(var defaultCharset: Charset) {
class Config {
var defaultCharset: Charset = Charsets.UTF_8

fun build(): HttpPlainText = HttpPlainText(defaultCharset)
internal fun build(): HttpPlainText = HttpPlainText(defaultCharset)
}

companion object Feature : HttpClientFeature<Config, HttpPlainText> {
Expand Down
Expand Up @@ -79,6 +79,7 @@ private fun renderClientCookies(cookies: List<Cookie>): String = buildString {
* Gets all the cookies for the specified [url] for this [HttpClient].
*/
suspend fun HttpClient.cookies(url: Url): List<Cookie> = feature(HttpCookies)?.get(url) ?: emptyList()

/**
* Gets all the cookies for the specified [urlString] for this [HttpClient].
*/
Expand Down
Expand Up @@ -94,6 +94,7 @@ class HttpRequestBuilder : HttpMessageBuilder {
/**
* A deferred used to control the execution of this request.
*/
@KtorExperimentalAPI
val executionContext: Job = CompletableDeferred<Unit>()

private var attributesBuilder: Attributes.() -> Unit = {}
Expand Down
Expand Up @@ -38,7 +38,7 @@ fun formData(vararg values: FormPart<*>): List<PartData> {
fun formData(block: FormBuilder.() -> Unit): List<PartData> =
formData(*FormBuilder().apply(block).build().toTypedArray())

class FormBuilder {
class FormBuilder internal constructor() {
private val parts = mutableListOf<FormPart<*>>()

fun <T : Any> append(key: String, value: T, headers: Headers = Headers.Empty) {
Expand Down
@@ -1,8 +1,11 @@
package io.ktor.client.utils

import io.ktor.util.*

/**
* List of [CacheControl] known values.
*/
@KtorExperimentalAPI
object CacheControl {
val MAX_AGE = "max-age"
val MIN_FRESH = "min-fresh"
Expand Down
@@ -1,6 +1,8 @@
package io.ktor.client.utils

import io.ktor.http.*
import io.ktor.util.*

@KtorExperimentalAPI
fun buildHeaders(block: HeadersBuilder.() -> Unit = {}): Headers =
HeadersBuilder().apply(block).build()
Expand Up @@ -25,7 +25,7 @@ class BasicAuth(val username: String, val password: String) {
*/
lateinit var password: String

fun build(): BasicAuth = BasicAuth(username, password)
internal fun build(): BasicAuth = BasicAuth(username, password)
}

companion object Feature : HttpClientFeature<Configuration, BasicAuth> {
Expand Down
Expand Up @@ -26,7 +26,7 @@ class GsonTest : TestWithKtor() {

override val server: ApplicationEngine = embeddedServer(Jetty, serverPort) {
install(ContentNegotiation) {
register(ContentType.Application.Json, GsonConverter())
gson()
}
routing {
post("/") {
Expand Down
Expand Up @@ -15,6 +15,8 @@ import kotlin.reflect.full.*
class WebSockets(
val maxFrameSize: Long = Int.MAX_VALUE.toLong()
) : Closeable {

@KtorExperimentalAPI
val context = CompletableDeferred<Unit>()

override fun close() {
Expand Down
@@ -1,18 +1,22 @@
package io.ktor.client.engine.ios

import io.ktor.util.KtorExperimentalAPI
import kotlinx.cinterop.*
import platform.Foundation.*

@KtorExperimentalAPI
fun ByteArray.toNSData(): NSData = NSMutableData().apply {
if (isEmpty()) return@apply
this@toNSData.usePinned {
appendBytes(it.addressOf(0), size.toULong())
}
}

@KtorExperimentalAPI
fun NSData.toByteArray(): ByteArray {
val data: CPointer<ByteVar> = bytes!!.reinterpret()
return ByteArray(length.toInt()) { index -> data[index] }
}

@KtorExperimentalAPI
class IosHttpRequestException(val origin: NSError? = null) : Throwable("Exception in http request: $origin")
Expand Up @@ -19,13 +19,3 @@ internal class PromiseContinuation<R>(private val continuation: Continuation<R>)
continuation.resume(result)
}
}

internal class CallbackContinuation(val continuation: Continuation<Unit>) : Callback {
override fun succeeded() {
continuation.resume(Unit)
}

override fun failed(x: Throwable) {
continuation.resumeWithException(x)
}
}
Expand Up @@ -12,6 +12,7 @@ import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.jetty.*
import kotlinx.coroutines.*
import java.util.concurrent.*
import java.util.concurrent.atomic.*
import kotlin.test.*

Expand Down Expand Up @@ -78,7 +79,7 @@ abstract class CacheTest(private val factory: HttpClientEngineFactory<*>) : Test
results += client.get<String>(request)
results += client.get<String>(request)

Thread.sleep(7 * 1000)
Thread.sleep(TimeUnit.SECONDS.toMillis(7))

results += client.get<String>(request)
results += client.get<String>(request)
Expand All @@ -90,4 +91,4 @@ abstract class CacheTest(private val factory: HttpClientEngineFactory<*>) : Test
client.close()
}

}
}
32 changes: 28 additions & 4 deletions ktor-features/ktor-auth-jwt/src/io/ktor/auth/jwt/JWTAuth.kt
Expand Up @@ -15,16 +15,34 @@ import java.util.*

private val JWTAuthKey: Any = "JWTAuth"

/**
* Represents a JWT credential consist of the specified [payload]
* @param payload JWT
* @see Payload
*/
class JWTCredential(val payload: Payload) : Credential

/**
* Represents a JWT principal consist of the specified [payload]
* @param payload JWT
* @see Payload
*/
class JWTPrincipal(val payload: Payload) : Principal

/**
* JWT authentication provider that will be registered with the specified [name]
*/
class JWTAuthenticationProvider(name: String?) : AuthenticationProvider(name) {
internal var authenticationFunction: suspend ApplicationCall.(JWTCredential) -> Principal? = { null }

internal var schemes = JWTAuthSchemes("Bearer")
var realm: String = "Ktor Server"
internal var verifier: ((HttpAuthHeader?) -> JWTVerifier?) = { null }

/**
* JWT realm name that will be used during auth challenge
*/
var realm: String = "Ktor Server"

/**
* @param [defaultScheme] default scheme that will be used to challenge the client when no valid auth is provided
* @param [additionalSchemes] additional schemes that will be accepted when validating the authentication
Expand Down Expand Up @@ -62,12 +80,16 @@ class JWTAuthenticationProvider(name: String?) : AuthenticationProvider(name) {
this.verifier = { token -> getVerifier(jwkProvider, token, schemes) }
}

fun validate(body: suspend ApplicationCall.(JWTCredential) -> Principal?) {
authenticationFunction = body
/**
* Apply [validate] function to every call with [JWTCredential]
* @return a principal (usually an instance of [JWTPrincipal]) or `null`
*/
fun validate(validate: suspend ApplicationCall.(JWTCredential) -> Principal?) {
authenticationFunction = validate
}
}

internal class JWTAuthSchemes(val defaultScheme: String, vararg val additionalSchemes: String) {
internal class JWTAuthSchemes(val defaultScheme: String, vararg additionalSchemes: String) {
val schemes = (arrayOf(defaultScheme) + additionalSchemes).toSet()
val schemesLowerCase = schemes.map { it.toLowerCase() }.toSet()

Expand Down Expand Up @@ -180,6 +202,7 @@ private fun DecodedJWT.parsePayload(): Payload {
return JWTParser().parsePayload(payloadString)
}

@Suppress("KDocMissingDocumentation")
@Deprecated("Use DSL builder form", replaceWith = ReplaceWith("jwt {\n" +
" this.realm = realm\n" +
" this.verifier(jwtVerifier)\n" +
Expand All @@ -193,6 +216,7 @@ fun Authentication.Configuration.jwtAuthentication(jwtVerifier: JWTVerifier, rea
}
}

@Suppress("KDocMissingDocumentation")
@Deprecated("Use DSL builder form", replaceWith = ReplaceWith("jwt {\n" +
" this.realm = realm\n" +
" this.verifier(jwkProvider, issuer)\n" +
Expand Down

0 comments on commit 42ae9e7

Please sign in to comment.