diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt
index 0b8048f00..ce67facff 100644
--- a/buildSrc/src/main/kotlin/Versions.kt
+++ b/buildSrc/src/main/kotlin/Versions.kt
@@ -31,7 +31,7 @@ object Versions {
     const val coroutines = "1.6.2"
     const val atomicFU = "0.17.2"
     const val serialization = "1.3.2"
-    const val ktor = "1.6.8"
+    const val ktor = "2.0.2"
 
     const val binaryValidator = "0.4.0"
 
@@ -110,7 +110,7 @@ val `ktor-client-core` = ktor("client-core", Versions.ktor)
 val `ktor-client-cio` = ktor("client-cio", Versions.ktor)
 val `ktor-client-mock` = ktor("client-mock", Versions.ktor)
 val `ktor-client-curl` = ktor("client-curl", Versions.ktor)
-val `ktor-client-ios` = ktor("client-ios", Versions.ktor)
+val `ktor-client-darwin` = ktor("client-darwin", Versions.ktor)
 val `ktor-client-okhttp` = ktor("client-okhttp", Versions.ktor)
 val `ktor-client-android` = ktor("client-android", Versions.ktor)
 val `ktor-client-logging` = ktor("client-logging", Versions.ktor)
diff --git a/logging/mirai-logging-log4j2/build.gradle.kts b/logging/mirai-logging-log4j2/build.gradle.kts
index 6fa225ab4..2f71c7b35 100644
--- a/logging/mirai-logging-log4j2/build.gradle.kts
+++ b/logging/mirai-logging-log4j2/build.gradle.kts
@@ -1,10 +1,10 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  *
- * https://github.com/mamoe/mirai/blob/master/LICENSE
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
 @file:Suppress("UnusedImport")
@@ -32,6 +32,7 @@ dependencies {
     testImplementation(`slf4j-api`)
     testImplementation(project(":mirai-core"))
     testImplementation(project(":mirai-core-utils"))
+    testImplementation(`ktor-client-okhttp`)
 }
 
 configurePublishing("mirai-logging-log4j2")
\ No newline at end of file
diff --git a/logging/mirai-logging-slf4j-logback/build.gradle.kts b/logging/mirai-logging-slf4j-logback/build.gradle.kts
index 8b3023311..78f520fab 100644
--- a/logging/mirai-logging-slf4j-logback/build.gradle.kts
+++ b/logging/mirai-logging-slf4j-logback/build.gradle.kts
@@ -1,10 +1,10 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  *
- * https://github.com/mamoe/mirai/blob/master/LICENSE
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
 @file:Suppress("UnusedImport")
@@ -33,6 +33,7 @@ dependencies {
 
     testImplementation(project(":mirai-core"))
     testImplementation(project(":mirai-core-utils"))
+    testImplementation(`ktor-client-okhttp`)
 }
 
 configurePublishing("mirai-logging-slf4j-logback")
\ No newline at end of file
diff --git a/logging/mirai-logging-slf4j-simple/build.gradle.kts b/logging/mirai-logging-slf4j-simple/build.gradle.kts
index 8015c1070..7eabbc7ee 100644
--- a/logging/mirai-logging-slf4j-simple/build.gradle.kts
+++ b/logging/mirai-logging-slf4j-simple/build.gradle.kts
@@ -1,10 +1,10 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  *
- * https://github.com/mamoe/mirai/blob/master/LICENSE
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
 @file:Suppress("UnusedImport")
@@ -33,6 +33,7 @@ dependencies {
 
     testImplementation(project(":mirai-core"))
     testImplementation(project(":mirai-core-utils"))
+    testImplementation(`ktor-client-okhttp`)
 }
 
 configurePublishing("mirai-logging-slf4j-simple")
\ No newline at end of file
diff --git a/logging/mirai-logging-slf4j/build.gradle.kts b/logging/mirai-logging-slf4j/build.gradle.kts
index 51bc654ba..a06e9681f 100644
--- a/logging/mirai-logging-slf4j/build.gradle.kts
+++ b/logging/mirai-logging-slf4j/build.gradle.kts
@@ -1,10 +1,10 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  *
- * https://github.com/mamoe/mirai/blob/master/LICENSE
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
 @file:Suppress("UnusedImport")
@@ -32,6 +32,7 @@ dependencies {
 
     testImplementation(project(":mirai-core"))
     testImplementation(project(":mirai-core-utils"))
+    testImplementation(`ktor-client-okhttp`)
 }
 
 configurePublishing("mirai-logging-slf4j")
\ No newline at end of file
diff --git a/mirai-console/backend/integration-test/testers/plugin-use-console-deps-fallback/build.gradle.kts b/mirai-console/backend/integration-test/testers/plugin-use-console-deps-fallback/build.gradle.kts
new file mode 100644
index 000000000..861dbe064
--- /dev/null
+++ b/mirai-console/backend/integration-test/testers/plugin-use-console-deps-fallback/build.gradle.kts
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+@file:Suppress("UnusedImport")
+
+plugins {
+    kotlin("jvm")
+    kotlin("plugin.serialization")
+    id("java")
+}
+
+version = "0.0.0"
+
+kotlin {
+    explicitApiWarning()
+}
+
+dependencies {
+    api(project(":mirai-console.integration-test"))
+    compileOnly(`ktor-client-okhttp`)
+}
diff --git a/mirai-console/backend/integration-test/testers/plugin-use-console-deps-fallback/src/PluginUseConsoleDepsFallback.kt b/mirai-console/backend/integration-test/testers/plugin-use-console-deps-fallback/src/PluginUseConsoleDepsFallback.kt
index 394db3041..d65d31c12 100644
--- a/mirai-console/backend/integration-test/testers/plugin-use-console-deps-fallback/src/PluginUseConsoleDepsFallback.kt
+++ b/mirai-console/backend/integration-test/testers/plugin-use-console-deps-fallback/src/PluginUseConsoleDepsFallback.kt
@@ -22,7 +22,7 @@ public class PluginUseConsoleDepsFallback :
     override fun onEnable() {
         logger.info { "Plugin loaded" }
         logger.info {
-            HttpClient(OkHttp).toString()
+            HttpClient(OkHttp).toString() // dependency is compileOnly
         }
     }
 }
