Skip to content

Commit

Permalink
fix(General): bug fix which includes the handling socket timeout exce…
Browse files Browse the repository at this point in the history
…ption, memory leak
  • Loading branch information
Udhayarajan committed Jul 16, 2023
1 parent 60e8626 commit 8c1ad78
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 49 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ plugins {
}

group = "io.github.udhayarajan"
version = "5.5.9.0.4"
version = "5.5.9.0.5"
//Version Naming incremented if "<NEW_FEATURE_ADDED>.<WORKED_ON_BUG>.<BETA_VERSION_COUNT>"
//Priority on incrementing Feature > BugFix > Beta

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.mugames.vidsnapkit.dataholders.ProgressState
import com.mugames.vidsnapkit.dataholders.Result
import com.mugames.vidsnapkit.network.HttpRequest
import com.mugames.vidsnapkit.sanitizeAsHeaderValue
import io.ktor.client.network.sockets.*
import io.ktor.client.plugins.*
import kotlinx.coroutines.*
import kotlinx.coroutines.future.future
Expand Down Expand Up @@ -158,6 +159,8 @@ abstract class Extractor(
clientRequestError()
else if (e is ClientRequestException && inputUrl.contains("instagram"))
onProgress(Result.Failed(Error.Instagram404Error(cookies != null)))
else if (e is SocketTimeoutException)
onProgress(Result.Failed(Error.NonFatalError("socket can't connect please try again")))
else
onProgress(Result.Failed(Error.InternalError("Error in SafeAnalyze", e)))
}
Expand Down
50 changes: 24 additions & 26 deletions src/commonMain/kotlin/com/mugames/vidsnapkit/network/HttpRequest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package com.mugames.vidsnapkit.network

