HTTPS 代理服务器超时

问题描述 投票:0回答:1

我正在尝试在 Kotlin(适用于 Android)中实现 HTTP/HTTPS 代理服务器,对于 HTTP,它按预期工作,但对于 HTTPS 请求,它始终会得到

 The connection has timed out

与服务器的客户端连接已建立,但我在实现中没有抛出任何错误,这是代理服务器的完整代码:


interface ProxyPortListener {
    fun setProxyPort(port: Int)
}

class ProxyServer(private val context: Context) : Thread() {

    var countOfConnectionsDone = 0

    companion object {
        private const val TAG = "ProxyServer"
        private const val CONNECT = "CONNECT"
        private const val HTTP_OK = "HTTP/1.1 200 OK\r\n"
        private const val HEADER_CONNECTION = "connection"
        private const val HEADER_PROXY_CONNECTION = "proxy-connection"
    }

    private val threadExecutor: ExecutorService = Executors.newCachedThreadPool()
    var isRunning: Boolean = false
        private set

    private var serverSocket: ServerSocket? = null
    private var port: Int = -1
    private var callback: ProxyPortListener? = null

    init {
        startServer()
    }

    fun setCallback(callback: ProxyPortListener) {
        this.callback = callback
        if (port != -1) {
            callback.setProxyPort(port)
        }
    }

    override fun run() {
        try {
            serverSocket =
                ServerSocket(Prefs.getProxyPort(context), 0, InetAddress.getByName("0.0.0.0"))
            port = serverSocket!!.localPort
            callback?.setProxyPort(port)
            isRunning = true
            Log.d(TAG, "Proxy server started on port $port")
            while (isRunning) {
                try {
                    val socket = serverSocket!!.accept()
                    Log.d(TAG, "Accepted connection from ${socket.inetAddress}")
                    val proxyConnection = ProxyConnection(socket)
                    threadExecutor.execute(proxyConnection)
                } catch (e: SocketException) {
                    Log.e(TAG, "Socket exception while running server", e)
                }
            }
        } catch (e: IOException) {
            Log.e(TAG, "Failed to start proxy server", e)
        }
    }

    fun startServer() {
        if (!isRunning && state == Thread.State.NEW) {
            start()
        }
    }

    fun stopServer() {
        isRunning = false
        serverSocket?.close()
        serverSocket = null
        try {
            join() // Wait for the thread to finish executing
        } catch (e: InterruptedException) {
            Log.e(TAG, "Failed to stop proxy server", e)
        }
    }



    private inner class ProxyConnection(private val connection: Socket) : Runnable {
        override fun run() {
            try {
                val requestLine = getLine(connection.getInputStream())
                val splitLine = requestLine.split(" ")
                if (splitLine.size < 3) {
                    connection.close()
                    return
                }

                val requestType = splitLine[0]
                var urlString = splitLine[1]
                val httpVersion = splitLine[2]

                val url: URI
                val host: String
                val port: Int
                var server: Socket? = null

                if (requestType == CONNECT) {
                    // Handle HTTPS connections using CONNECT method
                    val parts = urlString.split(":")
                    host = parts[0]
                    port = if (parts.size > 1) parts[1].toInt() else 443
                    try {
                        server = Socket(host, port)
                        sendLine(connection, HTTP_OK)
                        SocketConnect.connect(connection, server)
                    } catch (e: IOException) {
                        Log.e(TAG, "Error handling CONNECT request", e)
                        connection.close()
                    }
                    return
                } else {
                    // Handle HTTP connections
                    try {
                        url = URI(urlString)
                        host = url.host
                        port = if (url.port < 0) 80 else url.port
                    } catch (e: URISyntaxException) {
                        connection.close()
                        return
                    }
                }

                // Create socket based on proxy configuration
                val proxy = ProxySelector.getDefault().select(URI(urlString)).firstOrNull()
                if (proxy != Proxy.NO_PROXY) {
                    val inetSocketAddress = proxy?.address() as InetSocketAddress
                    server = Socket(inetSocketAddress.hostName, inetSocketAddress.port)
                } else {
                    server = Socket(host, port)
                }

                // Forward request and response
                sendAugmentedRequestToHost(connection, server, requestType, url, httpVersion)
                SocketConnect.connect(connection, server)
            } catch (e: Exception) {
                Log.d(TAG, "Problem Proxying", e)
            } finally {
                try {
                    connection.close()
                } catch (ioe: IOException) {
                    Log.e(TAG, "Error closing connection", ioe)
                }
            }
        }

        private fun sendAugmentedRequestToHost(
            src: Socket,
            dst: Socket,
            httpMethod: String,
            uri: URI,
            httpVersion: String
        ) {
            sendRequestLineWithPath(dst, httpMethod, uri, httpVersion)
            filterAndForwardRequestHeaders(src, dst)
            sendLine(dst, "Connection: close")
            sendLine(dst, "")
        }

        private fun sendRequestLineWithPath(
            server: Socket,
            requestType: String,
            absoluteUri: URI,
            httpVersion: String
        ) {
            val absolutePath = getAbsolutePathFromAbsoluteURI(absoluteUri)
            val outgoingRequestLine = "$requestType $absolutePath $httpVersion"
            sendLine(server, outgoingRequestLine)
        }

        private fun getAbsolutePathFromAbsoluteURI(uri: URI): String {
            val rawPath = uri.rawPath ?: "/"
            val rawQuery = uri.rawQuery?.let { "?$it" } ?: ""
            val rawFragment = uri.rawFragment?.let { "#$it" } ?: ""
            return "$rawPath$rawQuery$rawFragment"
        }

        private fun getLine(inputStream: InputStream): String {
            val buffer = StringBuilder()
            var byteBuffer = inputStream.read()
            if (byteBuffer < 0) return ""
            while (byteBuffer != '\n'.code && byteBuffer >= 0) {
                if (byteBuffer != '\r'.code) {
                    buffer.append(byteBuffer.toChar())
                }
                byteBuffer = inputStream.read()
            }
            return buffer.toString()
        }

        private fun sendLine(socket: Socket, line: String) {
            try {
                if (!socket.isClosed) {
                    val os = socket.getOutputStream()
                    os.write(line.toByteArray())
                    os.write('\r'.code)
                    os.write('\n'.code)
                    os.flush()
                } else {
                    Log.e(TAG, "Cannot write to closed socket")
                }
            } catch (e: IOException) {
                Log.e(TAG, "Error while writing to socket: ${e.message}")
            }
        }

        private fun filterAndForwardRequestHeaders(src: Socket, dst: Socket) {
            var line: String
            do {
                line = getLine(src.getInputStream())
                if (line.isNotEmpty() && !shouldRemoveHeaderLine(line)) {
                    sendLine(dst, line)
                }
            } while (line.isNotEmpty())
        }

        private fun shouldRemoveHeaderLine(line: String): Boolean {
            val colIndex = line.indexOf(":")
            if (colIndex != -1) {
                val headerName = line.substring(0, colIndex).trim()
                if (headerName.equals(HEADER_CONNECTION, ignoreCase = true)
                    || headerName.equals(HEADER_PROXY_CONNECTION, ignoreCase = true)
                ) {
                    return true
                }
            }
            return false
        }
    }