\ No newline at end of file
diff --git a/mirai-core-api/build.gradle.kts b/mirai-core-api/build.gradle.kts
index 6c7aa3964..70e1ebf2e 100644
--- a/mirai-core-api/build.gradle.kts
+++ b/mirai-core-api/build.gradle.kts
@@ -56,7 +56,6 @@ kotlin {
 
         val jvmBaseMain by getting {
             dependencies {
-                api(`ktor-client-okhttp`)
                 api(`kotlinx-coroutines-jdk8`)
                 implementation(`jetbrains-annotations`)
                 implementation(`log4j-api`)
diff --git a/mirai-core-api/compatibility-validation/android/api/android.api b/mirai-core-api/compatibility-validation/android/api/android.api
index 03653bd1b..e402a68a7 100644
--- a/mirai-core-api/compatibility-validation/android/api/android.api
+++ b/mirai-core-api/compatibility-validation/android/api/android.api
@@ -96,7 +96,6 @@ public abstract interface class net/mamoe/mirai/IMirai : net/mamoe/mirai/LowLeve
 	public abstract fun downloadLongMessage (Lnet/mamoe/mirai/Bot;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public abstract fun getBotFactory ()Lnet/mamoe/mirai/BotFactory;
 	public abstract fun getFileCacheStrategy ()Lnet/mamoe/mirai/utils/FileCacheStrategy;
-	public abstract fun getHttp ()Lio/ktor/client/HttpClient;
 	public fun getOnlineOtherClientsList (Lnet/mamoe/mirai/Bot;Z)Ljava/util/List;
 	public abstract fun getOnlineOtherClientsList (Lnet/mamoe/mirai/Bot;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static synthetic fun getOnlineOtherClientsList$default (Lnet/mamoe/mirai/IMirai;Lnet/mamoe/mirai/Bot;ZILjava/lang/Object;)Ljava/util/List;
@@ -125,7 +124,6 @@ public abstract interface class net/mamoe/mirai/IMirai : net/mamoe/mirai/LowLeve
 	public fun sendNudge (Lnet/mamoe/mirai/Bot;Lnet/mamoe/mirai/message/action/Nudge;Lnet/mamoe/mirai/contact/Contact;)Z
 	public abstract fun sendNudge (Lnet/mamoe/mirai/Bot;Lnet/mamoe/mirai/message/action/Nudge;Lnet/mamoe/mirai/contact/Contact;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public abstract fun setFileCacheStrategy (Lnet/mamoe/mirai/utils/FileCacheStrategy;)V
-	public abstract fun setHttp (Lio/ktor/client/HttpClient;)V
 }
 
 public abstract interface class net/mamoe/mirai/LowLevelApiAccessor {
diff --git a/mirai-core-api/compatibility-validation/jvm/api/jvm.api b/mirai-core-api/compatibility-validation/jvm/api/jvm.api
index 28ca081ee..ee7ca4faa 100644
--- a/mirai-core-api/compatibility-validation/jvm/api/jvm.api
+++ b/mirai-core-api/compatibility-validation/jvm/api/jvm.api
@@ -96,7 +96,6 @@ public abstract interface class net/mamoe/mirai/IMirai : net/mamoe/mirai/LowLeve
 	public abstract fun downloadLongMessage (Lnet/mamoe/mirai/Bot;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public abstract fun getBotFactory ()Lnet/mamoe/mirai/BotFactory;
 	public abstract fun getFileCacheStrategy ()Lnet/mamoe/mirai/utils/FileCacheStrategy;
-	public abstract fun getHttp ()Lio/ktor/client/HttpClient;
 	public fun getOnlineOtherClientsList (Lnet/mamoe/mirai/Bot;Z)Ljava/util/List;
 	public abstract fun getOnlineOtherClientsList (Lnet/mamoe/mirai/Bot;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static synthetic fun getOnlineOtherClientsList$default (Lnet/mamoe/mirai/IMirai;Lnet/mamoe/mirai/Bot;ZILjava/lang/Object;)Ljava/util/List;
@@ -125,7 +124,6 @@ public abstract interface class net/mamoe/mirai/IMirai : net/mamoe/mirai/LowLeve
 	public fun sendNudge (Lnet/mamoe/mirai/Bot;Lnet/mamoe/mirai/message/action/Nudge;Lnet/mamoe/mirai/contact/Contact;)Z
 	public abstract fun sendNudge (Lnet/mamoe/mirai/Bot;Lnet/mamoe/mirai/message/action/Nudge;Lnet/mamoe/mirai/contact/Contact;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public abstract fun setFileCacheStrategy (Lnet/mamoe/mirai/utils/FileCacheStrategy;)V
-	public abstract fun setHttp (Lio/ktor/client/HttpClient;)V
 }
 
 public abstract interface class net/mamoe/mirai/LowLevelApiAccessor {
diff --git a/mirai-core-api/src/commonMain/kotlin/IMirai.kt b/mirai-core-api/src/commonMain/kotlin/IMirai.kt
index 908cd03e2..2d2b6bce3 100644
--- a/mirai-core-api/src/commonMain/kotlin/IMirai.kt
+++ b/mirai-core-api/src/commonMain/kotlin/IMirai.kt
@@ -92,15 +92,15 @@ public interface IMirai : LowLevelApiAccessor {
      */
     public var FileCacheStrategy: FileCacheStrategy
 
-    /**
-     * Mirai 上传好友图片等使用的 Ktor [HttpClient].
-     * 默认使用 [OkHttp] 引擎, 连接超时为 30s.
-     *
-     * 覆盖后将会立即应用到全局.
-     */
-    @Deprecated("Mirai is not going to use ktor. This is deprecated for removal.", level = DeprecationLevel.WARNING)
-    @DeprecatedSinceMirai(warningSince = "2.11.0")
-    public var Http: HttpClient
+//    /**
+//     * Mirai 上传好友图片等使用的 Ktor [HttpClient].
+//     * 默认使用 [OkHttp] 引擎, 连接超时为 30s.
+//     *
+//     * 覆盖后将会立即应用到全局.
+//     */
+//    @Deprecated("Mirai is not going to use ktor. This is deprecated for removal.", level = DeprecationLevel.WARNING)
+//    @DeprecatedSinceMirai(warningSince = "2.11.0")
+//    public var Http: HttpClient
 
     /**
      * 获取 uin.
diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/LoginSolver.TxCaptchaHelper.kt b/mirai-core-api/src/jvmMain/kotlin/utils/LoginSolver.TxCaptchaHelper.kt
index c30d80971..5ceaacd3a 100644
--- a/mirai-core-api/src/jvmMain/kotlin/utils/LoginSolver.TxCaptchaHelper.kt
+++ b/mirai-core-api/src/jvmMain/kotlin/utils/LoginSolver.TxCaptchaHelper.kt
@@ -11,27 +11,15 @@ package net.mamoe.mirai.utils
 
 import io.ktor.client.*
 import io.ktor.client.request.*
+import io.ktor.client.statement.*
 import kotlinx.coroutines.*
-import net.mamoe.mirai.Mirai
 
 internal abstract class TxCaptchaHelper {
-    private val newClient: Boolean
-    val client: HttpClient
+    private val newClient: Boolean = true
+    val client: HttpClient = HttpClient()
     private lateinit var queue: Job
 
-    init {
-        var newClient = false
-        client = try {
-            @Suppress("DEPRECATION", "DEPRECATION_ERROR")
-            Mirai.Http
-        } catch (ignore: Throwable) {
-            newClient = true
-            HttpClient()
-        }
-        this.newClient = newClient
-    }
-
-    internal var latestDisplay = "Sending request..."
+    private var latestDisplay = "Sending request..."
 
     abstract fun onComplete(ticket: String)
     abstract fun updateDisplay(msg: String)
@@ -42,7 +30,7 @@ internal abstract class TxCaptchaHelper {
             updateDisplay(latestDisplay)
             while (isActive) {
                 try {
-                    val response: String = client.get(url0)
+                    val response: String = client.get(url0).bodyAsText()
                     if (response.startsWith("请在")) {
                         if (response != latestDisplay) {
                             latestDisplay = response
diff --git a/mirai-core-utils/src/commonTest/kotlin/net/mamoe/mirai/utils/CommonByteArrayOpTest.kt b/mirai-core-utils/src/commonTest/kotlin/net/mamoe/mirai/utils/CommonByteArrayOpTest.kt
index 8f2c564ab..920788768 100644
--- a/mirai-core-utils/src/commonTest/kotlin/net/mamoe/mirai/utils/CommonByteArrayOpTest.kt
+++ b/mirai-core-utils/src/commonTest/kotlin/net/mamoe/mirai/utils/CommonByteArrayOpTest.kt
@@ -220,7 +220,7 @@ internal open class CommonByteArrayOpTest {
         val result =
             "1F 8B 08 00 00 00 00 00 00 FF 2B 74 CF F3 32 0C 2A 72 73 B6 04 00 A8 35 6D D9 0A 00 00 00".hexToBytes()
                 .toReadPacket(release = { released = true }).let { input ->
-                    GzipDecompressionInput(input).readText().also {
+                    GzipDecompressionInput(input).readAllText().also {
                         assertEquals(true, input.endOfInput)
                         assertEquals(true, released)
                     }
@@ -278,7 +278,7 @@ internal open class CommonByteArrayOpTest {
         val result =
             "78 9C 2B 74 CF F3 32 0C 2A 72 73 B6 04 00 12 82 03 28".hexToBytes()
                 .toReadPacket(release = { released = true }).let { input ->
-                    InflateInput(input).readText().also {
+                    InflateInput(input).readAllText().also {
                         assertEquals(true, input.endOfInput)
                         assertEquals(true, released)
                     }
diff --git a/mirai-core-utils/src/nativeMain/kotlin/ByteArrayOp.kt b/mirai-core-utils/src/nativeMain/kotlin/ByteArrayOp.kt
index 8064065d7..170284331 100644
--- a/mirai-core-utils/src/nativeMain/kotlin/ByteArrayOp.kt
+++ b/mirai-core-utils/src/nativeMain/kotlin/ByteArrayOp.kt
@@ -153,7 +153,7 @@ internal class ZlibInput(
     private val zlibHasPending: ((z_streamp) -> Boolean)?, // null lambda means operation not defined
     private val zlibFlushMode: (shouldFlushAll: Boolean) -> Int,
     private val zlibEnd: (z_streamp) -> Int,
-) : Input {
+) : Input() {
     private val z: z_stream = nativeHeap.alloc()
     // Zlib manual: https://refspecs.linuxbase.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/zlib-inflate-1.html
 
@@ -165,123 +165,73 @@ internal class ZlibInput(
         }
     }
 
-    @Deprecated(
-        "Not supported anymore. All operations are big endian by default. Use readXXXLittleEndian or readXXX then X.reverseByteOrder() instead.",
-        level = DeprecationLevel.ERROR
-    )
-    override var byteOrder: ByteOrder
-        get() = throw UnsupportedOperationException()
-        set(_) {
-            throw UnsupportedOperationException()
-        }
-
-    private var bufferReadableSize = 0
+    private var bufferReadableSize = 0L
     private val inputBuffer = nativeHeap.allocArray<ByteVar>(ZLIB_BUFFER_SIZE)
-    private val buffer = nativeHeap.allocArray<ByteVar>(ZLIB_BUFFER_SIZE)
-    private var bufferIndex = 0L
 
-    private var closed: Boolean = false
-
-    override val endOfInput: Boolean
-        get() = closed || !prepare()
+    private var closed = false
 
     override fun close() {
-        debug { "closing" }
         if (closed) return
-        this.closed = true
-
-        source.close()
-        zlibEnd(z.ptr)
-        nativeHeap.free(z)
-        nativeHeap.free(buffer)
+        closed = true
+        debug { "close" }
+        super.close()
+        debug { "freeing inputBuffer" }
         nativeHeap.free(inputBuffer)
+        debug { "freed" }
     }
 
-    override fun discard(n: Long): Long {
-        if (closed) {
-            return 0
-        }
-        val old = bufferIndex
-        if (old >= bufferReadableSize) {
-            if (prepare()) return discard(n)
-            return 0
-        }
-        bufferIndex = (bufferIndex + n).coerceAtMost(ZLIB_BUFFER_SIZE)
-        return bufferIndex - old
+    override fun closeSource() {
+        debug { "closeSource" }
+        source.close()
+        debug { "zlibEnd" }
+        zlibEnd(z.ptr)
+        debug { "zlibEnd done" }
     }
 
-    override fun peekTo(destination: Memory, destinationOffset: Long, offset: Long, min: Long, max: Long): Long {
-        debug()
-        debug { "peekTo" }
-        require(min <= max) { "min > max" }
-        if (!prepare()) return 0
-        val readableLength = (bufferReadableSize - bufferIndex - offset).coerceAtLeast(0)
-        if (offset > readableLength) {
-            if (min == 0L) {
-                throw EOFException("offset($offset) > readableLength($readableLength)")
-            }
-        }
-        if (min > readableLength) return 0
-        val len = readableLength.coerceAtMost(max).coerceAtMost(destination.size)
-        debug { "peekTo: read $len" }
-        buffer.copyTo(destination, bufferIndex + offset, len, destinationOffset)
+    override fun fill(destination: Memory, offset: Int, length: Int): Int {
+        require(offset in 0..destination.size32) { "invalid offset: $offset" }
+        require(length in 0..destination.size32) { "invalid length: $length" }
+        require(offset + length in 0..destination.size32) { "invalid offset and length: $offset, $length" }
 
-        return len
-    }
-
-    override fun readByte(): Byte {
-        if (!prepare()) {
-            throw EOFException("One more byte required")
-        }
-        return buffer[bufferIndex++]
-    }
-
-    override fun tryPeek(): Int {
-        if (!prepare()) {
-            return -1
-        }
-        return buffer[bufferIndex].toIntUnsigned()
-    }
-
-    private fun prepare(): Boolean {
-        if (closed) {
-            return false
-        }
-        debug { "prepare: bufferIndex = $bufferIndex, bufferReadableSize = $bufferReadableSize" }
-        if (bufferIndex < bufferReadableSize) {
-            debug { "prepare returned, because " }
-            return true // has buf unused
-        }
-
-        bufferIndex = 0
+        debug { "prepare:  bufferReadableSize = $bufferReadableSize" }
         debug { "prepare: previous value: z.avail_in=${z.avail_in}, z.avail_out=${z.avail_out}" }
 
-        if (z.avail_in == 0u) {
+        val filled = try {
+            if (z.avail_in == 0u) {
 
-            // These two cases are similar.
+                // These two cases are similar.
 //            if (z.avail_out == 0u) {
 //                // Last time we used all the output, there is either something cached in Zlib, or no further source.
 //            } else {
 //                // We did not use all the inputs, meaning least time we used all avail_in.
 //            }
 
-            // bot input and output are used
-            val flush = updateAvailIn() ?: return false
-            copyOutputsFromZlib(flush)
-        } else {
-            // Inputs not used up.
-            copyOutputsFromZlib(Z_NO_FLUSH)
-        }
+                // bot input and output are used
+                val flush = updateAvailIn() ?: return 0
+                copyOutputsFromZlib(destination, offset, length, flush)
+            } else {
+                // Inputs not used up.
+                copyOutputsFromZlib(destination, offset, length, Z_NO_FLUSH)
+            }
 
-        return true
+        } catch (e: Throwable) {
+            // If you throw this error up, ktor will somehow kill the process. (Ktor 2.0.2)
+            debug { e.printStackTrace(); "" }
+            return 0
+        }
+        check(filled in 0..length) { "Filled more than $length bytes: $filled" }
+        check(filled in 0..destination.size) { "Filled more than ${destination.size} bytes: $filled" }
+        return filled
     }
 
-    private fun copyOutputsFromZlib(flush: Int): Boolean {
-        z.avail_out = ZLIB_BUFFER_SIZE.toUInt()
-        z.next_out = buffer.reinterpret()
+    private fun copyOutputsFromZlib(memory: Memory, offset: Int, length: Int, flush: Int): Int {
+        debug { "copyOutputsFromZlib, memory.offset = $offset, memory.length=$length, memory.size=${memory.size}" }
+
+        z.avail_out = length.convert()
+        z.next_out = (memory.pointer + offset)!!.reinterpret()
 
         // We still have input, no need to update.
-        debug { "Set z.avail_out=${z.avail_out}, z.next_out=buffer.reinterpret()" }
+        debug { "Set z.avail_out=${z.avail_out}, z.next_out=(memory.pointer + offset)!!.reinterpret()" }
         debug { "Calling zlib, flush = $flush" }
 
         val p = zlibProcess(z.ptr, flush)
@@ -293,23 +243,23 @@ internal class ZlibInput(
             Z_NEED_DICT -> error("Zlib failed to process data. (Z_NEED_DICT)")
             else -> debug { "zlib: $p" }
         }
-        bufferReadableSize = (ZLIB_BUFFER_SIZE.toUInt() - z.avail_out).toInt()
+        val readSize = (length.toUInt() - z.avail_out).toInt()
 
-        debug { "Zlib produced bufferReadableSize=$bufferReadableSize  bytes" }
-        debug { "Partial output: ${buffer.readBytes(bufferReadableSize).toUHexString()}" }
+        debug { "Zlib produced readSize=$readSize  bytes" }
+//        debug { "Partial output: ${memory.readBytes(bufferReadableSize).toUHexString()}" }
         debug { "Now z.avail_in=${z.avail_in}, z.avail_out=${z.avail_out}" }
 
         if (p == Z_FINISH) {
             debug { "Zlib returned Z_FINISH. Ignoring result check." }
-            return true
+            return readSize
         }
 
         if (p == Z_STREAM_END) {
             debug { "Zlib returned Z_STREAM_END. Ignoring result check." }
-            return true
+            return readSize
         }
 
-        if (bufferReadableSize == 0 && (z.avail_in == 0u && source.endOfInput)) {
+        if (bufferReadableSize == 0L && (z.avail_in == 0u && source.endOfInput)) {
             if (zlibHasPending?.invoke(z.ptr) == true) {
                 // has pending. So the data must be incomplete.
                 error("Failed to process data, possibly bad data inputted.")
@@ -324,7 +274,7 @@ internal class ZlibInput(
             }
             // can't read
         }
-        return true
+        return readSize
     }
 
     private fun updateAvailIn(): Int? {
@@ -334,6 +284,7 @@ internal class ZlibInput(
             close() // automatically close
             return null // no more source available
         }
+        bufferReadableSize = read
         z.avail_in = read.toUInt()
         val flush = zlibFlushMode(read < ZLIB_BUFFER_SIZE || source.endOfInput)
         debug { "inputBuffer content: " + inputBuffer.readBytes(read.toInt()).toUHexString() }
diff --git a/mirai-core-utils/src/nativeMain/kotlin/MiraiFile.kt b/mirai-core-utils/src/nativeMain/kotlin/MiraiFile.kt
index 308bd3b86..798037742 100644
--- a/mirai-core-utils/src/nativeMain/kotlin/MiraiFile.kt
+++ b/mirai-core-utils/src/nativeMain/kotlin/MiraiFile.kt
@@ -14,7 +14,6 @@ package net.mamoe.mirai.utils
 import io.ktor.utils.io.bits.*
 import io.ktor.utils.io.core.*
 import io.ktor.utils.io.errors.*
-import io.ktor.utils.io.streams.*
 import kotlinx.cinterop.*
 import platform.posix.*
 
@@ -162,8 +161,7 @@ internal class FileNotFoundException(message: String, cause: Throwable? = null)
 
 
 @Suppress("DEPRECATION")
-@OptIn(ExperimentalIoApi::class)
-internal class PosixFileInstanceOutput(val file: CPointer<FILE>) : AbstractOutput() {
+internal class PosixFileInstanceOutput(val file: CPointer<FILE>) : Output() {
     private var closed = false
 
     override fun flush(source: Memory, offset: Int, length: Int) {
@@ -171,7 +169,12 @@ internal class PosixFileInstanceOutput(val file: CPointer<FILE>) : AbstractOutpu
         var currentOffset = offset
 
         while (currentOffset < end) {
-            val result = fwrite(source, currentOffset, end - currentOffset, file.cast())
+            val result = fwrite(
+                source.pointer + currentOffset.convert(),
+                sizeOf<ByteVar>().convert(),
+                (end - currentOffset).convert(),
+                file.cast()
+            ).convert<Int>()
             if (result == 0) {
                 throw PosixException.forErrno(posixFunctionName = "fwrite()").wrapIO()
             }
@@ -190,12 +193,16 @@ internal class PosixFileInstanceOutput(val file: CPointer<FILE>) : AbstractOutpu
 }
 
 @Suppress("DEPRECATION")
-@OptIn(ExperimentalIoApi::class)
-internal class PosixInputForFile(val file: CPointer<FILE>) : AbstractInput() {
+internal class PosixInputForFile(val file: CPointer<FILE>) : Input() {
     private var closed = false
 
     override fun fill(destination: Memory, offset: Int, length: Int): Int {
-        val size = fread(destination, offset, length, file.cast())
+        val size = fread(
+            destination.pointer + offset.convert(),
+            sizeOf<ByteVar>().convert(),
+            length.convert(),
+            file.cast()
+        ).toInt()
         if (size == 0) {
             if (feof(file) != 0) return 0
             throw PosixException.forErrno(posixFunctionName = "read()").wrapIO()
@@ -214,6 +221,5 @@ internal class PosixInputForFile(val file: CPointer<FILE>) : AbstractInput() {
     }
 }
 
-@OptIn(ExperimentalIoApi::class)
 public fun PosixException.wrapIO(): IOException =
     IOException("I/O operation failed due to posix error code $errno", this)
diff --git a/mirai-core-utils/src/unixMain/kotlin/MiraiFileImpl.kt b/mirai-core-utils/src/unixMain/kotlin/MiraiFileImpl.kt
index 9cfe54a8c..8fdbebe64 100644
--- a/mirai-core-utils/src/unixMain/kotlin/MiraiFileImpl.kt
+++ b/mirai-core-utils/src/unixMain/kotlin/MiraiFileImpl.kt
@@ -14,7 +14,6 @@ import io.ktor.utils.io.errors.*
 import kotlinx.cinterop.*
 import platform.posix.*
 
-@OptIn(ExperimentalIoApi::class)
 private fun readlink(path: String): String = memScoped {
     val len = realpath(path, null)
     if (len != null) {
@@ -114,7 +113,6 @@ internal actual class MiraiFileImpl actual constructor(
         return resolve(parent).resolve(file.name)
     }
 
-    @OptIn(UnsafeNumber::class)
     override fun createNewFile(): Boolean {
         memScoped {
             val fp = fopen(absolutePath, "w")
@@ -155,7 +153,6 @@ internal actual class MiraiFileImpl actual constructor(
         }
     }
 
-    @OptIn(ExperimentalIoApi::class)
     override fun input(): Input {
         val handle = fopen(absolutePath, "rb")
             ?: throw IOException(
@@ -165,7 +162,6 @@ internal actual class MiraiFileImpl actual constructor(
         return PosixInputForFile(handle)
     }
 
-    @OptIn(ExperimentalIoApi::class)
     override fun output(): Output {
         val handle = fopen(absolutePath, "wb")
             ?: throw IOException(
diff --git a/mirai-core/build.gradle.kts b/mirai-core/build.gradle.kts
index 5fd0f1d5d..794d5069e 100644
--- a/mirai-core/build.gradle.kts
+++ b/mirai-core/build.gradle.kts
@@ -153,13 +153,13 @@ kotlin {
 
         configure(LINUX_TARGETS.map { getByName(it + "Main") }) {
             dependencies {
-                implementation(`ktor-client-curl`)
+                implementation(`ktor-client-cio`)
             }
         }
 
         val darwinMain by getting {
             dependencies {
-                implementation(`ktor-client-ios`)
+                implementation(`ktor-client-darwin`)
             }
         }
 
diff --git a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt
index aed9103cd..264470a8d 100644
--- a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt
+++ b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt
@@ -14,6 +14,7 @@ package net.mamoe.mirai.internal
 import io.ktor.client.*
 import io.ktor.client.request.*
 import io.ktor.client.request.forms.*
+import io.ktor.client.statement.*
 import io.ktor.utils.io.core.*
 import kotlinx.serialization.json.Json
 import kotlinx.serialization.json.JsonObject
@@ -93,8 +94,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
 
     override var FileCacheStrategy: FileCacheStrategy = net.mamoe.mirai.utils.FileCacheStrategy.PlatformDefault
 
-    @Deprecated("Mirai is not going to use ktor. This is deprecated for removal.", level = DeprecationLevel.WARNING)
-    override var Http: HttpClient = createDefaultHttpClient()
+    @Suppress("PrivatePropertyName")
+    private val httpClient: HttpClient = createDefaultHttpClient()
 
     override suspend fun acceptNewFriendRequest(event: NewFriendRequestEvent) {
         @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
@@ -530,8 +531,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
     override suspend fun getRawGroupActiveData(bot: Bot, groupId: Long, page: Int): GroupActiveData =
         bot.asQQAndroidBot().run {
             val rep = network.run {
-                @Suppress("DEPRECATION", "DEPRECATION_ERROR")
-                Mirai.Http.get<String> {
+                httpClient.get() {
                     url("https://qqweb.qq.com/c/activedata/get_mygroup_data")
                     parameter("bkn", client.wLoginSigInfo.bkn)
                     parameter("gc", groupId)
@@ -547,7 +547,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
                     }
                 }
             }
-            return json.decodeFromString(GroupActiveData.serializer(), rep)
+            return json.decodeFromString(GroupActiveData.serializer(), rep.bodyAsText())
         }
 
     @LowLevelApi
@@ -558,8 +558,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
         type: GroupHonorType
     ): GroupHonorListData? = bot.asQQAndroidBot().run {
         val rep = network.run {
-            @Suppress("DEPRECATION", "DEPRECATION_ERROR")
-            Mirai.Http.get<String> {
+            httpClient.get {
                 url("https://qun.qq.com/interactive/honorlist")
                 parameter("gc", groupId)
                 parameter("type", type.value)
@@ -575,7 +574,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
                 }
             }
         }
-        val jsonText = Regex("""window.__INITIAL_STATE__=(.+?)</script>""").find(rep)?.groupValues?.get(1)
+        val jsonText = Regex("""window.__INITIAL_STATE__=(.+?)</script>""").find(rep.bodyAsText())?.groupValues?.get(1)
         return jsonText?.let { json.decodeFromString(GroupHonorListData.serializer(), it) }
     }
 
@@ -670,16 +669,17 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
         seconds: Int
     ) {
         bot as QQAndroidBot
-        @Suppress("DEPRECATION", "DEPRECATION_ERROR")
-        val response = Mirai.Http.post<String> {
+        val response = httpClient.post {
             url("https://qqweb.qq.com/c/anonymoustalk/blacklist")
-            body = MultiPartFormDataContent(formData {
-                append("anony_id", anonymousId)
-                append("group_code", groupId)
-                append("seconds", seconds)
-                append("anony_nick", anonymousNick)
-                append("bkn", bot.client.wLoginSigInfo.bkn)
-            })
+            setBody(
+                MultiPartFormDataContent(formData {
+                    append("anony_id", anonymousId)
+                    append("group_code", groupId)
+                    append("seconds", seconds)
+                    append("anony_nick", anonymousNick)
+                    append("bkn", bot.client.wLoginSigInfo.bkn)
+                })
+            )
             headers {
                 // ktor bug
                 append(
@@ -687,7 +687,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
                     "uin=o${bot.id}; skey=${bot.sKey};"
                 )
             }
-        }
+        }.bodyAsText()
         val jsonObj = Json.decodeFromString(JsonObject.serializer(), response)
         if ((jsonObj["retcode"] ?: jsonObj["cgicode"] ?: error("missing response code")).jsonPrimitive.long != 0L) {
             throw IllegalStateException(response)
@@ -828,8 +828,6 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
         bot.asQQAndroidBot()
         when (val resp = bot.network.sendAndExpect(MultiMsg.ApplyDown(bot.client, 2, resourceId, 1))) {
             is MultiMsg.ApplyDown.Response.RequireDownload -> {
-                @Suppress("DEPRECATION", "DEPRECATION_ERROR")
-                val http = Mirai.Http
                 val origin = resp.origin
 
                 val data: ByteArray = if (origin.msgExternInfo?.channelType == 2) {
@@ -841,16 +839,16 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
                         resourceKind = resourceKind,
                         channelKind = ChannelKind.HTTP
                     ) { host, _ ->
-                        http.get("$host${origin.thumbDownPara}")
-                    }
+                        httpClient.get("$host${origin.thumbDownPara}")
+                    }.readBytes()
                 } else tryServersDownload(
                     bot = bot,
                     servers = origin.uint32DownIp.zip(origin.uint32DownPort),
                     resourceKind = resourceKind,
                     channelKind = ChannelKind.HTTP
                 ) { ip, port ->
-                    http.get("http://$ip:$port${origin.thumbDownPara}")
-                }
+                    httpClient.get("http://$ip:$port${origin.thumbDownPara}")
+                }.readBytes()
 
                 val body = data.read {
                     check(readByte() == 40.toByte()) {
diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt
index f8615b865..b921edfe3 100644
--- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt
+++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt
@@ -203,6 +203,7 @@ internal open class QQAndroidBot constructor(
         set(SsoProcessor, SsoProcessorImpl(get(SsoProcessorContext)))
         set(HeartbeatProcessor, HeartbeatProcessorImpl())
         set(HeartbeatScheduler, TimeBasedHeartbeatSchedulerImpl(networkLogger.subLogger("HeartbeatScheduler")))
+        set(HttpClientProvider, HttpClientProviderImpl())
         set(KeyRefreshProcessor, KeyRefreshProcessorImpl(networkLogger.subLogger("KeyRefreshProcessor")))
         set(ConfigPushProcessor, ConfigPushProcessorImpl(networkLogger.subLogger("ConfigPushProcessor")))
         set(BotOfflineEventMonitor, BotOfflineEventMonitorImpl())
diff --git a/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt b/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt
index 1b35fcc14..37e35bb2c 100644
--- a/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt
+++ b/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt
@@ -9,7 +9,6 @@
 
 package net.mamoe.mirai.internal.contact
 
-import net.mamoe.mirai.Mirai
 import net.mamoe.mirai.contact.Friend
 import net.mamoe.mirai.contact.Member
 import net.mamoe.mirai.contact.Stranger
@@ -27,6 +26,7 @@ import net.mamoe.mirai.internal.message.protocol.outgoing.MessageProtocolStrateg
 import net.mamoe.mirai.internal.network.component.buildComponentStorage
 import net.mamoe.mirai.internal.network.components.BdhSession
 import net.mamoe.mirai.internal.network.components.ClockHolder
+import net.mamoe.mirai.internal.network.components.HttpClientProvider
 import net.mamoe.mirai.internal.network.highway.ChannelKind
 import net.mamoe.mirai.internal.network.highway.Highway
 import net.mamoe.mirai.internal.network.highway.ResourceKind.PRIVATE_IMAGE
@@ -202,7 +202,7 @@ internal sealed class AbstractUser(
                         resourceKind = PRIVATE_IMAGE,
                         channelKind = ChannelKind.HTTP
                     ) { ip, port ->
-                        @Suppress("DEPRECATION", "DEPRECATION_ERROR") Mirai.Http.postImage(
+                        bot.components[HttpClientProvider].getHttpClient().postImage(
                             serverIp = ip,
                             serverPort = port,
                             htcmd = "0x6ff0070",
@@ -214,7 +214,7 @@ internal sealed class AbstractUser(
                     }
                 }.recoverCatchingSuppressed {
                     // try upload by http on fallback server
-                    @Suppress("DEPRECATION", "DEPRECATION_ERROR") Mirai.Http.postImage(
+                    bot.components[HttpClientProvider].getHttpClient().postImage(
                         serverIp = "htdata2.qq.com",
                         htcmd = "0x6ff0070",
                         uin = bot.id,
diff --git a/mirai-core/src/commonMain/kotlin/contact/FriendImpl.kt b/mirai-core/src/commonMain/kotlin/contact/FriendImpl.kt
index 4f8ab87d7..1ea206b66 100644
--- a/mirai-core/src/commonMain/kotlin/contact/FriendImpl.kt
+++ b/mirai-core/src/commonMain/kotlin/contact/FriendImpl.kt
@@ -16,7 +16,6 @@ package net.mamoe.mirai.internal.contact
 
 import io.ktor.utils.io.core.*
 import net.mamoe.mirai.LowLevelApi
-import net.mamoe.mirai.Mirai
 import net.mamoe.mirai.contact.Friend
 import net.mamoe.mirai.contact.roaming.RoamingMessages
 import net.mamoe.mirai.event.events.FriendMessagePostSendEvent
@@ -27,6 +26,7 @@ import net.mamoe.mirai.internal.contact.roaming.RoamingMessagesImplFriend
 import net.mamoe.mirai.internal.message.data.OfflineAudioImpl
 import net.mamoe.mirai.internal.message.protocol.outgoing.FriendMessageProtocolStrategy
 import net.mamoe.mirai.internal.message.protocol.outgoing.MessageProtocolStrategy
+import net.mamoe.mirai.internal.network.components.HttpClientProvider
 import net.mamoe.mirai.internal.network.highway.*
 import net.mamoe.mirai.internal.network.protocol.data.proto.Cmd0x346
 import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
@@ -93,6 +93,7 @@ internal class FriendImpl(
     override suspend fun uploadAudio(resource: ExternalResource): OfflineAudio = AudioToSilkService.convert(
         resource
     ).useAutoClose { res ->
+
         var audio: OfflineAudioImpl? = null
         kotlin.runCatching {
             val resp = Highway.uploadResourceBdh(
@@ -133,8 +134,8 @@ internal class FriendImpl(
                         ResourceKind.GROUP_AUDIO,
                         ChannelKind.HTTP
                     ) { ip, port ->
-                        @Suppress("DEPRECATION", "DEPRECATION_ERROR")
-                        Mirai.Http.postPtt(ip, port, res, resp.uKey, resp.fileKey)
+                        bot.components[HttpClientProvider].getHttpClient()
+                            .postPtt(ip, port, res, resp.uKey, resp.fileKey)
                     }
                     audio = OfflineAudioImpl(
                         filename = "${res.md5.toUHexString("")}.amr",
diff --git a/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt b/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
index 3d63afd12..2b7de1258 100644
--- a/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
+++ b/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
@@ -15,7 +15,6 @@ package net.mamoe.mirai.internal.contact
 import kotlinx.atomicfu.atomic
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.LowLevelApi
-import net.mamoe.mirai.Mirai
 import net.mamoe.mirai.contact.*
 import net.mamoe.mirai.contact.announcement.Announcements
 import net.mamoe.mirai.contact.file.RemoteFiles
@@ -36,6 +35,7 @@ import net.mamoe.mirai.internal.message.image.getImageTypeById
 import net.mamoe.mirai.internal.message.protocol.outgoing.GroupMessageProtocolStrategy
 import net.mamoe.mirai.internal.message.protocol.outgoing.MessageProtocolStrategy
 import net.mamoe.mirai.internal.network.components.BdhSession
+import net.mamoe.mirai.internal.network.components.HttpClientProvider
 import net.mamoe.mirai.internal.network.handler.logger
 import net.mamoe.mirai.internal.network.highway.ChannelKind
 import net.mamoe.mirai.internal.network.highway.Highway
@@ -322,8 +322,8 @@ internal abstract class CommonGroupImpl constructor(
                         GROUP_AUDIO,
                         ChannelKind.HTTP
                     ) { ip, port ->
-                        @Suppress("DEPRECATION", "DEPRECATION_ERROR")
-                        Mirai.Http.postPtt(ip, port, resource, resp.uKey, resp.fileKey)
+                        bot.components[HttpClientProvider].getHttpClient()
+                            .postPtt(ip, port, resource, resp.uKey, resp.fileKey)
                     }
                 }
             }
diff --git a/mirai-core/src/commonMain/kotlin/contact/announcement/AnnouncementsImpl.kt b/mirai-core/src/commonMain/kotlin/contact/announcement/AnnouncementsImpl.kt
index f9d9221c0..50977a8d7 100644
--- a/mirai-core/src/commonMain/kotlin/contact/announcement/AnnouncementsImpl.kt
+++ b/mirai-core/src/commonMain/kotlin/contact/announcement/AnnouncementsImpl.kt
@@ -13,19 +13,17 @@ package net.mamoe.mirai.internal.contact.announcement
 
 import io.ktor.client.request.*
 import io.ktor.client.request.forms.*
+import io.ktor.client.statement.*
 import io.ktor.http.*
-import io.ktor.util.*
 import kotlinx.coroutines.flow.*
 import kotlinx.serialization.SerialName
 import kotlinx.serialization.Serializable
-import net.mamoe.mirai.Bot
-import net.mamoe.mirai.Mirai
 import net.mamoe.mirai.contact.Group
 import net.mamoe.mirai.contact.MemberPermission
 import net.mamoe.mirai.contact.announcement.*
 import net.mamoe.mirai.contact.checkBotPermission
+import net.mamoe.mirai.internal.AbstractBot
 import net.mamoe.mirai.internal.QQAndroidBot
-import net.mamoe.mirai.internal.asQQAndroidBot
 import net.mamoe.mirai.internal.contact.GroupImpl
 import net.mamoe.mirai.internal.contact.OnlineAnnouncementImpl
 import net.mamoe.mirai.internal.contact.announcement.AnnouncementProtocol.deleteGroupAnnouncement
@@ -34,6 +32,8 @@ import net.mamoe.mirai.internal.contact.announcement.AnnouncementProtocol.getRaw
 import net.mamoe.mirai.internal.contact.announcement.AnnouncementProtocol.sendGroupAnnouncement
 import net.mamoe.mirai.internal.contact.announcement.AnnouncementProtocol.toAnnouncement
 import net.mamoe.mirai.internal.contact.announcement.AnnouncementProtocol.toGroupAnnouncement
+import net.mamoe.mirai.internal.network.client
+import net.mamoe.mirai.internal.network.components.HttpClientProvider
 import net.mamoe.mirai.internal.network.highway.ChannelKind
 import net.mamoe.mirai.internal.network.highway.ResourceKind
 import net.mamoe.mirai.internal.network.highway.tryServersUpload
@@ -154,31 +154,32 @@ internal object AnnouncementProtocol {
     ) : CheckableResponseA(), JsonStruct
 
     suspend fun uploadGroupAnnouncementImage(
-        bot: Bot,
+        bot: AbstractBot,
         resource: ExternalResource
-    ): AnnouncementImage = bot.asQQAndroidBot().run {
-        @OptIn(InternalAPI::class) // ktor bug
-        val resp = Mirai.Http.post<String> {
+    ): AnnouncementImage = bot.run {
+        val resp = bot.components[HttpClientProvider].getHttpClient().post {
             url("https://web.qun.qq.com/cgi-bin/announce/upload_img")
-            body = MultiPartFormDataContent(formData {
-                append("\"bkn\"", client.wLoginSigInfo.bkn)
-                append("\"source\"", "troopNotice")
-                append("m", "0")
-                append(
-                    "\"pic_up\"",
-                    headers = Headers.build {
-                        append(HttpHeaders.ContentType, ContentType.Image.PNG)
-                        append(HttpHeaders.ContentDisposition, "filename=\"temp_uploadFile.png\"")
+            setBody(
+                MultiPartFormDataContent(formData {
+                    append("\"bkn\"", client.wLoginSigInfo.bkn)
+                    append("\"source\"", "troopNotice")
+                    append("m", "0")
+                    append(
+                        "\"pic_up\"",
+                        headers = Headers.build {
+                            append(HttpHeaders.ContentType, ContentType.Image.PNG)
+                            append(HttpHeaders.ContentDisposition, "filename=\"temp_uploadFile.png\"")
+                        }
+                    ) {
+                        writeResource(resource)
                     }
-                ) {
-                    writeResource(resource)
-                }
-            })
+                })
+            )
             cookie("uin", "o$id")
             cookie("p_uin", "o$id")
             cookie("skey", sKey)
             cookie("p_skey", psKey("qun.qq.com"))
-        }.loadSafelyAs(UploadImageResp.serializer()).check()
+        }.bodyAsText().loadSafelyAs(UploadImageResp.serializer()).check()
         return resp.id.replace("&quot;", "\"").loadSafelyAs(GroupAnnouncementImage.serializer()).check().toPublic()
     }
 
@@ -194,7 +195,7 @@ internal object AnnouncementProtocol {
         announcement: GroupAnnouncement,
         image: AnnouncementImage?,
     ): String {
-        return Mirai.Http.post<String> {
+        return bot.components[HttpClientProvider].getHttpClient().post {
             url(
                 "https://web.qun.qq.com/cgi-bin/announce/add_qun_" + if (announcement.type == 20) {
                     "instruction"
@@ -202,28 +203,30 @@ internal object AnnouncementProtocol {
                     "notice"
                 }
             )
-            body = MultiPartFormDataContent(formData {
-                append("qid", groupId)
-                append("bkn", client.wLoginSigInfo.bkn)
-                append("text", announcement.msg.text)
-                append("pinned", announcement.pinned)
-                image?.let {
-                    append("pic", image.id)
-                    append("imgWidth", image.width)
-                    append("imgHeight", image.height)
-                }
-                append(
-                    "settings",
-                    announcement.settings.toJsonString(GroupAnnouncementSettings.serializer()),
-                )
-                append("format", "json")
-                // append("type", announcement.type.toString())
-            })
+            setBody(
+                MultiPartFormDataContent(formData {
+                    append("qid", groupId)
+                    append("bkn", client.wLoginSigInfo.bkn)
+                    append("text", announcement.msg.text)
+                    append("pinned", announcement.pinned)
+                    image?.let {
+                        append("pic", image.id)
+                        append("imgWidth", image.width)
+                        append("imgHeight", image.height)
+                    }
+                    append(
+                        "settings",
+                        announcement.settings.toJsonString(GroupAnnouncementSettings.serializer()),
+                    )
+                    append("format", "json")
+                    // append("type", announcement.type.toString())
+                })
+            )
             cookie("uin", "o$id")
             cookie("p_uin", "o$id")
             cookie("skey", sKey)
             cookie("p_skey", psKey("qun.qq.com"))
-        }.loadSafelyAs(SendGroupAnnouncementResp.serializer()).check().fid
+        }.bodyAsText().loadSafelyAs(SendGroupAnnouncementResp.serializer()).check().fid
     }
 
     suspend fun QQAndroidBot.getRawGroupAnnouncements(
@@ -231,20 +234,22 @@ internal object AnnouncementProtocol {
         page: Int,
         amount: Int = 10
     ): Either<DeserializationFailure, GroupAnnouncementList> {
-        return Mirai.Http.post<String> {
+        return bot.components[HttpClientProvider].getHttpClient().post {
             url("https://web.qun.qq.com/cgi-bin/announce/list_announce")
-            body = MultiPartFormDataContent(formData {
-                append("qid", groupId)
-                append("bkn", client.wLoginSigInfo.bkn)
-                append("ft", 23)  //好像是一个用来识别应用的参数
-                append("s", if (page == 1) 0 else -(page * amount + 1))  // 第一页这里的参数应该是-1
-                append("n", amount)
-                append("ni", if (page == 1) 1 else 0)
-                append("format", "json")
-            })
+            setBody(
+                MultiPartFormDataContent(formData {
+                    append("qid", groupId)
+                    append("bkn", client.wLoginSigInfo.bkn)
+                    append("ft", 23)  //好像是一个用来识别应用的参数
+                    append("s", if (page == 1) 0 else -(page * amount + 1))  // 第一页这里的参数应该是-1
+                    append("n", amount)
+                    append("ni", if (page == 1) 1 else 0)
+                    append("format", "json")
+                })
+            )
             cookie("uin", "o$id")
             cookie("skey", sKey)
-        }.loadSafelyAs(GroupAnnouncementList.serializer())
+        }.bodyAsText().loadSafelyAs(GroupAnnouncementList.serializer())
     }
 
     @Serializable
@@ -254,25 +259,25 @@ internal object AnnouncementProtocol {
     ) : CheckableResponseA(), JsonStruct
 
     suspend fun QQAndroidBot.deleteGroupAnnouncement(groupId: Long, fid: String): Boolean {
-        Mirai.Http.post<String> {
+        components[HttpClientProvider].getHttpClient().post {
             url("https://web.qun.qq.com/cgi-bin/announce/del_feed")
-            body = feedBody(groupId, fid)
+            setBody(feedBody(groupId, fid))
             cookie("uin", "o$id")
             cookie("p_uin", "o$id")
             cookie("skey", sKey)
             cookie("p_skey", psKey("qun.qq.com"))
-        }.loadSafelyAs(DeleteResp.serializer()).check()
+        }.bodyAsText().loadSafelyAs(DeleteResp.serializer()).check()
         return true
     }
 
     suspend fun QQAndroidBot.getGroupAnnouncement(groupId: Long, fid: String): GroupAnnouncement {
-        return Mirai.Http.post<String> {
+        return bot.components[HttpClientProvider].getHttpClient().post {
             url("https://web.qun.qq.com/cgi-bin/announce/get_feed")
-            body = feedBody(groupId, fid)
+            setBody(feedBody(groupId, fid))
             cookie("uin", "o$id")
             cookie("p_uin", "o$id")
             cookie("skey", sKey)
-        }.loadAs(GroupAnnouncement.serializer())
+        }.bodyAsText().loadAs(GroupAnnouncement.serializer())
     }
 
     private fun QQAndroidBot.feedBody(
diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/RichMessageProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/RichMessageProtocol.kt
index c24450715..7ac4ea657 100644
--- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/RichMessageProtocol.kt
+++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/RichMessageProtocol.kt
@@ -140,7 +140,7 @@ internal class RichMessageProtocol : MessageProtocol() {
                 { "resId=" + lightApp.msgResid + "data=" + lightApp.data.toUHexString() }) {
                 when (lightApp.data[0].toInt()) {
                     0 -> lightApp.data.decodeToString(startIndex = 1)
-                    1 -> lightApp.data.toReadPacket(offset = 1).inflateInput().readText()
+                    1 -> lightApp.data.toReadPacket(offset = 1).inflateInput().readAllText()
                     else -> error("unknown compression flag=${lightApp.data[0]}")
                 }
             }
@@ -159,7 +159,7 @@ internal class RichMessageProtocol : MessageProtocol() {
             val content = runWithBugReport("解析 richMsg", { richMsg.template1.toUHexString() }) {
                 when (richMsg.template1[0].toInt()) {
                     0 -> richMsg.template1.decodeToString(startIndex = 1)
-                    1 -> richMsg.template1.toReadPacket(offset = 1).inflateInput().readText()
+                    1 -> richMsg.template1.toReadPacket(offset = 1).inflateInput().readAllText()
                     else -> error("unknown compression flag=${richMsg.template1[0]}")
                 }
             }
diff --git a/mirai-core/src/commonMain/kotlin/network/components/EcdhInitialPublicKeyUpdater.kt b/mirai-core/src/commonMain/kotlin/network/components/EcdhInitialPublicKeyUpdater.kt
index 3a19ddd66..cea70d255 100644
--- a/mirai-core/src/commonMain/kotlin/network/components/EcdhInitialPublicKeyUpdater.kt
+++ b/mirai-core/src/commonMain/kotlin/network/components/EcdhInitialPublicKeyUpdater.kt
@@ -10,11 +10,11 @@
 package net.mamoe.mirai.internal.network.components
 
 import io.ktor.client.request.*
+import io.ktor.client.statement.*
 import kotlinx.coroutines.withTimeout
 import kotlinx.serialization.SerialName
 import kotlinx.serialization.Serializable
 import kotlinx.serialization.json.Json
-import net.mamoe.mirai.Mirai
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.network.component.ComponentKey
 import net.mamoe.mirai.internal.utils.crypto.ECDH
@@ -89,8 +89,11 @@ internal class EcdhInitialPublicKeyUpdaterImpl(
             } else {
                 logger.info("ECDH key is invalid, start to fetch ecdh public key from server.")
                 val respStr =
-                    @Suppress("DEPRECATION", "DEPRECATION_ERROR")
-                    withTimeout(10.seconds) { Mirai.Http.get<String>("https://keyrotate.qq.com/rotate_key?cipher_suite_ver=305&uin=${bot.client.uin}") }
+                    withTimeout(10.seconds) {
+                        bot.components[HttpClientProvider].getHttpClient()
+                            .get("https://keyrotate.qq.com/rotate_key?cipher_suite_ver=305&uin=${bot.client.uin}")
+                            .bodyAsText()
+                    }
                 val resp = json.decodeFromString(ServerRespPOJO.serializer(), respStr)
                 resp.pubKeyMeta.let { meta ->
                     val isValid = ECDH.verifyPublicKey(
diff --git a/mirai-core/src/commonMain/kotlin/network/components/HttpClientProvider.kt b/mirai-core/src/commonMain/kotlin/network/components/HttpClientProvider.kt
new file mode 100644
index 000000000..33119f2a9
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/components/HttpClientProvider.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+package net.mamoe.mirai.internal.network.components
+
+import io.ktor.client.*
+import net.mamoe.mirai.internal.createDefaultHttpClient
+import net.mamoe.mirai.internal.network.component.ComponentKey
+
+internal interface HttpClientProvider {
+    fun getHttpClient(): HttpClient
+
+    companion object : ComponentKey<HttpClientProvider>
+}
+
+internal class HttpClientProviderImpl : HttpClientProvider {
+    private val instance by lazy { createDefaultHttpClient() }
+    override fun getHttpClient(): HttpClient = instance
+}
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/highway/Http.kt b/mirai-core/src/commonMain/kotlin/network/highway/Http.kt
index 3e9f99bf1..3f46f562a 100644
--- a/mirai-core/src/commonMain/kotlin/network/highway/Http.kt
+++ b/mirai-core/src/commonMain/kotlin/network/highway/Http.kt
@@ -49,7 +49,7 @@ internal suspend fun HttpClient.postImage(
     groupcode: Long?,
     imageInput: ExternalResource,
     uKeyHex: String,
-): Boolean = post<HttpStatusCode> {
+): Boolean = post {
     url {
         protocol = URLProtocol.HTTP
         host = serverIp // "htdata2.qq.com"
@@ -71,7 +71,7 @@ internal suspend fun HttpClient.postImage(
     }
 
     body = imageInput.consumeAsWriteChannelContent(ContentType.Image.Any)
-} == HttpStatusCode.OK
+}.status == HttpStatusCode.OK
 
 internal suspend fun HttpClient.postPtt(
     serverIp: String,
@@ -80,7 +80,7 @@ internal suspend fun HttpClient.postPtt(
     uKey: ByteArray,
     fileKey: ByteArray,
 ) {
-    post<String> {
+    post {
         url("http://$serverIp:$serverPort")
         parameter("ver", 4679)
         parameter("ukey", uKey.toUHexString(""))
@@ -89,6 +89,6 @@ internal suspend fun HttpClient.postPtt(
         parameter("bmd5", resource.md5.toUHexString(""))
         parameter("mType", "pttDu")
         parameter("voice_encodec", resource.voiceCodec)
-        body = resource.consumeAsWriteChannelContent(null)
+        setBody(resource.consumeAsWriteChannelContent(null))
     }
 }
diff --git a/mirai-core/src/commonMain/kotlin/utils/io/serialization/tars/internal/TarsOld.kt b/mirai-core/src/commonMain/kotlin/utils/io/serialization/tars/internal/TarsOld.kt
index b0cfd8595..ed14bb84a 100644
--- a/mirai-core/src/commonMain/kotlin/utils/io/serialization/tars/internal/TarsOld.kt
+++ b/mirai-core/src/commonMain/kotlin/utils/io/serialization/tars/internal/TarsOld.kt
@@ -97,7 +97,6 @@ internal class TarsOld internal constructor(
      * From: com.qq.taf.Tars.TarsOutputStream
      */
     @Suppress("unused", "MemberVisibilityCanBePrivate")
-    @OptIn(ExperimentalIoApi::class)
     private open inner class TarsEncoder(
         val output: BytePacketBuilder,
     ) : TaggedEncoder<Int>() {
diff --git a/mirai-core/src/commonMain/kotlin/utils/io/serialization/utils.kt b/mirai-core/src/commonMain/kotlin/utils/io/serialization/utils.kt
index 5cbca9643..2004dac3a 100644
--- a/mirai-core/src/commonMain/kotlin/utils/io/serialization/utils.kt
+++ b/mirai-core/src/commonMain/kotlin/utils/io/serialization/utils.kt
@@ -95,7 +95,7 @@ private fun <T : JceStruct> ByteArray.doLoadAs(
             } catch (secondFailure: Exception) {
                 throw contextualBugReportException(
                     "解析 " + deserializer.descriptor.serialName,
-                    build.readText(),
+                    build.readAllText(),
                     ExceptionCollector.compressExceptions(originalException, secondFailure)
                 )
             }
diff --git a/mirai-core/src/commonTest/kotlin/message/ImageReadingTest.kt b/mirai-core/src/commonTest/kotlin/message/ImageReadingTest.kt
index 99ac63c0f..a6459e100 100644
--- a/mirai-core/src/commonTest/kotlin/message/ImageReadingTest.kt
+++ b/mirai-core/src/commonTest/kotlin/message/ImageReadingTest.kt
@@ -9,6 +9,7 @@
 
 package net.mamoe.mirai.internal.message
 
+import io.ktor.utils.io.core.EOFException
 import io.ktor.utils.io.errors.*
 import net.mamoe.mirai.internal.message.image.calculateImageInfo
 import net.mamoe.mirai.internal.test.AbstractTest
@@ -78,7 +79,7 @@ internal class ImageReadingTest : AbstractTest() {
                 ImageType.JPG
             )
         }
-        assertFailsWith(IllegalStateException::class) {
+        assertFailsWith(EOFException::class) {
             "FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 78 00 78 00 00 FF E1 00 5A".testMatch(
                 ImageType.JPG
             )
diff --git a/mirai-core/src/commonTest/kotlin/network/framework/AbstractMockNetworkHandlerTest.kt b/mirai-core/src/commonTest/kotlin/network/framework/AbstractMockNetworkHandlerTest.kt
index 3bccfaa34..e1122caf7 100644
--- a/mirai-core/src/commonTest/kotlin/network/framework/AbstractMockNetworkHandlerTest.kt
+++ b/mirai-core/src/commonTest/kotlin/network/framework/AbstractMockNetworkHandlerTest.kt
@@ -76,6 +76,7 @@ internal abstract class AbstractMockNetworkHandlerTest : AbstractNetworkHandlerT
         set(ImagePatcher, TestImagePatcher())
         set(PacketLoggingStrategy, PacketLoggingStrategyImpl(bot))
         set(AccountSecretsManager, MemoryAccountSecretsManager())
+        set(HttpClientProvider, HttpClientProviderImpl())
     }
 
     fun NetworkHandler.assertState(state: NetworkHandler.State) {
diff --git a/mirai-core/src/darwinMain/kotlin/MiraiImpl.kt b/mirai-core/src/darwinMain/kotlin/MiraiImpl.kt
index e55c4c34d..07f8cd43a 100644
--- a/mirai-core/src/darwinMain/kotlin/MiraiImpl.kt
+++ b/mirai-core/src/darwinMain/kotlin/MiraiImpl.kt
@@ -10,11 +10,11 @@
 package net.mamoe.mirai.internal
 
 import io.ktor.client.*
-import io.ktor.client.engine.ios.*
-import io.ktor.client.features.*
+import io.ktor.client.engine.darwin.*
+import io.ktor.client.plugins.*
 
 internal actual fun createDefaultHttpClient(): HttpClient {
-    return HttpClient(Ios) {
+    return HttpClient(Darwin) {
         install(HttpTimeout) {
             this.requestTimeoutMillis = 30_0000
             this.connectTimeoutMillis = 30_0000
diff --git a/mirai-core/src/jvmBaseMain/kotlin/MiraiImpl.kt b/mirai-core/src/jvmBaseMain/kotlin/MiraiImpl.kt
index f46c0686b..2679e62d6 100644
--- a/mirai-core/src/jvmBaseMain/kotlin/MiraiImpl.kt
+++ b/mirai-core/src/jvmBaseMain/kotlin/MiraiImpl.kt
@@ -13,7 +13,7 @@ package net.mamoe.mirai.internal
 
 import io.ktor.client.*
 import io.ktor.client.engine.okhttp.*
-import io.ktor.client.features.*
+import io.ktor.client.plugins.*
 import kotlinx.atomicfu.atomic
 import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
 
diff --git a/mirai-core/src/linuxX64Main/kotlin/MiraiImpl.kt b/mirai-core/src/linuxX64Main/kotlin/MiraiImpl.kt
index 16390e369..841be8763 100644
--- a/mirai-core/src/linuxX64Main/kotlin/MiraiImpl.kt
+++ b/mirai-core/src/linuxX64Main/kotlin/MiraiImpl.kt
@@ -10,11 +10,11 @@
 package net.mamoe.mirai.internal
 
 import io.ktor.client.*
-import io.ktor.client.engine.curl.*
-import io.ktor.client.features.*
+import io.ktor.client.engine.cio.*
+import io.ktor.client.plugins.*
 
 internal actual fun createDefaultHttpClient(): HttpClient {
-    return HttpClient(Curl) {
+    return HttpClient(CIO) {
         install(HttpTimeout) {
             this.requestTimeoutMillis = 30_0000
             this.connectTimeoutMillis = 30_0000
diff --git a/mirai-core/src/mingwX64Main/kotlin/MiraiImpl.kt b/mirai-core/src/mingwX64Main/kotlin/MiraiImpl.kt
index 16390e369..62a9aa7db 100644
--- a/mirai-core/src/mingwX64Main/kotlin/MiraiImpl.kt
+++ b/mirai-core/src/mingwX64Main/kotlin/MiraiImpl.kt
@@ -11,7 +11,7 @@ package net.mamoe.mirai.internal
 
 import io.ktor.client.*
 import io.ktor.client.engine.curl.*
-import io.ktor.client.features.*
+import io.ktor.client.plugins.*
 
 internal actual fun createDefaultHttpClient(): HttpClient {
     return HttpClient(Curl) {
diff --git a/mirai-core/src/mingwX64Main/kotlin/utils/PlatformSocket.kt b/mirai-core/src/mingwX64Main/kotlin/utils/PlatformSocket.kt
index 58542abdb..34873f035 100644
--- a/mirai-core/src/mingwX64Main/kotlin/utils/PlatformSocket.kt
+++ b/mirai-core/src/mingwX64Main/kotlin/utils/PlatformSocket.kt
@@ -45,14 +45,12 @@ internal actual class PlatformSocket(
     actual val isOpen: Boolean
         get() = write(socket, null, 0) != 0
 
-    @OptIn(ExperimentalIoApi::class)
     actual override fun close() {
         if (close(socket) != 0) {
             throw PosixException.forErrno(posixFunctionName = "close()").wrapIO()
         }
     }
 
-    @OptIn(ExperimentalIoApi::class)
     actual suspend fun send(packet: ByteArray, offset: Int, length: Int): Unit = readLock.withLock {
         withContext(dispatcher) {
             require(offset >= 0) { "offset must >= 0" }
@@ -66,10 +64,7 @@ internal actual class PlatformSocket(
         }
     }
 
-    /**
-     * @throws SendPacketInternalException
-     */
-    @OptIn(ExperimentalIoApi::class)
+
     actual override suspend fun send(packet: ByteReadPacket): Unit = readLock.withLock {
         withContext(dispatcher) {
             val writeBuffer = writeBuffer
@@ -93,7 +88,6 @@ internal actual class PlatformSocket(
 
     actual companion object {
 
-        @OptIn(UnsafeNumber::class, ExperimentalIoApi::class)
         actual suspend fun connect(
             serverIp: String,
             serverPort: Int
diff --git a/mirai-core/src/nativeMain/kotlin/network/handler/LengthDelimitedPacketReader.kt b/mirai-core/src/nativeMain/kotlin/network/handler/LengthDelimitedPacketReader.kt
index ca1fa3ba3..73b35c5ea 100644
--- a/mirai-core/src/nativeMain/kotlin/network/handler/LengthDelimitedPacketReader.kt
+++ b/mirai-core/src/nativeMain/kotlin/network/handler/LengthDelimitedPacketReader.kt
@@ -79,7 +79,7 @@ internal class LengthDelimitedPacketReader(
             else -> {
                 if (missingLength == 0L) {
                     debugLogger.info { "Multiple packets length perfectly matched." }
-                    sendDecode(buildPacket(bufferedParts.sumOf { it.remaining }.toInt()) {
+                    sendDecode(buildPacket {
                         bufferedParts.forEach { writePacket(it) }
                     })
 
@@ -95,7 +95,7 @@ internal class LengthDelimitedPacketReader(
 
                     if (combinedLength < 0) return // not enough, still more parts missing.
 
-                    sendDecode(buildPacket(combinedLength) {
+                    sendDecode(buildPacket {
                         repeat(bufferedParts.size - 1) { i ->
                             writePacket(bufferedParts[i])
                         }
diff --git a/mirai-core/src/unixMain/kotlin/utils/PlatformSocket.kt b/mirai-core/src/unixMain/kotlin/utils/PlatformSocket.kt
index 8cd91578c..aaa6bfba1 100644
--- a/mirai-core/src/unixMain/kotlin/utils/PlatformSocket.kt
+++ b/mirai-core/src/unixMain/kotlin/utils/PlatformSocket.kt
@@ -55,7 +55,6 @@ internal actual class PlatformSocket(
         writeBuffer.unpin()
     }
 
-    @OptIn(ExperimentalIoApi::class)
     actual suspend fun send(packet: ByteArray, offset: Int, length: Int): Unit = writeLock.withLock {
         withContext(sendDispatcher) {
             require(offset >= 0) { "offset must >= 0" }
@@ -72,7 +71,6 @@ internal actual class PlatformSocket(
     /**
      * @throws SendPacketInternalException
      */
-    @OptIn(ExperimentalIoApi::class)
     actual override suspend fun send(packet: ByteReadPacket): Unit = writeLock.withLock {
         withContext(sendDispatcher) {
             logger.info { "Native socket sending: len=${packet.remaining}" }