@@ -15,12 +15,11 @@ import de.robv.android.xposed.XposedHelpers
1515import java.io.ByteArrayInputStream
1616import java.io.ByteArrayOutputStream
1717import java.io.IOException
18- import java.net.ProtocolException
1918import java.io.InputStream
20- import java.lang.reflect.Field
21- import java.net.HttpURLConnection
2219import java.net.InetAddress
23- import java.net.URL
20+ import java.net.ProtocolException
21+ import java.net.UnknownHostException
22+ import java.lang.reflect.Field
2423import java.nio.ByteBuffer
2524import java.util.UUID
2625import java.util.concurrent.ConcurrentHashMap
@@ -137,7 +136,7 @@ internal object RequestHookHandler {
137136 " after"
138137 ) { param ->
139138 if (RequestHook .processDnsRequest(param.args[0 ], param.result)) {
140- param.result = null
139+ param.throwable = UnknownHostException ( " Blocked by AdClose: ${param.args[ 0 ]} " )
141140 }
142141 }
143142 HookUtil .findAndHookMethod(
@@ -147,7 +146,7 @@ internal object RequestHookHandler {
147146 " after"
148147 ) { param ->
149148 if (RequestHook .processDnsRequest(param.args[0 ], param.result)) {
150- param.result = emptyArray< InetAddress >( )
149+ param.throwable = UnknownHostException ( " Blocked by AdClose: ${param.args[ 0 ]} " )
151150 }
152151 }
153152 }
@@ -164,14 +163,15 @@ internal object RequestHookHandler {
164163 }
165164
166165 val socket = XposedHelpers .getObjectField(param.thisObject, " socket" )
166+ ? : return @hookAllMethods
167167 if (socket is SSLSocket ) return @hookAllMethods
168168
169169 val bytes = param.args[1 ] as ByteArray
170170 val offset = param.args[2 ] as Int
171171 val len = param.args[3 ] as Int
172172 if (len <= 0 ) return @hookAllMethods
173173
174- val key = System .identityHashCode( socket)
174+ val key = socket
175175 val buffer = RequestHook .requestBuffers.computeIfAbsent(key) { ByteArrayOutputStream () }
176176 buffer.write(bytes, offset, len)
177177 if (RequestHook .processRequestBuffer(key, isHttps = false )) {
@@ -190,17 +190,30 @@ internal object RequestHookHandler {
190190 }
191191
192192 val socket = XposedHelpers .getObjectField(param.thisObject, " socket" )
193+ ? : return @hookAllMethods
193194 if (socket is SSLSocket ) return @hookAllMethods
194195
195196 val bytes = param.args[1 ] as ByteArray
196197 val len = param.result as ? Int ? : - 1
197198 if (len <= 0 ) return @hookAllMethods
198199
199- val key = System .identityHashCode( socket)
200+ val key = socket
200201 val buffer = RequestHook .responseBuffers.computeIfAbsent(key) { ByteArrayOutputStream () }
201202 buffer.write(bytes, 0 , len)
202203 RequestHook .processResponseBuffer(key, param)
203204 }
205+
206+ // Remove buffer entries as soon as the socket closes.
207+ HookUtil .hookAllMethods(
208+ " java.net.Socket" ,
209+ " close" ,
210+ " after"
211+ ) { param ->
212+ val key = param.thisObject
213+ RequestHook .requestBuffers.remove(key)
214+ RequestHook .responseBuffers.remove(key)
215+ RequestHook .pendingRequests.remove(key)
216+ }
204217 } catch (e: Throwable ) {
205218 XposedBridge .log(" $LOG_PREFIX Error setting up plain socket hook: ${e.message} " )
206219 }
@@ -241,7 +254,7 @@ internal object RequestHookHandler {
241254 return @findAndHookMethod
242255 }
243256
244- val key = connId.toInt() or Int . MIN_VALUE
257+ val key = param.thisObject
245258 val buffer = RequestHook .requestBuffers.computeIfAbsent(key) { ByteArrayOutputStream () }
246259 buffer.write(bytes)
247260 if (RequestHook .processRequestBuffer(key, isHttps = true )) {
@@ -290,7 +303,7 @@ internal object RequestHookHandler {
290303 return @findAndHookMethod
291304 }
292305
293- val key = connId.toInt() or Int . MIN_VALUE
306+ val key = param.thisObject
294307 val buffer = RequestHook .responseBuffers.computeIfAbsent(key) { ByteArrayOutputStream () }
295308 buffer.write(bytes)
296309 RequestHook .processResponseBuffer(key, param)
@@ -311,6 +324,9 @@ internal object RequestHookHandler {
311324 try {
312325 val connId = System .identityHashCode(param.thisObject).toLong() or (1L shl 48 )
313326 NativeRequestHook .freeH2Conn(connId)
327+ RequestHook .requestBuffers.remove(param.thisObject)
328+ RequestHook .responseBuffers.remove(param.thisObject)
329+ RequestHook .pendingRequests.remove(param.thisObject)
314330 } catch (e: Throwable ) {
315331 XposedBridge .log(" $LOG_PREFIX ConscryptEngine.closeInbound hook error: ${e.message} " )
316332 }
@@ -350,10 +366,6 @@ internal object RequestHookHandler {
350366 param.result = emptyWebResponse
351367 return @hookAllMethods
352368 }
353-
354- if (HookPrefs .getBoolean(HookPrefs .KEY_COLLECT_RESPONSE_BODY , false )) {
355- sendParallelRequestForLogging(request)
356- }
357369 },
358370 classLoader
359371 )
@@ -372,84 +384,10 @@ internal object RequestHookHandler {
372384 )
373385 }
374386
375- private fun sendParallelRequestForLogging (request : WebResourceRequest ) {
376- val url = request.url
377- if (url == null || (url.scheme != " http" && url.scheme != " https" )) return
378-
379- RequestHook .asyncBroadcastExecutor.execute {
380- try {
381- val urlConnection = URL (request.url.toString()).openConnection() as HttpURLConnection
382- urlConnection.connectTimeout = 5000
383- urlConnection.readTimeout = 10000
384- urlConnection.requestMethod = request.method
385-
386- request.requestHeaders.forEach { (key, value) ->
387- urlConnection.setRequestProperty(key, value)
388- }
389- urlConnection.setRequestProperty(" X-AdClose-Proxy" , " true" )
390-
391- urlConnection.connect()
392-
393- val responseCode = urlConnection.responseCode
394- val responseMessage = urlConnection.responseMessage
395- val responseHeaders = urlConnection.headerFields
396- .entries.filter { it.key != null }
397- .joinToString(" \n " ) { " ${it.key} : ${it.value.joinToString(" , " )} " }
398- val contentType = urlConnection.contentType
399- val contentEncoding = urlConnection.contentEncoding
400-
401- val responseBodyBytes = if (HookPrefs .getBoolean(HookPrefs .KEY_COLLECT_RESPONSE_BODY , false )) {
402- val inputStream: InputStream ? = try {
403- urlConnection.inputStream
404- } catch (e: IOException ) {
405- urlConnection.errorStream
406- }
407- inputStream?.use { input ->
408- val buffer = ByteArrayOutputStream ()
409- TeeInputStream (input, buffer).use { it.readBytes() }
410- buffer.toByteArray()
411- }
412- } else null
413-
414- val mimeTypeWithEncoding = if (! contentEncoding.isNullOrEmpty()) {
415- " $contentType ; encoding=$contentEncoding "
416- } else {
417- contentType
418- }
419-
420- val formattedUrl = RequestHook .formatUrlWithoutQuery(url)
421- val info = BlockedRequest (
422- requestType = " Web" ,
423- requestValue = formattedUrl,
424- method = request.method,
425- urlString = url.toString(),
426- requestHeaders = request.requestHeaders.toString(),
427- requestBody = null ,
428- responseCode = responseCode,
429- responseMessage = responseMessage,
430- responseHeaders = responseHeaders,
431- responseBody = responseBodyBytes,
432- responseBodyContentType = mimeTypeWithEncoding,
433- stack = HookUtil .getFormattedStackTrace(),
434- dnsHost = null ,
435- fullAddress = null ,
436- requestId = UUID .randomUUID().toString()
437- )
438- RequestHook .checkShouldBlockRequest(info)
439- } catch (e: Throwable ) {
440- XposedBridge .log(" $LOG_PREFIX Error in parallel WebView request: ${e.message} " )
441- }
442- }
443- }
444-
445387 private fun processWebRequest (request : Any? ): Boolean {
446388 try {
447389 val webResourceRequest = request as ? WebResourceRequest ? : return false
448390
449- if (webResourceRequest.requestHeaders[" X-AdClose-Proxy" ] == " true" ) {
450- return false
451- }
452-
453391 val urlString = webResourceRequest.url?.toString() ? : return false
454392 val formattedUrl = RequestHook .formatUrlWithoutQuery(Uri .parse(urlString))
455393
0 commit comments