    class SocketConnect(private val from: Socket, private val to: Socket) : Thread() {
        private val buffer = ByteArray(512)

        override fun run() {
            val inputStream = from.getInputStream()
            val outputStream = to.getOutputStream()
            try {
                var bytesRead: Int
                while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                    outputStream.write(buffer, 0, bytesRead)
                }
            } catch (ioe: IOException) {
                // Do nothing
            }
        }

        companion object {
            fun connect(first: Socket, second: Socket) {
                val sc1 = SocketConnect(first, second)
                val sc2 = SocketConnect(second, first)
                sc1.start()
                sc2.start()
                try {
                    sc1.join()
                    sc2.join()
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }
            }
        }
    }
}

这个超时错误可能是什么原因?

android kotlin sockets proxy
1个回答
0
投票

因此我创建了一个函数,可以在 CONNET 中传输数据(HTTPS 情况):

   @Throws(IOException::class)
        private fun skipToRequestBody(socket: Socket) {
            while (getLine(socket.getInputStream()).isNotEmpty())
        }

这里是调整后的运行函数:

override fun run() {
            try {
                countOfConnectionsDone = NetworkUtils.checkIfCountExceeded(countOfConnectionsDone, context)
                val requestLine = getLine(connection.getInputStream())
                val splitLine = requestLine.split(" ")
                if (splitLine.size < 3) {
                    connection.close()
                    return
                }

                val requestType = splitLine[0]
                var urlString = splitLine[1]
                val httpVersion = splitLine[2]

                val url: URI
                val host: String
                val port: Int
                var server: Socket? = null

                if (requestType == CONNECT) {
                    val hostPortSplit: List<String> = urlString.split(":")
                    host = hostPortSplit[0]

                    // Use default SSL port if not specified. Parse it otherwise
                    port = if (hostPortSplit.size < 2) {
                        443
                    } else {
                        try {
                            hostPortSplit[1].toInt()
                        } catch (nfe: NumberFormatException) {
                            connection.close()
                            return
                        }
                    }
                    urlString = "Https://" + attr.host + ":" + port
                } else {
                    // Handle HTTP connections
                    try {
                        url = URI(urlString)
                        host = url.host
                        port = if (url.port < 0) 80 else url.port
                    } catch (e: URISyntaxException) {
                        connection.close()
                        return
                    }
                }

                // Create socket based on proxy configuration
                val proxy = ProxySelector.getDefault().select(URI(urlString)).firstOrNull()
                if (proxy != Proxy.NO_PROXY) {
                    val inetSocketAddress = proxy?.address() as InetSocketAddress
                    server = Socket(inetSocketAddress.hostName, inetSocketAddress.port)
                } else {
                    server = Socket(host, port)
                }

                // Forward request and response
                if (requestType == CONNECT) {
                    skipToRequestBody(connection);
                    // No proxy to respond so we must.
                    sendLine(connection, HTTP_OK);
                } else {
                    sendAugmentedRequestToHost(connection, server, requestType, URI(urlString), httpVersion)
                }
                SocketConnect.connect(connection, server)
            } catch (e: Exception) {
                Log.d(TAG, "Problem Proxying", e)
            } finally {
                try {
                    connection.close()
                } catch (ioe: IOException) {
                    Log.e(TAG, "Error closing connection", ioe)
                }
            }
        }
© www.soinside.com 2019 - 2024. All rights reserved.