1
+ package com.lagradost.cloudstream3.network
2
+
3
+ import android.util.Log
4
+ import okhttp3.Credentials
5
+ import okhttp3.Interceptor
6
+ import okhttp3.OkHttpClient
7
+ import okhttp3.Response
8
+ import java.io.IOException
9
+ import java.net.ConnectException
10
+ import java.net.InetSocketAddress
11
+ import java.net.Proxy
12
+ import java.net.SocketTimeoutException
13
+ import java.util.concurrent.TimeUnit
14
+
15
+ class ProxyInterceptor (
16
+ private val host : String ,
17
+ private val port : Int ,
18
+ private val proxyType : Proxy .Type = Proxy .Type .HTTP ,
19
+ private val username : String? = null ,
20
+ private val password : String? = null ,
21
+ private val allowFallback : Boolean = false ,
22
+ private val connectTimeoutSeconds : Long = 15L ,
23
+ private val readTimeoutSeconds : Long = 15L
24
+ ) : Interceptor {
25
+
26
+ companion object {
27
+ private const val TAG = " ProxyDebug"
28
+ }
29
+
30
+ init {
31
+ Log .d(
32
+ TAG ,
33
+ " proxy setup: " + listOf (
34
+ " host=$host " ,
35
+ " port=$port " ,
36
+ " type=${proxyType.name} " ,
37
+ " timeouts=${connectTimeoutSeconds} s/${readTimeoutSeconds} s" ,
38
+ " auth=${if (username != null ) " enabled" else " None" } " ,
39
+ " fallback=${if (allowFallback) " Allowed" else " Disabled" } "
40
+ ).joinToString(separator = " , " ) // Join only the parameters
41
+ )
42
+ }
43
+
44
+ private val proxyClient by lazy {
45
+ Log .d(TAG , " Building proxy client for $host :$port " )
46
+
47
+ val proxy = Proxy (proxyType, InetSocketAddress (host, port))
48
+ OkHttpClient .Builder ()
49
+ .proxy(proxy)
50
+ .connectTimeout(connectTimeoutSeconds, TimeUnit .SECONDS )
51
+ .readTimeout(readTimeoutSeconds, TimeUnit .SECONDS )
52
+ .apply {
53
+ if (username != null && password != null ) {
54
+ Log .d(TAG , " Configuring proxy credentials" )
55
+ proxyAuthenticator { _, response ->
56
+ Log .d(TAG , " Authenticating proxy for ${response.request.url} " )
57
+ response.request.newBuilder()
58
+ .header(" Proxy-Authorization" , Credentials .basic(username, password))
59
+ .build()
60
+ }
61
+ }
62
+ }
63
+ .build()
64
+ }
65
+
66
+ override fun intercept (chain : Interceptor .Chain ): Response {
67
+ Log .d(TAG , " Intercepting request to ${chain.request().url.host} " )
68
+
69
+ return try {
70
+ val response = proxyClient.newCall(chain.request()).execute()
71
+
72
+ Log .d(
73
+ TAG ,
74
+ " proxy response:" + listOf (
75
+ " url=${response.request.url} " ,
76
+ " status=${response.code} " ,
77
+ " headers=${response.headers.size} " ,
78
+ " body=${response.body?.contentLength() ? : 0 } bytes"
79
+ ).joinToString(separator = " , " )
80
+ )
81
+
82
+ when {
83
+ response.code == 407 -> handleProxyAuthenticationError(chain, response)
84
+ ! response.isSuccessful -> throw IOException (" HTTP ${response.code} " )
85
+ else -> response
86
+ }
87
+ } catch (e: IOException ) {
88
+ Log .d(
89
+ TAG ,
90
+ " proxy error:" + listOf (
91
+ " type=${e.javaClass.simpleName} " ,
92
+ " message=${e.message} " ,
93
+ " request=${chain.request().url} "
94
+ ).joinToString(separator = " , " )
95
+ )
96
+ handleProxyError(e, chain)
97
+ }
98
+ }
99
+
100
+ private fun handleProxyAuthenticationError (
101
+ chain : Interceptor .Chain ,
102
+ response : Response
103
+ ): Response {
104
+ response.close()
105
+ Log .d(TAG , " Proxy authentication failed for $host :$port " )
106
+ return if (allowFallback) {
107
+ Log .d(TAG , " Attempting fallback connection" )
108
+ fallback(chain)
109
+ } else {
110
+ throw IOException (" Proxy authentication required" )
111
+ }
112
+ }
113
+
114
+ private fun handleProxyError (e : IOException , chain : Interceptor .Chain ): Response {
115
+ return when (e) {
116
+ is ConnectException -> {
117
+ Log .d(TAG , " Connection refused to proxy $host :$port " )
118
+ if (allowFallback) fallback(chain) else throw e
119
+ }
120
+
121
+ is SocketTimeoutException -> {
122
+ Log .d(TAG , " Timeout connecting to proxy (${connectTimeoutSeconds} s)" )
123
+ if (allowFallback) fallback(chain) else throw e
124
+ }
125
+
126
+ else -> {
127
+ Log .d(TAG , " Unexpected proxy error: ${e.javaClass.simpleName} " )
128
+ throw e
129
+ }
130
+ }
131
+ }
132
+
133
+ private fun fallback (chain : Interceptor .Chain ): Response {
134
+ Log .d(TAG , " Using direct connection to ${chain.request().url.host} " )
135
+ return chain.proceed(chain.request()).also { response ->
136
+ Log .d(
137
+ TAG ,
138
+ " direct connection: " + listOf (
139
+ " status=${response.code} " ,
140
+ " via=${response.handshake?.tlsVersion ? : " Plaintext" } " ,
141
+ " server=${response.header(" Server" ) ? : " Unknown" } "
142
+ ).joinToString(separator = " , " )
143
+ )
144
+ }
145
+ }
146
+ }
0 commit comments