import io.ktor.client.*
import io.ktor.client.engine.android.*
import io.ktor.client.plugins.*
import io.ktor.client.request.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
Expand All @@ -42,18 +43,22 @@ class HttpRequest(
companion object {
private var prefixUrl = ""
private var additionHeader: Hashtable<String, String>? = null
private fun defaultClient(requiresRedirection: Boolean = true) = HttpInterfaceImpl(
HttpClient(Android).config {
followRedirects = requiresRedirection
}
)

private var clientGenerator: () -> HttpClient = {
HttpClient(Android)
}

private fun createClient(requiresRedirection: Boolean = true): HttpInterface {
return HttpInterfaceImpl(clientGenerator().config { followRedirects = requiresRedirection })
private fun getClient(
useCustomClient: Boolean,
requiresRedirection: Boolean = true,
): HttpInterfaceImpl {
val httpClient = if (useCustomClient) clientGenerator() else HttpClient(Android)
return HttpInterfaceImpl(httpClient.config {
followRedirects = requiresRedirection
install(HttpTimeout) {
socketTimeoutMillis = 13_000
}
})
}

/**
Expand Down Expand Up @@ -90,9 +95,8 @@ class HttpRequest(
*/
suspend fun getResponse(needsRedirection: Boolean = true, useCustomClient: Boolean = true): String? =
withContext(Dispatchers.IO) {
(if (useCustomClient) createClient(needsRedirection) else defaultClient(needsRedirection)).getData(
getUrl(),
getHeader()
getClient(useCustomClient, needsRedirection).getData(
getUrl(), getHeader()
)
}

Expand All @@ -101,30 +105,24 @@ class HttpRequest(
*
* @return bytes count of given [url]
*/
suspend fun getSize(useCustomClient: Boolean = true) =
(if (useCustomClient) createClient() else defaultClient()).getSize(url, getHeader())
suspend fun getSize(useCustomClient: Boolean = true) = getClient(useCustomClient).getSize(url, getHeader())

suspend fun postRequest(postData: Hashtable<String, Any>? = null, useCustomClient: Boolean = true): String =
withContext(Dispatchers.IO) {
(if (useCustomClient) createClient() else defaultClient()).postData(
getUrl(),
postData,
getHeader()
getClient(useCustomClient).postData(
getUrl(), postData, getHeader()
)
}

suspend fun getRawResponse(needsRedirection: Boolean = true, useCustomClient: Boolean = true) =
(if (useCustomClient) createClient(needsRedirection) else defaultClient(needsRedirection)).getRawResponse(
getUrl(),
getHeader()
getClient(useCustomClient, needsRedirection).getRawResponse(
getUrl(), getHeader()
)

suspend fun isAvailable(useCustomClient: Boolean = true): Boolean =
withContext(Dispatchers.IO) {
(if (useCustomClient) createClient(false) else defaultClient(false)).checkWebPage(
getUrl(),
getHeader()
)
}
suspend fun isAvailable(useCustomClient: Boolean = true): Boolean = withContext(Dispatchers.IO) {
getClient(useCustomClient, false).checkWebPage(
getUrl(), getHeader()
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package com.mugames.vidsnapkit.network

import com.mugames.vidsnapkit.toJsonString
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.network.sockets.*
import io.ktor.client.plugins.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
Expand Down Expand Up @@ -67,7 +67,7 @@ class HttpInterfaceImpl(
headers: Hashtable<String, String>?,
): String {
return try {
client.post {
val data = client.post {
url(url)
headers?.let {
if (it.isNotEmpty())
Expand All @@ -80,11 +80,14 @@ class HttpInterfaceImpl(
setBody(TextContent(it.toJsonString(), ContentType.Application.Json))
}
}.bodyAsText()
client.close()
data
} catch (e: Exception) {
logger.error(
"postData() url=${url} header=${headers.toString()} & postData=${postData.toString()} Error:",
e
)
client.close()
throw e
}
}
Expand Down Expand Up @@ -116,22 +119,27 @@ class HttpInterfaceImpl(
}
}
}.run {
status in acceptedStatusCode || run {
val data = status in acceptedStatusCode || run {
if (status in redirectionStatusCode) {
val res = getLastPossibleRedirectedResponse(this, headers)
val isPageAvailable = res.status in acceptedStatusCode || res.status in redirectionStatusCode
logger.info("page availability = $isPageAvailable")
client.close()
return isPageAvailable
}
logger.warn("Unhandled in checkWebPage() status code=${status} for url=${url} with headers=${headers.toString()} & response=${bodyAsText()}")
false
}
client.close()
data
}
} catch (e: ClientRequestException) {
logger.error("checkWebPage() url=${url} header=${headers.toString()} ClientRequestException:", e)
client.close()
false
} catch (e: Exception) {
logger.error("checkWebPage() url=${url} header=${headers.toString()} GenericException:", e)
client.close()
false
}
}
Expand All @@ -149,38 +157,50 @@ class HttpInterfaceImpl(
}
}
}.run {
if (status == HttpStatusCode.OK)
body()
else if (status in redirectionStatusCode) {
getLastPossibleRedirectedResponse(this, headers).body()
} else if (url.contains("instagram") && status == HttpStatusCode.InternalServerError) "{error:\"Invalid Cookies\"}"
else if (status == HttpStatusCode.TooManyRequests) {
if (status == HttpStatusCode.OK) {
val data = bodyAsText()
client.close()
data
} else if (status in redirectionStatusCode) {
val data = getLastPossibleRedirectedResponse(this, headers).bodyAsText()
client.close()
data
} else if (url.contains("instagram") && status == HttpStatusCode.InternalServerError) {
client.close()
"{error:\"Invalid Cookies\"}"
} else if (status == HttpStatusCode.TooManyRequests) {
logger.warn("Unhandled in getData() TooManyRequest for url=${url} with headers=${headers.toString()} & response=${bodyAsText()}")
client.close()
"429"
} else {
logger.warn("Unhandled in getData() status code=${status} for url=${url} with headers=${headers.toString()} &\n response=${bodyAsText()}")
client.close()
null
}
}
} catch (e: ClientRequestException) {
logger.error("getData() url=${url} header=${headers.toString()} ClientRequestException:", e)
client.close()
null
} catch (e: SendCountExceedException) {
if (url.contains("instagram") && headers?.containsKey("Cookie") == true)
if (url.contains("instagram") && headers?.containsKey("Cookie") == true) {
client.close()
"{error:\"Invalid Cookies\"}"
else {
} else {
logger.error("getData() url=${url} header=${headers.toString()} SendCountExceedException:", e)
client.close()
throw e
}
} catch (e: Exception) {
logger.error("getData() url=${url} header=${headers.toString()} Generic exception:", e)
client.close()
throw e
}
}

override suspend fun getRawResponse(url: String, headers: Hashtable<String, String>?): HttpResponse? {
return try {
client.get {
val response = client.get {
url(url)
headers?.let {
if (it.isNotEmpty()) {
Expand All @@ -191,25 +211,45 @@ class HttpInterfaceImpl(
}
}
}
client.close()
response
} catch (e: Exception) {
var x = false
client.config { x = followRedirects }
client.close()
logger.error(
"getRawResponse() url=${url} header=${headers.toString()} clientRedirection=${x} Generic exception:",
"getRawResponse() url=${url} header=${headers.toString()} Generic exception:",
e
)
null
}
}

override suspend fun getSize(url: String, headers: Hashtable<String, String>?): Long {
return client.request {
method = HttpMethod.Head
url(url)
}.run {
if (status == HttpStatusCode.OK)
this.headers["content-length"]?.toLong() ?: Long.MIN_VALUE
else Long.MIN_VALUE
return try {
client.request {
method = HttpMethod.Head
url(url)
timeout {
socketTimeoutMillis = 13_000
requestTimeoutMillis = 13_000
connectTimeoutMillis = 13_000
}
}.run {
if (status == HttpStatusCode.OK) {
val data = this.headers["content-length"]?.toLong() ?: Long.MIN_VALUE
client.close()
data
} else Long.MIN_VALUE
}
} catch (e: Exception) {
client.close()
when (e) {
is HttpRequestTimeoutException, is ConnectTimeoutException, is SocketTimeoutException -> {
// handle the exception
1
}

else -> throw e
}
}
}

Expand Down Expand Up @@ -238,6 +278,7 @@ class HttpInterfaceImpl(
}
}
}
nonRedirectingClient.close()
if (cacheResponse.request.url == tempResponse.request.url)
break
cacheResponse = tempResponse
Expand Down

0 comments on commit 8c1ad78

Please sign in to comment.