Открыть боковую панель
Aurora OS
Kotlin Multiplatform
Libraries
ktor
Коммиты
702364f9
Коммит
702364f9
создал
Дек 14, 2022
по автору
Rustam
Зафиксировано автором
Aleksei Tirman
Мар 03, 2023
Просмотр файлов
KTOR-4547 Add Apache 5 client engine (#3313)
владелец
ff69ac13
Изменения
20
Скрыть пробелы
Построчно
Рядом
gradle/libs.versions.toml
Просмотр файла @
702364f9
...
...
@@ -17,6 +17,7 @@ jetty-alpn-boot-version = "8.1.13.v20181017"
tomcat-version
=
"9.0.70"
apache-version
=
"4.1.5"
apache5-version
=
"5.2"
apacheds-version
=
"2.0.0-M24"
okhttp-version
=
"4.10.0"
...
...
@@ -123,6 +124,7 @@ logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "lo
junit
=
{
module
=
"junit:junit"
,
version.ref
=
"junit-version"
}
apache-httpasyncclient
=
{
module
=
"org.apache.httpcomponents:httpasyncclient"
,
version.ref
=
"apache-version"
}
apache-client5
=
{
module
=
"org.apache.httpcomponents.client5:httpclient5"
,
version.ref
=
"apache5-version"
}
apacheds-server
=
{
module
=
"org.apache.directory.server:apacheds-server-integ"
,
version.ref
=
"apacheds-version"
}
apacheds-core
=
{
module
=
"org.apache.directory.server:apacheds-core-integ"
,
version.ref
=
"apacheds-version"
}
...
...
ktor-client/ktor-client-apache5/api/ktor-client-apache5.api
0 → 100644
Просмотр файла @
702364f9
public final class io/ktor/client/engine/apache5/Apache5 : io/ktor/client/engine/HttpClientEngineFactory {
public static final field INSTANCE Lio/ktor/client/engine/apache5/Apache5;
public fun create (Lkotlin/jvm/functions/Function1;)Lio/ktor/client/engine/HttpClientEngine;
}
public final class io/ktor/client/engine/apache5/Apache5EngineConfig : io/ktor/client/engine/HttpClientEngineConfig {
public fun <init> ()V
public final fun customizeClient (Lkotlin/jvm/functions/Function1;)V
public final fun customizeRequest (Lkotlin/jvm/functions/Function1;)V
public final fun getConnectTimeout ()J
public final fun getConnectionRequestTimeout ()J
public final fun getFollowRedirects ()Z
public final fun getSocketTimeout ()I
public final fun getSslContext ()Ljavax/net/ssl/SSLContext;
public final fun setConnectTimeout (J)V
public final fun setConnectionRequestTimeout (J)V
public final fun setFollowRedirects (Z)V
public final fun setSocketTimeout (I)V
public final fun setSslContext (Ljavax/net/ssl/SSLContext;)V
}
public final class io/ktor/client/engine/apache5/Apache5EngineContainer : io/ktor/client/HttpClientEngineContainer {
public fun <init> ()V
public fun getFactory ()Lio/ktor/client/engine/HttpClientEngineFactory;
public fun toString ()Ljava/lang/String;
}
ktor-client/ktor-client-apache5/build.gradle.kts
0 → 100644
Просмотр файла @
702364f9
description
=
"Apache backend for ktor http client"
apply
<
test
.
server
.
TestServerPlugin
>()
kotlin
.
sourceSets
{
jvmMain
{
dependencies
{
api
(
project
(
":ktor-client:ktor-client-core"
))
api
(
libs
.
apache
.
client5
)
}
}
jvmTest
{
dependencies
{
api
(
project
(
":ktor-client:ktor-client-tests"
))
}
}
}
ktor-client/ktor-client-apache5/jvm/resources/META-INF/services/io.ktor.client.HttpClientEngineContainer
0 → 100644
Просмотр файла @
702364f9
io.ktor.client.engine.apache5.Apache5EngineContainer
ktor-client/ktor-client-apache5/jvm/src/io/ktor/client/engine/apache5/Apache5.kt
0 → 100644
Просмотр файла @
702364f9
/*
* Copyright 2014-2022 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
package
io.ktor.client.engine.apache5
import
io.ktor.client.*
import
io.ktor.client.engine.*
/**
* A JVM client engine that uses the Apache HTTP client.
*
* To create the client with this engine, pass it to the `HttpClient` constructor:
* ```kotlin
* val client = HttpClient(Apache)
* ```
* To configure the engine, pass settings exposed by [ApacheEngineConfig] to the `engine` method:
* ```kotlin
* val client = HttpClient(Apache) {
* engine {
* // this: ApacheEngineConfig
* }
* }
* ```
*
* You can learn more about client engines from [Engines](https://ktor.io/docs/http-client-engines.html).
*/
public
object
Apache5
:
HttpClientEngineFactory
<
Apache5EngineConfig
>
{
override
fun
create
(
block
:
Apache5EngineConfig
.()
->
Unit
):
HttpClientEngine
{
val
config
=
Apache5EngineConfig
().
apply
(
block
)
return
Apache5Engine
(
config
)
}
}
@Suppress
(
"KDocMissingDocumentation"
)
public
class
Apache5EngineContainer
:
HttpClientEngineContainer
{
override
val
factory
:
HttpClientEngineFactory
<
*
>
=
Apache5
override
fun
toString
():
String
=
"Apache5"
}
ktor-client/ktor-client-apache5/jvm/src/io/ktor/client/engine/apache5/Apache5Engine.kt
0 → 100644
Просмотр файла @
702364f9
/*
* Copyright 2014-2022 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
package
io.ktor.client.engine.apache5
import
io.ktor.client.engine.*
import
io.ktor.client.plugins.*
import
io.ktor.client.request.*
import
io.ktor.client.utils.*
import
io.ktor.util.*
import
kotlinx.coroutines.*
import
org.apache.hc.client5.http.config.*
import
org.apache.hc.client5.http.impl.async.*
import
org.apache.hc.client5.http.impl.nio.*
import
org.apache.hc.client5.http.ssl.*
import
org.apache.hc.core5.http.*
import
org.apache.hc.core5.http.ssl.*
import
org.apache.hc.core5.reactor.*
import
org.apache.hc.core5.ssl.*
import
java.net.*
import
java.util.concurrent.*
private
const
val
MAX_CONNECTIONS_COUNT
=
1000
private
const
val
IO_THREAD_COUNT_DEFAULT
=
4
@OptIn
(
InternalAPI
::
class
)
internal
class
Apache5Engine
(
override
val
config
:
Apache5EngineConfig
)
:
HttpClientEngineBase
(
"ktor-apache"
)
{
override
val
dispatcher
by
lazy
{
Dispatchers
.
clientDispatcher
(
config
.
threadsCount
,
"ktor-apache-dispatcher"
)
}
override
val
supportedCapabilities
=
setOf
(
HttpTimeout
)
@Volatile
private
var
engine
:
CloseableHttpAsyncClient
?
=
null
override
suspend
fun
execute
(
data
:
HttpRequestData
):
HttpResponseData
{
val
callContext
=
callContext
()
val
engine
=
engine
(
data
)
val
apacheRequest
=
ApacheRequestProducer
(
data
,
config
,
callContext
)
return
engine
.
sendRequest
(
apacheRequest
,
callContext
,
data
)
}
override
fun
close
()
{
super
.
close
()
coroutineContext
[
Job
]
!!
.
invokeOnCompletion
{
engine
?.
close
()
}
}
private
fun
engine
(
data
:
HttpRequestData
):
CloseableHttpAsyncClient
{
return
engine
?:
synchronized
(
this
)
{
engine
?:
HttpAsyncClients
.
custom
().
apply
{
val
timeout
=
data
.
getCapabilityOrNull
(
HttpTimeout
)
setThreadFactory
{
Thread
(
it
,
"Ktor-client-apache"
).
apply
{
isDaemon
=
true
setUncaughtExceptionHandler
{
_
,
_
->
}
}
}
disableAuthCaching
()
disableConnectionState
()
disableCookieManagement
()
setConnectionManager
(
PoolingAsyncClientConnectionManagerBuilder
.
create
()
.
setMaxConnTotal
(
MAX_CONNECTIONS_COUNT
)
.
setMaxConnTotal
(
MAX_CONNECTIONS_COUNT
)
.
setTlsStrategy
(
ClientTlsStrategyBuilder
.
create
()
.
setSslContext
(
config
.
sslContext
?:
SSLContexts
.
createSystemDefault
())
.
setTlsVersions
(
TLS
.
V_1_3
,
TLS
.
V_1_2
)
.
build
()
)
.
setDefaultConnectionConfig
(
ConnectionConfig
.
custom
()
.
setConnectTimeout
(
timeout
?.
connectTimeoutMillis
?:
config
.
connectTimeout
,
TimeUnit
.
MILLISECONDS
)
.
setSocketTimeout
(
timeout
?.
socketTimeoutMillis
?.
toInt
()
?:
config
.
socketTimeout
,
TimeUnit
.
MILLISECONDS
)
.
build
()
)
.
build
()
)
setIOReactorConfig
(
IOReactorConfig
.
custom
()
.
setIoThreadCount
(
IO_THREAD_COUNT_DEFAULT
)
.
build
()
)
setupProxy
()
with
(
config
)
{
customClient
()
}
}.
build
().
also
{
engine
=
it
it
.
start
()
}
}
}
private
fun
HttpAsyncClientBuilder
.
setupProxy
()
{
val
proxy
=
config
.
proxy
?:
return
if
(
proxy
.
type
()
==
Proxy
.
Type
.
DIRECT
)
{
return
}
val
address
=
proxy
.
address
()
check
(
proxy
.
type
()
==
Proxy
.
Type
.
HTTP
&&
address
is
InetSocketAddress
)
{
"Only http proxy is supported for Apache engine."
}
setProxy
(
HttpHost
.
create
(
"http://${address.hostName}:${address.port}"
))
}
}
ktor-client/ktor-client-apache5/jvm/src/io/ktor/client/engine/apache5/Apache5EngineConfig.kt
0 → 100644
Просмотр файла @
702364f9
/*
* Copyright 2014-2022 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
package
io.ktor.client.engine.apache5
import
io.ktor.client.engine.*
import
org.apache.hc.client5.http.config.*
import
org.apache.hc.client5.http.impl.async.*
import
javax.net.ssl.*
/**
* A configuration for the [Apache5] client engine.
*/
public
class
Apache5EngineConfig
:
HttpClientEngineConfig
()
{
/**
* Specifies whether to follow redirects automatically.
* Disabled by default.
*
* _Note: By default, the Apache client allows `50` redirects._
*/
public
var
followRedirects
:
Boolean
=
false
/**
* Specifies a maximum time (in milliseconds) of inactivity between two data packets when exchanging data with a server.
*
* Set this value to `0` to use an infinite timeout.
*/
public
var
socketTimeout
:
Int
=
10_000
/**
* Specifies a time period (in milliseconds) in which a client should establish a connection with a server.
*
* A `0` value represents an infinite timeout, while `-1` represents a system's default value.
*/
public
var
connectTimeout
:
Long
=
10_000
/**
* Specifies a time period (in milliseconds) in which a client should start a request.
*
* A `0` value represents an infinite timeout, while `-1` represents a system's default value.
*/
public
var
connectionRequestTimeout
:
Long
=
20_000
/**
* Allows you to configure [SSL](https://ktor.io/docs/client-ssl.html) settings for this engine.
*/
public
var
sslContext
:
SSLContext
?
=
null
internal
var
customRequest
:
(
RequestConfig
.
Builder
.()
->
RequestConfig
.
Builder
)
=
{
this
}
internal
var
customClient
:
(
HttpAsyncClientBuilder
.()
->
HttpAsyncClientBuilder
)
=
{
this
}
/**
* Customizes a [RequestConfig.Builder] in the specified [block].
*/
public
fun
customizeRequest
(
block
:
RequestConfig
.
Builder
.()
->
Unit
)
{
val
current
=
customRequest
customRequest
=
{
current
();
block
();
this
}
}
/**
* Customizes a [HttpAsyncClientBuilder] in the specified [block].
*/
public
fun
customizeClient
(
block
:
HttpAsyncClientBuilder
.()
->
Unit
)
{
val
current
=
customClient
customClient
=
{
current
();
block
();
this
}
}
}
ktor-client/ktor-client-apache5/jvm/src/io/ktor/client/engine/apache5/ApacheHttpRequest.kt
0 → 100644
Просмотр файла @
702364f9
/*
* Copyright 2014-2022 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
package
io.ktor.client.engine.apache5
import
io.ktor.client.plugins.*
import
io.ktor.client.request.*
import
io.ktor.http.*
import
io.ktor.util.date.*
import
kotlinx.coroutines.*
import
org.apache.hc.client5.http.impl.async.*
import
org.apache.hc.core5.concurrent.*
import
org.apache.hc.core5.http.message.*
import
org.apache.hc.core5.http.nio.*
import
java.net.*
import
kotlin.coroutines.*
internal
suspend
fun
CloseableHttpAsyncClient
.
sendRequest
(
request
:
AsyncRequestProducer
,
callContext
:
CoroutineContext
,
requestData
:
HttpRequestData
):
HttpResponseData
{
val
requestTime
=
GMTDate
()
val
bodyConsumer
=
ApacheResponseConsumer
(
callContext
,
requestData
)
val
responseConsumer
=
BasicResponseConsumer
(
bodyConsumer
)
val
callback
=
object
:
FutureCallback
<
Unit
>
{
override
fun
failed
(
exception
:
Exception
)
{}
override
fun
completed
(
result
:
Unit
)
{}
override
fun
cancelled
()
{}
}
val
future
=
execute
(
request
,
responseConsumer
,
callback
)
!!
try
{
val
rawResponse
=
responseConsumer
.
responseDeferred
.
await
()
val
statusLine
=
StatusLine
(
rawResponse
)
val
status
=
HttpStatusCode
(
statusLine
.
statusCode
,
statusLine
.
reasonPhrase
?:
""
)
val
version
=
with
(
statusLine
.
protocolVersion
)
{
HttpProtocolVersion
.
fromValue
(
protocol
,
major
,
minor
)
}
val
rawHeaders
=
rawResponse
.
headers
.
filter
{
it
.
name
!=
null
||
it
.
name
.
isNotBlank
()
}.
groupBy
(
{
it
.
name
},
{
it
.
value
?:
""
}
)
val
headers
=
HeadersImpl
(
rawHeaders
)
return
HttpResponseData
(
status
,
requestTime
,
headers
,
version
,
bodyConsumer
.
responseChannel
,
callContext
)
}
catch
(
cause
:
Exception
)
{
future
.
cancel
(
true
)
val
mappedCause
=
mapCause
(
cause
,
requestData
)
callContext
.
cancel
(
CancellationException
(
"Failed to execute request."
,
mappedCause
))
throw
mappedCause
}
}
internal
fun
mapCause
(
exception
:
Exception
,
requestData
:
HttpRequestData
):
Exception
=
when
{
exception
is
ConnectException
&&
exception
.
isTimeoutException
()
->
ConnectTimeoutException
(
requestData
,
exception
)
exception
is
SocketTimeoutException
->
SocketTimeoutException
(
requestData
,
exception
)
else
->
exception
}
ktor-client/ktor-client-apache5/jvm/src/io/ktor/client/engine/apache5/ApacheRequestProducer.kt
0 → 100644
Просмотр файла @
702364f9
/*
* Copyright 2014-2022 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
package
io.ktor.client.engine.apache5
import
io.ktor.client.call.*
import
io.ktor.client.engine.*
import
io.ktor.client.plugins.*
import
io.ktor.client.request.*
import
io.ktor.http.*
import
io.ktor.http.HttpHeaders
import
io.ktor.http.content.*
import
io.ktor.util.*
import
io.ktor.utils.io.*
import
kotlinx.atomicfu.*
import
kotlinx.coroutines.*
import
org.apache.hc.client5.http.async.methods.*
import
org.apache.hc.client5.http.classic.methods.*
import
org.apache.hc.client5.http.config.*
import
org.apache.hc.client5.http.utils.*
import
org.apache.hc.core5.http.*
import
org.apache.hc.core5.http.HttpRequest
import
org.apache.hc.core5.http.io.entity.*
import
org.apache.hc.core5.http.message.*
import
org.apache.hc.core5.http.nio.*
import
org.apache.hc.core5.http.nio.entity.*
import
org.apache.hc.core5.http.nio.support.*
import
org.apache.hc.core5.http.protocol.*
import
java.nio.*
import
java.util.concurrent.*
import
kotlin.coroutines.*
@OptIn
(
InternalAPI
::
class
)
internal
fun
ApacheRequestProducer
(
requestData
:
HttpRequestData
,
config
:
Apache5EngineConfig
,
callContext
:
CoroutineContext
):
AsyncRequestProducer
{
val
content
=
requestData
.
body
var
length
:
String
?
=
null
var
type
:
String
?
=
null
mergeHeaders
(
requestData
.
headers
,
content
)
{
key
,
value
->
when
(
key
)
{
HttpHeaders
.
ContentLength
->
length
=
value
HttpHeaders
.
ContentType
->
type
=
value
}
}
val
isGetOrHead
=
requestData
.
method
==
HttpMethod
.
Get
||
requestData
.
method
==
HttpMethod
.
Head
val
hasContent
=
requestData
.
body
!
is
OutgoingContent
.
NoContent
val
contentLength
=
length
?.
toLong
()
?:
-
1
val
isChunked
=
contentLength
==
-
1L
&&
!
isGetOrHead
&&
hasContent
return
BasicRequestProducer
(
setupRequest
(
requestData
,
config
),
if
(!
hasContent
&&
isGetOrHead
)
null
else
ApacheRequestEntityProducer
(
requestData
,
callContext
,
contentLength
,
type
,
isChunked
)
)
}
@OptIn
(
InternalAPI
::
class
)
private
fun
setupRequest
(
requestData
:
HttpRequestData
,
config
:
Apache5EngineConfig
):
HttpRequest
=
with
(
requestData
)
{
val
request
=
ConfigurableHttpRequest
(
method
.
value
,
url
.
toURI
())
mergeHeaders
(
headers
,
body
)
{
key
,
value
->
when
(
key
)
{
HttpHeaders
.
ContentLength
->
{}
HttpHeaders
.
ContentType
->
{}
else
->
request
.
addHeader
(
key
,
value
)
}
}
with
(
config
)
{
request
.
config
=
RequestConfig
.
custom
()
.
setRedirectsEnabled
(
followRedirects
)
.
setConnectionRequestTimeout
(
connectionRequestTimeout
,
TimeUnit
.
MILLISECONDS
)
.
customRequest
()
.
build
()
}
return
request
}
internal
class
ApacheRequestEntityProducer
(
private
val
requestData
:
HttpRequestData
,
callContext
:
CoroutineContext
,
private
val
contentLength
:
Long
,
private
val
contentType
:
String
?,
private
val
isChunked
:
Boolean
)
:
AsyncEntityProducer
,
CoroutineScope
{
private
val
waitingForContent
=
atomic
(
false
)
private
val
producerJob
=
Job
()
override
val
coroutineContext
:
CoroutineContext
=
callContext
+
producerJob
@OptIn
(
DelicateCoroutinesApi
::
class
)
private
val
channel
:
ByteReadChannel
=
when
(
val
body
=
requestData
.
body
)
{
is
OutgoingContent
.
ByteArrayContent
->
ByteReadChannel
(
body
.
bytes
())
is
OutgoingContent
.
ProtocolUpgrade
->
throw
UnsupportedContentTypeException
(
body
)
is
OutgoingContent
.
NoContent
->
ByteReadChannel
.
Empty
is
OutgoingContent
.
ReadChannelContent
->
body
.
readFrom
()
is
OutgoingContent
.
WriteChannelContent
->
GlobalScope
.
writer
(
callContext
,
autoFlush
=
true
)
{
body
.
writeTo
(
channel
)
}.
channel
}
init
{
producerJob
.
invokeOnCompletion
{
cause
->
channel
.
cancel
(
cause
)
}
}
override
fun
releaseResources
()
{
channel
.
cancel
()
producerJob
.
complete
()
}
override
fun
available
():
Int
=
channel
.
availableForRead
override
fun
produce
(
channel
:
DataStreamChannel
)
{
var
result
:
Int
do
{
result
=
this
.
channel
.
readAvailable
{
buffer
:
ByteBuffer
->
channel
.
write
(
buffer
)
}
}
while
(
result
>
0
)
if
(
this
.
channel
.
isClosedForRead
)
{
channel
.
endStream
()
return
}
if
(
result
==
-
1
&&
!
waitingForContent
.
getAndSet
(
true
))
{
launch
(
Dispatchers
.
Unconfined
)
{
try
{
this
@ApacheRequestEntityProducer
.
channel
.
awaitContent
()
}
finally
{
waitingForContent
.
value
=
false
channel
.
requestOutput
()
}
}
}
}
override
fun
getContentLength
():
Long
=
contentLength
override
fun
getContentType
():
String
?
=
contentType
override
fun
getContentEncoding
():
String
?
=
null
override
fun
isChunked
():
Boolean
=
isChunked
override
fun
getTrailerNames
():
Set
<
String
>
=
emptySet
()
override
fun
isRepeatable
():
Boolean
=
false
override
fun
failed
(
cause
:
Exception
)
{
val
mappedCause
=
mapCause
(
cause
,
requestData
)
channel
.
cancel
(
mappedCause
)
producerJob
.
completeExceptionally
(
mappedCause
)
}
}
ktor-client/ktor-client-apache5/jvm/src/io/ktor/client/engine/apache5/ApacheResponseConsumer.kt
0 → 100644
Просмотр файла @
702364f9
/*
* Copyright 2014-2022 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
package
io.ktor.client.engine.apache5
import
io.ktor.client.request.*
import
io.ktor.client.statement.*
import
io.ktor.util.*
import
io.ktor.utils.io.*
import
io.ktor.utils.io.pool.*
import
kotlinx.atomicfu.*
import
kotlinx.coroutines.*
import
kotlinx.coroutines.channels.*
import
kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
import
org.apache.hc.client5.http.async.methods.*
import
org.apache.hc.core5.concurrent.*
import
org.apache.hc.core5.function.*
import
org.apache.hc.core5.http.*
import
org.apache.hc.core5.http.HttpResponse
import
org.apache.hc.core5.http.nio.*
import
org.apache.hc.core5.http.nio.entity.*
import
org.apache.hc.core5.http.protocol.*
import
org.apache.hc.core5.util.*
import
java.io.*
import
java.nio.*
import
java.util.concurrent.atomic.*
import
kotlin.coroutines.*
private
object
CloseChannel
internal
class
BasicResponseConsumer
(
private
val
dataConsumer
:
ApacheResponseConsumer
)
:
AsyncResponseConsumer
<
Unit
>
{
internal
val
responseDeferred
=
CompletableDeferred
<
HttpResponse
>()
override
fun
consumeResponse
(
response
:
HttpResponse
,
entityDetails
:
EntityDetails
?,
httpContext
:
HttpContext
,
resultCallback
:
FutureCallback
<
Unit
>
)
{
responseDeferred
.
complete
(
response
)
if
(
entityDetails
!=
null
)
{
dataConsumer
.
streamStart
(
entityDetails
,
object
:
CallbackContribution
<
Unit
>(
resultCallback
)
{
override
fun
completed
(
body
:
Unit
)
{
resultCallback
.
completed
(
Unit
)
}
}
)
}
else
{
dataConsumer
.
close
()
resultCallback
.
completed
(
Unit
)
}
}
override
fun
informationResponse
(
response
:
HttpResponse
,
httpContext
:
HttpContext
)
{
}
override
fun
updateCapacity
(
capacityChannel
:
CapacityChannel
)
{
dataConsumer
.
updateCapacity
(
capacityChannel
)
}
override
fun
consume
(
src
:
ByteBuffer
)
{
dataConsumer
.
consume
(
src
)
}
override
fun
streamEnd
(
trailers
:
List
<
Header
>?)
{
dataConsumer
.
streamEnd
(
trailers
)
}
override
fun
failed
(
cause
:
Exception
)
{
responseDeferred
.
completeExceptionally
(
cause
)
dataConsumer
.
failed
(
cause
)
}
override
fun
releaseResources
()
{
dataConsumer
.
releaseResources
()
}
}
@OptIn
(
InternalCoroutinesApi
::
class
)
internal
class
ApacheResponseConsumer
(
parentContext
:
CoroutineContext
,
private
val
requestData
:
HttpRequestData
)
:
AsyncEntityConsumer
<
Unit
>,
CoroutineScope
{
private
val
consumerJob
=
Job
(
parentContext
[
Job
])
override
val
coroutineContext
:
CoroutineContext
=
parentContext
+
consumerJob
private
val
channel
=
ByteChannel
().
also
{
it
.
attachJob
(
consumerJob
)
}
@Volatile
private
var
capacityChannel
:
CapacityChannel
?
=
null
private
val
messagesQueue
=
Channel
<
Any
>(
capacity
=
UNLIMITED
)
internal
val
responseChannel
:
ByteReadChannel
=
channel
init
{
coroutineContext
[
Job
]
?.
invokeOnCompletion
(
onCancelling
=
true
)
{
cause
->
if
(
cause
!=
null
)
{
responseChannel
.
cancel
(
cause
)
}
}
launch
(
coroutineContext
)
{
for
(
message
in
messagesQueue
)
{
when
(
message
)
{
is
CloseChannel
->
close
()
is
ByteBuffer
->
{
val
remaining
=
message
.
remaining
()
channel
.
writeFully
(
message
)
capacityChannel
?.
update
(
remaining
)
}
else
->
throw
IllegalStateException
(
"Unknown message $message"
)
}
}
}
}
override
fun
releaseResources
()
{
messagesQueue
.
close
()
}
override
fun
updateCapacity
(
capacityChannel
:
CapacityChannel
)
{
if
(
this
.
capacityChannel
==
null
)
{
this
.
capacityChannel
=
capacityChannel
capacityChannel
.
update
(
channel
.
availableForWrite
)
}
}
override
fun
consume
(
src
:
ByteBuffer
)
{
if
(
channel
.
isClosedForWrite
)
{
channel
.
closedCause
?.
let
{
throw
it
}
}
messagesQueue
.
trySend
(
src
.
copy
())
}
override
fun
streamEnd
(
trailers
:
List
<
Header
>?)
{
messagesQueue
.
trySend
(
CloseChannel
)
}
override
fun
streamStart
(
entityDetails
:
EntityDetails
,
resultCallback
:
FutureCallback
<
Unit
>)
{}
override
fun
failed
(
cause
:
Exception
)
{
val
mappedCause
=
mapCause
(
cause
,
requestData
)
consumerJob
.
completeExceptionally
(
mappedCause
)
responseChannel
.
cancel
(
mappedCause
)
}
internal
fun
close
()
{
channel
.
close
()
consumerJob
.
complete
()
}
override
fun
getContent
()
=
Unit
}
ktor-client/ktor-client-apache5/jvm/src/io/ktor/client/engine/apache5/ApacheUtils.kt
0 → 100644
Просмотр файла @
702364f9
/*
* Copyright 2014-2021 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
package
io.ktor.client.engine.apache5
import
java.net.*
/**
* Checks the message of the exception and identifies timeout exception by it.
*/
internal
fun
ConnectException
.
isTimeoutException
()
=
message
?.
contains
(
"Timeout connecting"
)
?:
false
ktor-client/ktor-client-apache5/jvm/test-resources/logback.xml
0 → 100644
Просмотр файла @
702364f9
<configuration>
<appender
name=
"STDOUT"
class=
"ch.qos.logback.core.ConsoleAppender"
>
<encoder>
<pattern>
%d{HH:mm:ss} %thread %-5level %logger{36} %msg%n
</pattern>
</encoder>
</appender>
<logger
name=
"org.apache"
level=
"ERROR"
/>
<logger
name=
"httpclient"
level=
"ERROR"
/>
<root
level=
"DEBUG"
>
<appender-ref
ref=
"STDOUT"
/>
</root>
</configuration>
ktor-client/ktor-client-apache5/jvm/test/io/ktor/client/engine/apache5/CommonTests.kt
0 → 100644
Просмотр файла @
702364f9
/*
* Copyright 2014-2022 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
package
io.ktor.client.engine.apache5
import
io.ktor.client.tests.*
class
Apache5HttpClientTest
:
HttpClientTest
(
Apache5
)
class
Apache5SslOverProxyTest
:
SslOverProxyTest
<
Apache5EngineConfig
>(
Apache5
)
{
override
fun
Apache5EngineConfig
.
disableCertificatePinning
()
{
this
.
sslContext
=
this
@Apache5SslOverProxyTest
.
unsafeSslContext
}
}
ktor-client/ktor-client-tests/build.gradle.kts
Просмотр файла @
702364f9
...
...
@@ -56,6 +56,7 @@ kotlin.sourceSets {
jvmTest
{
dependencies
{
api
(
project
(
":ktor-client:ktor-client-apache"
))
api
(
project
(
":ktor-client:ktor-client-apache5"
))
runtimeOnly
(
project
(
":ktor-client:ktor-client-android"
))
runtimeOnly
(
project
(
":ktor-client:ktor-client-okhttp"
))
if
(
currentJdk
>=
11
)
{
...
...
ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/HttpTimeoutTest.kt
Просмотр файла @
702364f9
...
...
@@ -459,7 +459,7 @@ class HttpTimeoutTest : ClientLoader() {
}
@Test
fun
testSocketTimeoutReadPerRequestAttributes
()
=
clientTests
(
listOf
(
"Js"
,
"native:CIO"
,
"Java"
))
{
fun
testSocketTimeoutReadPerRequestAttributes
()
=
clientTests
(
listOf
(
"Js"
,
"native:CIO"
,
"Java"
,
"Apache5"
))
{
config
{
install
(
HttpTimeout
)
}
...
...
@@ -490,7 +490,7 @@ class HttpTimeoutTest : ClientLoader() {
@Test
fun
testSocketTimeoutWriteFailOnWritePerRequestAttributes
()
=
clientTests
(
listOf
(
"Js"
,
"Android"
,
"native:CIO"
,
"Java"
)
listOf
(
"Js"
,
"Android"
,
"Apache5"
,
"native:CIO"
,
"Java"
)
)
{
config
{
install
(
HttpTimeout
)
...
...
ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/MultiPartFormDataTest.kt
Просмотр файла @
702364f9
...
...
@@ -4,10 +4,8 @@
package
io.ktor.client.tests
import
io.ktor.client.call.*
import
io.ktor.client.request.*
import
io.ktor.client.request.forms.*
import
io.ktor.client.statement.*
import
io.ktor.client.tests.utils.*
import
io.ktor.http.*
import
kotlin.test.*
...
...
ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/WebSocketTest.kt
Просмотр файла @
702364f9
...
...
@@ -17,7 +17,7 @@ import io.ktor.websocket.*
import
kotlinx.coroutines.*
import
kotlin.test.*
internal
val
ENGINES_WITHOUT_WS
=
listOf
(
"Android"
,
"Apache"
,
"Curl"
,
"DarwinLegacy"
)
internal
val
ENGINES_WITHOUT_WS
=
listOf
(
"Android"
,
"Apache"
,
"Apache5"
,
"Curl"
,
"DarwinLegacy"
)
private
const
val
TEST_SIZE
:
Int
=
100
...
...
@@ -111,7 +111,7 @@ class WebSocketTest : ClientLoader() {
}
@Test
fun
testWebsocketWithDefaultRequest
()
=
clientTests
(
ENGINES_WITHOUT_WS
)
{
fun
testWebsocketWithDefaultRequest
()
=
clientTests
(
ENGINES_WITHOUT_WS
+
"Js"
)
{
config
{
install
(
WebSockets
)
defaultRequest
{
...
...
@@ -142,7 +142,7 @@ class WebSocketTest : ClientLoader() {
}
@Test
fun
testExceptionWss
()
=
clientTests
(
listOf
(
"Android"
,
"Apache"
,
"Curl"
,
"JS"
,
"DarwinLegacy"
)
)
{
fun
testExceptionWss
()
=
clientTests
(
ENGINES_WITHOUT_WS
+
"Js"
)
{
config
{
install
(
WebSockets
)
}
...
...
ktor-client/ktor-client-tests/jvm/test-resources/logback.xml
0 → 100644
Просмотр файла @
702364f9
<configuration>
<appender
name=
"STDOUT"
class=
"ch.qos.logback.core.ConsoleAppender"
>
<encoder>
<pattern>
%d{HH:mm:ss} %thread %-5level %logger{36} %msg%n
</pattern>
</encoder>
</appender>
<logger
name=
"org.apache"
level=
"ERROR"
/>
<logger
name=
"httpclient"
level=
"ERROR"
/>
<root
level=
"DEBUG"
>
<appender-ref
ref=
"STDOUT"
/>
</root>
</configuration>
ktor-client/ktor-client-tests/jvm/test/io/ktor/client/tests/WebSocketJvmTest.kt
Просмотр файла @
702364f9
...
...
@@ -14,7 +14,7 @@ private const val TEST_SIZE: Int = 100
class
WebSocketJvmTest
:
ClientLoader
(
100000
)
{
@Test
fun
testWebSocketDeflateBinary
()
=
clientTests
(
listOf
(
"Android"
,
"Apache"
))
{
fun
testWebSocketDeflateBinary
()
=
clientTests
(
listOf
(
"Android"
,
"Apache"
,
"Apache5"
))
{
config
{
WebSockets
{
extensions
{
...
...
@@ -38,7 +38,7 @@ class WebSocketJvmTest : ClientLoader(100000) {
}
@Test
fun
testWebSocketDeflateNoContextTakeover
()
=
clientTests
(
listOf
(
"Android"
,
"Apache"
))
{
fun
testWebSocketDeflateNoContextTakeover
()
=
clientTests
(
listOf
(
"Android"
,
"Apache"
,
"Apache5"
))
{
config
{
WebSockets
{
extensions
{
...
...
settings.gradle.kts
Просмотр файла @
702364f9
...
...
@@ -62,6 +62,7 @@ include(":ktor-client")
include
(
":ktor-client:ktor-client-core"
)
include
(
":ktor-client:ktor-client-tests"
)
include
(
":ktor-client:ktor-client-apache"
)
include
(
":ktor-client:ktor-client-apache5"
)
include
(
":ktor-client:ktor-client-android"
)
include
(
":ktor-client:ktor-client-cio"
)
if
(
native_targets_enabled
)
{
...
...
Редактирование
Предварительный просмотр
Поддерживает Markdown
0%
Попробовать снова
или
прикрепить новый файл
.
Отмена
You are about to add
0
people
to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Отмена
Пожалуйста,
зарегистрируйтесь
или
войдите
чтобы прокомментировать