mirror of
https://github.com/jlengrand/ktor.git
synced 2026-03-10 08:31:20 +00:00
Mark exceptions with CopyableThrowable to help stacktrace recovery
This commit is contained in:
committed by
Leonid Stashevsky
parent
8bc22be550
commit
a29cb179b3
@@ -61,7 +61,7 @@ class AndroidClientEngine(override val config: AndroidEngineConfig) : HttpClient
|
||||
config.requestConfig(this)
|
||||
|
||||
if (outgoingContent !is OutgoingContent.NoContent) {
|
||||
if (data.method in listOf(HttpMethod.Get, HttpMethod.Head)) throw RequestInvalidException(
|
||||
if (data.method in listOf(HttpMethod.Get, HttpMethod.Head)) error(
|
||||
"Request of type ${data.method} couldn't send a body with the [Android] engine."
|
||||
)
|
||||
|
||||
@@ -123,6 +123,3 @@ internal fun HttpURLConnection.content(callScope: CoroutineContext): ByteReadCha
|
||||
} catch (_: IOException) {
|
||||
errorStream?.buffered()
|
||||
}?.toByteReadChannel(context = callScope, pool = KtorDefaultPool) ?: ByteReadChannel.Empty
|
||||
|
||||
@Suppress("KDocMissingDocumentation")
|
||||
internal class RequestInvalidException(override val message: String) : IllegalStateException()
|
||||
|
||||
@@ -92,7 +92,7 @@ internal class CIOEngine(override val config: CIOEngineConfig) : HttpClientEngin
|
||||
|
||||
@Suppress("KDocMissingDocumentation")
|
||||
@Deprecated("Use ClientEngineClosedException instead", replaceWith = ReplaceWith("ClientEngineClosedException"))
|
||||
class ClientClosedException(override val cause: Throwable? = null) : IllegalStateException("Client already closed")
|
||||
class ClientClosedException(cause: Throwable? = null) : IllegalStateException("Client already closed", cause)
|
||||
|
||||
private fun <K : Any, V : Closeable> ConcurrentHashMap<K, V>.computeIfAbsentWeak(key: K, block: (K) -> V): V {
|
||||
get(key)?.let { return it }
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
package io.ktor.client.engine.cio
|
||||
|
||||
import io.ktor.util.cio.*
|
||||
import io.ktor.network.selector.*
|
||||
import io.ktor.network.sockets.*
|
||||
import io.ktor.network.sockets.Socket
|
||||
|
||||
@@ -111,4 +111,10 @@ internal class OkHttpWebsocketSession(
|
||||
}
|
||||
|
||||
@Suppress("KDocMissingDocumentation")
|
||||
class UnsupportedFrameTypeException(frame: Frame) : IllegalArgumentException("Unsupported frame type: $frame")
|
||||
class UnsupportedFrameTypeException(
|
||||
private val frame: Frame
|
||||
) : IllegalArgumentException("Unsupported frame type: $frame"), CopyableThrowable<UnsupportedFrameTypeException> {
|
||||
override fun createCopy(): UnsupportedFrameTypeException? = UnsupportedFrameTypeException(frame).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,22 +6,18 @@ package io.ktor.auth
|
||||
|
||||
import io.ktor.application.*
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.response.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.http.content.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.auth.*
|
||||
import io.ktor.util.pipeline.*
|
||||
import io.ktor.http.content.*
|
||||
import io.ktor.response.*
|
||||
import io.ktor.util.*
|
||||
import io.ktor.util.pipeline.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.json.simple.*
|
||||
import org.slf4j.*
|
||||
import java.io.*
|
||||
import java.lang.Exception
|
||||
import java.net.*
|
||||
|
||||
private val Logger: Logger = LoggerFactory.getLogger("io.ktor.auth.oauth")
|
||||
@@ -364,22 +360,33 @@ sealed class OAuth2Exception(message: String, val errorCode: String?) : Exceptio
|
||||
* decoded but the response doesn't contain error code nor access token
|
||||
*/
|
||||
@KtorExperimentalAPI
|
||||
class MissingAccessToken :
|
||||
OAuth2Exception("OAuth2 server response is OK neither error nor access token provided", null)
|
||||
class MissingAccessToken : OAuth2Exception(
|
||||
"OAuth2 server response is OK neither error nor access token provided", null
|
||||
)
|
||||
|
||||
/**
|
||||
* Throw when an OAuth2 server replied with error "unsupported_grant_type"
|
||||
* @param grantType that was passed to the server
|
||||
*/
|
||||
@KtorExperimentalAPI
|
||||
class UnsupportedGrantType(val grantType: String) :
|
||||
OAuth2Exception("OAuth2 server doesn't support grant type $grantType", "unsupported_grant_type")
|
||||
class UnsupportedGrantType(val grantType: String) : OAuth2Exception(
|
||||
"OAuth2 server doesn't support grant type $grantType", "unsupported_grant_type"
|
||||
), CopyableThrowable<UnsupportedGrantType> {
|
||||
override fun createCopy(): UnsupportedGrantType = UnsupportedGrantType(grantType).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* OAuth2 server responded with an error code [errorCode]
|
||||
* @param errorCode the OAuth2 server replied with
|
||||
*/
|
||||
@KtorExperimentalAPI
|
||||
class UnknownException(message: String, errorCode: String) :
|
||||
OAuth2Exception("$message (error code = $errorCode)", errorCode)
|
||||
class UnknownException(
|
||||
private val details: String, errorCode: String
|
||||
) : OAuth2Exception("$details (error code = $errorCode)", errorCode), CopyableThrowable<UnknownException> {
|
||||
override fun createCopy(): UnknownException = UnknownException(details, errorCode!!).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,11 @@ import io.ktor.features.*
|
||||
import io.ktor.features.ContentTransformationException
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.*
|
||||
import io.ktor.util.pipeline.*
|
||||
import io.ktor.request.*
|
||||
import io.ktor.util.pipeline.*
|
||||
import io.ktor.utils.io.*
|
||||
import io.ktor.utils.io.jvm.javaio.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.*
|
||||
|
||||
@@ -56,8 +57,15 @@ fun ContentNegotiation.Configuration.gson(
|
||||
register(contentType, converter)
|
||||
}
|
||||
|
||||
internal class ExcludedTypeGsonException(val type: KClass<*>) :
|
||||
Exception("Type ${type.jvmName} is excluded so couldn't be used in receive")
|
||||
internal class ExcludedTypeGsonException(
|
||||
val type: KClass<*>
|
||||
) : Exception("Type ${type.jvmName} is excluded so couldn't be used in receive"),
|
||||
CopyableThrowable<ExcludedTypeGsonException> {
|
||||
|
||||
override fun createCopy(): ExcludedTypeGsonException? = ExcludedTypeGsonException(type).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal class UnsupportedNullValuesException :
|
||||
ContentTransformationException("Receiving null values is not supported")
|
||||
|
||||
@@ -111,9 +111,14 @@ class WebSocketReader(
|
||||
* Raised when the frame is bigger than allowed in a current websocket session
|
||||
* @param frameSize size of received or posted frame that is too big
|
||||
*/
|
||||
class FrameTooBigException(val frameSize: Long) : Exception() {
|
||||
class FrameTooBigException(val frameSize: Long) : Exception(), CopyableThrowable<FrameTooBigException> {
|
||||
|
||||
override val message: String
|
||||
get() = "Frame is too big: $frameSize"
|
||||
|
||||
override fun createCopy(): FrameTooBigException = FrameTooBigException(frameSize).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
private enum class State {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
package io.ktor.network.tls
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import java.security.*
|
||||
import java.security.cert.*
|
||||
import javax.net.ssl.*
|
||||
@@ -99,8 +100,14 @@ fun TLSConfigBuilder.addKeyStore(store: KeyStore, password: CharArray) {
|
||||
* Throws if failed to find [PrivateKey] for any alias in [KeyStore].
|
||||
*/
|
||||
class NoPrivateKeyException(
|
||||
alias: String, store: KeyStore
|
||||
) : IllegalStateException("Failed to find private key for alias $alias. Please check your key store: $store")
|
||||
private val alias: String, private val store: KeyStore
|
||||
) : IllegalStateException("Failed to find private key for alias $alias. Please check your key store: $store"),
|
||||
CopyableThrowable<NoPrivateKeyException> {
|
||||
|
||||
override fun createCopy(): NoPrivateKeyException? = NoPrivateKeyException(alias, store).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findTrustManager(): X509TrustManager {
|
||||
val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())!!
|
||||
|
||||
@@ -6,6 +6,7 @@ package io.ktor.application
|
||||
|
||||
import io.ktor.util.pipeline.*
|
||||
import io.ktor.util.*
|
||||
import kotlinx.coroutines.*
|
||||
import io.ktor.utils.io.core.*
|
||||
|
||||
/**
|
||||
@@ -116,6 +117,12 @@ class DuplicateApplicationFeatureException(message: String) : Exception(message)
|
||||
* Thrown when Application Feature has been attempted to be accessed but has not been installed before
|
||||
* @param key application feature's attribute key
|
||||
*/
|
||||
class MissingApplicationFeatureException(val key: AttributeKey<*>) : IllegalStateException() {
|
||||
class MissingApplicationFeatureException(
|
||||
val key: AttributeKey<*>
|
||||
) : IllegalStateException(), CopyableThrowable<MissingApplicationFeatureException> {
|
||||
override val message: String get() = "Application feature ${key.name} is not installed"
|
||||
|
||||
override fun createCopy(): MissingApplicationFeatureException? = MissingApplicationFeatureException(key).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import io.ktor.http.*
|
||||
import io.ktor.response.*
|
||||
import io.ktor.util.*
|
||||
import io.ktor.util.pipeline.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.slf4j.*
|
||||
import kotlin.random.*
|
||||
import kotlin.reflect.jvm.*
|
||||
@@ -29,7 +30,13 @@ typealias CallIdVerifier = (String) -> Boolean
|
||||
* An exception that could be thrown to reject a call due to illegal call id
|
||||
* @param illegalCallId that caused rejection
|
||||
*/
|
||||
class RejectedCallIdException(val illegalCallId: String) : IllegalArgumentException()
|
||||
class RejectedCallIdException(
|
||||
val illegalCallId: String
|
||||
) : IllegalArgumentException(), CopyableThrowable<RejectedCallIdException> {
|
||||
override fun createCopy(): RejectedCallIdException? = RejectedCallIdException(illegalCallId).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call id that is retrieved or generated by [CallId] feature or `null` (this is possible if there is no
|
||||
@@ -64,9 +71,9 @@ val ApplicationCall.callId: String? get() = attributes.getOrNull(CallId.callIdKe
|
||||
* [CallId] feature will be installed to [CallId.phase] into [ApplicationCallPipeline].
|
||||
*/
|
||||
class CallId private constructor(
|
||||
private val providers: Array<CallIdProvider>,
|
||||
private val repliers: Array<(call: ApplicationCall, callId: String) -> Unit>,
|
||||
private val verifier: CallIdVerifier
|
||||
private val providers: Array<CallIdProvider>,
|
||||
private val repliers: Array<(call: ApplicationCall, callId: String) -> Unit>,
|
||||
private val verifier: CallIdVerifier
|
||||
) {
|
||||
/**
|
||||
* [CallId] feature's configuration
|
||||
@@ -186,9 +193,9 @@ class CallId private constructor(
|
||||
val configuration = Configuration().apply(configure)
|
||||
|
||||
val instance = CallId(
|
||||
providers = (configuration.retrievers + configuration.generators).toTypedArray(),
|
||||
repliers = configuration.responseInterceptors.toTypedArray(),
|
||||
verifier = configuration.verifier
|
||||
providers = (configuration.retrievers + configuration.generators).toTypedArray(),
|
||||
repliers = configuration.responseInterceptors.toTypedArray(),
|
||||
verifier = configuration.verifier
|
||||
)
|
||||
|
||||
pipeline.insertPhaseBefore(ApplicationCallPipeline.Setup, phase)
|
||||
@@ -216,7 +223,8 @@ class CallId private constructor(
|
||||
break
|
||||
}
|
||||
} catch (rejection: RejectedCallIdException) {
|
||||
logger.warn("Illegal call id retrieved or generated that is rejected by call id verifier:" +
|
||||
logger.warn(
|
||||
"Illegal call id retrieved or generated that is rejected by call id verifier:" +
|
||||
" (url-encoded) " +
|
||||
rejection.illegalCallId.encodeURLParameter()
|
||||
)
|
||||
|
||||
@@ -132,8 +132,9 @@ sealed class CachedTransformationResult<T : Any>(val type: KType) {
|
||||
* receive attempt is simply replaying the previous exception cause.
|
||||
*/
|
||||
@KtorExperimentalAPI
|
||||
class RequestReceiveAlreadyFailedException internal constructor(cause: Throwable) :
|
||||
Exception("Request body consumption was failed", cause, false, true)
|
||||
class RequestReceiveAlreadyFailedException internal constructor(
|
||||
cause: Throwable
|
||||
) : Exception("Request body consumption was failed", cause, false, true)
|
||||
|
||||
private val LastReceiveCachedResult = AttributeKey<CachedTransformationResult<*>>("LastReceiveRequest")
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ package io.ktor.features
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.util.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.full.*
|
||||
|
||||
@@ -31,8 +32,15 @@ class NotFoundException(message: String? = "Resource not found") : Exception(mes
|
||||
* @property parameterName of missing request parameter
|
||||
*/
|
||||
@KtorExperimentalAPI
|
||||
class MissingRequestParameterException(val parameterName: String) :
|
||||
BadRequestException("Request parameter $parameterName is missing")
|
||||
class MissingRequestParameterException(
|
||||
val parameterName: String
|
||||
) : BadRequestException("Request parameter $parameterName is missing"),
|
||||
CopyableThrowable<MissingRequestParameterException> {
|
||||
|
||||
override fun createCopy(): MissingRequestParameterException = MissingRequestParameterException(parameterName).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This exception is thrown when a required parameter with name [parameterName] couldn't be converted to the [type]
|
||||
@@ -41,7 +49,14 @@ class MissingRequestParameterException(val parameterName: String) :
|
||||
*/
|
||||
@KtorExperimentalAPI
|
||||
class ParameterConversionException(val parameterName: String, val type: String, cause: Throwable? = null) :
|
||||
BadRequestException("Request parameter $parameterName couldn't be parsed/converted to $type", cause)
|
||||
BadRequestException("Request parameter $parameterName couldn't be parsed/converted to $type", cause),
|
||||
CopyableThrowable<ParameterConversionException> {
|
||||
|
||||
override fun createCopy(): ParameterConversionException =
|
||||
ParameterConversionException(parameterName, type, this).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when content cannot be transformed to the desired type.
|
||||
@@ -51,16 +66,30 @@ class ParameterConversionException(val parameterName: String, val type: String,
|
||||
@KtorExperimentalAPI
|
||||
abstract class ContentTransformationException(message: String) : Exception(message)
|
||||
|
||||
internal class CannotTransformContentToTypeException(type: KType) :
|
||||
ContentTransformationException("Cannot transform this request's content to $type") {
|
||||
internal class CannotTransformContentToTypeException(
|
||||
private val type: KType
|
||||
) : ContentTransformationException("Cannot transform this request's content to $type"),
|
||||
CopyableThrowable<CannotTransformContentToTypeException> {
|
||||
@Suppress("unused")
|
||||
@Deprecated("Use KType instead", level = DeprecationLevel.HIDDEN)
|
||||
constructor(type: KClass<*>) : this(type.starProjectedType)
|
||||
|
||||
override fun createCopy(): CannotTransformContentToTypeException? =
|
||||
CannotTransformContentToTypeException(type).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when there is no conversion for a content type configured.
|
||||
* HTTP status 415 Unsupported Media Type will be replied when this exception is thrown and not caught.
|
||||
*/
|
||||
class UnsupportedMediaTypeException(contentType: ContentType) :
|
||||
ContentTransformationException("Content type $contentType is not supported")
|
||||
class UnsupportedMediaTypeException(
|
||||
private val contentType: ContentType
|
||||
) : ContentTransformationException("Content type $contentType is not supported"),
|
||||
CopyableThrowable<UnsupportedMediaTypeException> {
|
||||
|
||||
override fun createCopy(): UnsupportedMediaTypeException? = UnsupportedMediaTypeException(contentType).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
package io.ktor.server.engine
|
||||
|
||||
import io.ktor.application.*
|
||||
import io.ktor.util.cio.*
|
||||
import io.ktor.http.content.*
|
||||
import io.ktor.features.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.*
|
||||
import io.ktor.response.*
|
||||
import io.ktor.util.*
|
||||
import kotlinx.coroutines.*
|
||||
import io.ktor.util.cio.*
|
||||
import io.ktor.utils.io.*
|
||||
import io.ktor.utils.io.pool.*
|
||||
import kotlinx.coroutines.*
|
||||
import java.nio.*
|
||||
|
||||
/**
|
||||
@@ -70,7 +70,8 @@ abstract class BaseApplicationResponse(override val call: ApplicationCall) : App
|
||||
}
|
||||
!transferEncodingSet -> {
|
||||
when (content) {
|
||||
is OutgoingContent.ProtocolUpgrade -> { }
|
||||
is OutgoingContent.ProtocolUpgrade -> {
|
||||
}
|
||||
is OutgoingContent.NoContent -> headers.append(HttpHeaders.ContentLength, "0", safeOnly = false)
|
||||
else -> headers.append(HttpHeaders.TransferEncoding, "chunked", safeOnly = false)
|
||||
}
|
||||
@@ -100,7 +101,7 @@ abstract class BaseApplicationResponse(override val call: ApplicationCall) : App
|
||||
return respondUpgrade(content)
|
||||
}
|
||||
|
||||
// ByteArrayContent is most efficient
|
||||
// ByteArrayContent is most efficient
|
||||
is OutgoingContent.ByteArrayContent -> {
|
||||
// First call user code to acquire bytes, because it could fail
|
||||
val bytes = content.bytes()
|
||||
@@ -109,7 +110,7 @@ abstract class BaseApplicationResponse(override val call: ApplicationCall) : App
|
||||
return respondFromBytes(bytes)
|
||||
}
|
||||
|
||||
// WriteChannelContent is more efficient than ReadChannelContent
|
||||
// WriteChannelContent is more efficient than ReadChannelContent
|
||||
is OutgoingContent.WriteChannelContent -> {
|
||||
// First set headers
|
||||
commitHeaders(content)
|
||||
@@ -117,7 +118,7 @@ abstract class BaseApplicationResponse(override val call: ApplicationCall) : App
|
||||
return respondWriteChannelContent(content)
|
||||
}
|
||||
|
||||
// Pipe is least efficient
|
||||
// Pipe is least efficient
|
||||
is OutgoingContent.ReadChannelContent -> {
|
||||
// First call user code to acquire read channel, because it could fail
|
||||
val readChannel = content.readFrom()
|
||||
@@ -126,7 +127,7 @@ abstract class BaseApplicationResponse(override val call: ApplicationCall) : App
|
||||
return respondFromChannel(readChannel)
|
||||
}
|
||||
|
||||
// Do nothing, but maintain `when` exhaustiveness
|
||||
// Do nothing, but maintain `when` exhaustiveness
|
||||
is OutgoingContent.NoContent -> {
|
||||
commitHeaders(content)
|
||||
return respondNoContent(content)
|
||||
@@ -215,11 +216,13 @@ abstract class BaseApplicationResponse(override val call: ApplicationCall) : App
|
||||
/**
|
||||
* ByteBuffer pool
|
||||
*/
|
||||
@Deprecated("Avoid specifying pools or use KtorDefaultPool instead.",
|
||||
@Deprecated(
|
||||
"Avoid specifying pools or use KtorDefaultPool instead.",
|
||||
ReplaceWith("KtorDefaultPool", "io.ktor.util.cio.KtorDefaultPool"),
|
||||
level = DeprecationLevel.ERROR
|
||||
)
|
||||
protected open val bufferPool: ObjectPool<ByteBuffer> get() = KtorDefaultPool
|
||||
protected open val bufferPool: ObjectPool<ByteBuffer>
|
||||
get() = KtorDefaultPool
|
||||
|
||||
/**
|
||||
* Set underlying engine's response status
|
||||
@@ -239,21 +242,39 @@ abstract class BaseApplicationResponse(override val call: ApplicationCall) : App
|
||||
* [OutgoingContent] is trying to set some header that is not allowed for this content type.
|
||||
* For example, only upgrade content can set `Upgrade` header.
|
||||
*/
|
||||
class InvalidHeaderForContent(name: String, content: String) : IllegalStateException("Header $name is not allowed for $content")
|
||||
class InvalidHeaderForContent(
|
||||
private val name: String, private val content: String
|
||||
) : IllegalStateException("Header $name is not allowed for $content"),
|
||||
CopyableThrowable<InvalidHeaderForContent> {
|
||||
override fun createCopy(): InvalidHeaderForContent? = InvalidHeaderForContent(name, content).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Content's actual body size doesn't match the provided one in `Content-Length` header
|
||||
*/
|
||||
class BodyLengthIsTooSmall(expected: Long, actual: Long) : IllegalStateException(
|
||||
"Body.size is too small. Body: $actual, Content-Length: $expected"
|
||||
)
|
||||
class BodyLengthIsTooSmall(
|
||||
private val expected: Long, private val actual: Long
|
||||
) : IllegalStateException("Body.size is too small. Body: $actual, Content-Length: $expected"),
|
||||
CopyableThrowable<BodyLengthIsTooSmall> {
|
||||
override fun createCopy(): BodyLengthIsTooSmall? = BodyLengthIsTooSmall(expected, actual).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Content's actual body size doesn't match the provided one in `Content-Length` header
|
||||
*/
|
||||
class BodyLengthIsTooLong(expected: Long) : IllegalStateException(
|
||||
"Body.size is too long. Expected $expected"
|
||||
)
|
||||
class BodyLengthIsTooLong(private val expected: Long) : IllegalStateException(
|
||||
"Body.size is too long. Expected $expected"
|
||||
), CopyableThrowable<BodyLengthIsTooLong> {
|
||||
override fun createCopy(): BodyLengthIsTooLong? = BodyLengthIsTooLong(expected).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
|
||||
@@ -157,9 +157,15 @@ internal class NettyHttp2Handler(
|
||||
return superclass.findIdField()
|
||||
}
|
||||
|
||||
private class Http2ClosedChannelException(val errorCode: Long) : ClosedChannelException() {
|
||||
private class Http2ClosedChannelException(
|
||||
val errorCode: Long
|
||||
) : ClosedChannelException(), CopyableThrowable<Http2ClosedChannelException> {
|
||||
override val message: String
|
||||
get() = "Got close frame with code $errorCode"
|
||||
|
||||
override fun createCopy(): Http2ClosedChannelException? = Http2ClosedChannelException(errorCode).also {
|
||||
it.initCause(this)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
Reference in New Issue
Block a user