Further work on http imp.

This commit is contained in:
Koen J
2025-11-24 10:33:18 +01:00
parent 1ea7b307fa
commit 3f85b7ed78
@@ -51,6 +51,15 @@ class PackageHttpImp : V8Package {
Logger.w(TAG, "PackageHttpImp Cleaning up") Logger.w(TAG, "PackageHttpImp Cleaning up")
} }
@V8Function
fun socket(
url: String,
headers: MutableMap<String, String>? = null,
useAuth: Boolean = false
): Any {
throw NotImplementedError("WebSocket is not supported by the curl-impersonate HTTP implementation.")
}
private fun <T, R> autoParallelPool( private fun <T, R> autoParallelPool(
data: List<T>, data: List<T>,
parallelism: Int, parallelism: Int,
@@ -115,13 +124,30 @@ class PackageHttpImp : V8Package {
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
useAuth: Boolean = false, useAuth: Boolean = false,
bytesResult: Boolean = false bytesResult: Boolean = false
): IBridgeHttpResponse {
return request(method, url, headers, useAuth, bytesResult, null)
}
@V8Function
fun request(
method: String,
url: String,
headers: MutableMap<String, String>,
useAuth: Boolean,
bytesResult: Boolean,
options: MutableMap<String, Any?>?
): IBridgeHttpResponse { ): IBridgeHttpResponse {
val client = if (useAuth) _packageClientAuth else _packageClient val client = if (useAuth) _packageClientAuth else _packageClient
val parsed = parseRequestOptions(options)
val returnType = if (bytesResult) ReturnType.BYTES else ReturnType.STRING
return client.requestInternal( return client.requestInternal(
method, method,
url, url,
headers, headers,
if (bytesResult) ReturnType.BYTES else ReturnType.STRING returnType,
parsed.impersonateTarget,
parsed.useBuiltInHeaders,
parsed.timeoutMs
) )
} }
@@ -129,19 +155,88 @@ class PackageHttpImp : V8Package {
fun requestWithBody( fun requestWithBody(
method: String, method: String,
url: String, url: String,
body: String, body: Any,
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
useAuth: Boolean = false, useAuth: Boolean = false,
bytesResult: Boolean = false bytesResult: Boolean = false
): IBridgeHttpResponse {
return requestWithBody(method, url, body, headers, useAuth, bytesResult, null)
}
@V8Function
fun requestWithBody(
method: String,
url: String,
body: Any,
headers: MutableMap<String, String>,
useAuth: Boolean,
bytesResult: Boolean,
options: MutableMap<String, Any?>?
): IBridgeHttpResponse { ): IBridgeHttpResponse {
val client = if (useAuth) _packageClientAuth else _packageClient val client = if (useAuth) _packageClientAuth else _packageClient
return client.requestWithBodyInternal( val parsed = parseRequestOptions(options)
method, val returnType = if (bytesResult) ReturnType.BYTES else ReturnType.STRING
url,
body, return when (body) {
headers, is V8ValueString ->
if (bytesResult) ReturnType.BYTES else ReturnType.STRING client.requestWithBodyInternal(
) method,
url,
body.value,
headers,
returnType,
parsed.impersonateTarget,
parsed.useBuiltInHeaders,
parsed.timeoutMs
)
is String ->
client.requestWithBodyInternal(
method,
url,
body,
headers,
returnType,
parsed.impersonateTarget,
parsed.useBuiltInHeaders,
parsed.timeoutMs
)
is V8ValueTypedArray ->
client.requestWithBodyInternal(
method,
url,
body.toBytes(),
headers,
returnType,
parsed.impersonateTarget,
parsed.useBuiltInHeaders,
parsed.timeoutMs
)
is ByteArray ->
client.requestWithBodyInternal(
method,
url,
body,
headers,
returnType,
parsed.impersonateTarget,
parsed.useBuiltInHeaders,
parsed.timeoutMs
)
is ArrayList<*> ->
client.requestWithBodyInternal(
method,
url,
body.map { (it as Double).toInt().toByte() }.toByteArray(),
headers,
returnType,
parsed.impersonateTarget,
parsed.useBuiltInHeaders,
parsed.timeoutMs
)
else -> throw NotImplementedError(
"Body type ${body?.javaClass?.name} not implemented for requestWithBody"
)
}
} }
@V8Function @V8Function
@@ -150,12 +245,27 @@ class PackageHttpImp : V8Package {
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
useAuth: Boolean = false, useAuth: Boolean = false,
useByteResponse: Boolean = false useByteResponse: Boolean = false
): IBridgeHttpResponse {
return GET(url, headers, useAuth, useByteResponse, null)
}
@V8Function
fun GET(
url: String,
headers: MutableMap<String, String>,
useAuth: Boolean,
useByteResponse: Boolean,
options: MutableMap<String, Any?>?
): IBridgeHttpResponse { ): IBridgeHttpResponse {
val client = if (useAuth) _packageClientAuth else _packageClient val client = if (useAuth) _packageClientAuth else _packageClient
val parsed = parseRequestOptions(options)
return client.GETInternal( return client.GETInternal(
url, url,
headers, headers,
if (useByteResponse) ReturnType.BYTES else ReturnType.STRING if (useByteResponse) ReturnType.BYTES else ReturnType.STRING,
parsed.impersonateTarget,
parsed.useBuiltInHeaders,
parsed.timeoutMs
) )
} }
@@ -166,26 +276,77 @@ class PackageHttpImp : V8Package {
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
useAuth: Boolean = false, useAuth: Boolean = false,
useByteResponse: Boolean = false useByteResponse: Boolean = false
): IBridgeHttpResponse {
return POST(url, body, headers, useAuth, useByteResponse, null)
}
@V8Function
fun POST(
url: String,
body: Any,
headers: MutableMap<String, String>,
useAuth: Boolean,
useByteResponse: Boolean,
options: MutableMap<String, Any?>?
): IBridgeHttpResponse { ): IBridgeHttpResponse {
val client = if (useAuth) _packageClientAuth else _packageClient val client = if (useAuth) _packageClientAuth else _packageClient
val parsed = parseRequestOptions(options)
val returnType = if (useByteResponse) ReturnType.BYTES else ReturnType.STRING
return when (body) { return when (body) {
is V8ValueString -> is V8ValueString ->
client.POSTInternal(url, body.value, headers, if (useByteResponse) ReturnType.BYTES else ReturnType.STRING) client.POSTInternal(
url,
body.value,
headers,
returnType,
parsed.impersonateTarget,
parsed.useBuiltInHeaders,
parsed.timeoutMs
)
is String -> is String ->
client.POSTInternal(url, body, headers, if (useByteResponse) ReturnType.BYTES else ReturnType.STRING) client.POSTInternal(
url,
body,
headers,
returnType,
parsed.impersonateTarget,
parsed.useBuiltInHeaders,
parsed.timeoutMs
)
is V8ValueTypedArray -> is V8ValueTypedArray ->
client.POSTInternal(url, body.toBytes(), headers, if (useByteResponse) ReturnType.BYTES else ReturnType.STRING) client.POSTInternal(
url,
body.toBytes(),
headers,
returnType,
parsed.impersonateTarget,
parsed.useBuiltInHeaders,
parsed.timeoutMs
)
is ByteArray -> is ByteArray ->
client.POSTInternal(url, body, headers, if (useByteResponse) ReturnType.BYTES else ReturnType.STRING) client.POSTInternal(
url,
body,
headers,
returnType,
parsed.impersonateTarget,
parsed.useBuiltInHeaders,
parsed.timeoutMs
)
is ArrayList<*> -> is ArrayList<*> ->
client.POSTInternal( client.POSTInternal(
url, url,
body.map { (it as Double).toInt().toByte() }.toByteArray(), body.map { (it as Double).toInt().toByte() }.toByteArray(),
headers, headers,
if (useByteResponse) ReturnType.BYTES else ReturnType.STRING returnType,
parsed.impersonateTarget,
parsed.useBuiltInHeaders,
parsed.timeoutMs
) )
else -> throw NotImplementedError("Body type ${body?.javaClass?.name} not implemented for POST") else -> throw NotImplementedError(
"Body type ${body?.javaClass?.name} not implemented for POST"
)
} }
} }
@@ -261,7 +422,19 @@ class PackageHttpImp : V8Package {
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
useAuth: Boolean = false useAuth: Boolean = false
): BatchBuilder { ): BatchBuilder {
return clientRequest(_package.getDefaultClient(useAuth).clientId(), method, url, headers) return request(method, url, headers, useAuth, null)
}
@V8Function
fun request(
method: String,
url: String,
headers: MutableMap<String, String>,
useAuth: Boolean,
options: MutableMap<String, Any?>?
): BatchBuilder {
val clientId = _package.getDefaultClient(useAuth).clientId()
return clientRequest(clientId, method, url, headers, options)
} }
@V8Function @V8Function
@@ -272,7 +445,20 @@ class PackageHttpImp : V8Package {
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
useAuth: Boolean = false useAuth: Boolean = false
): BatchBuilder { ): BatchBuilder {
return clientRequestWithBody(_package.getDefaultClient(useAuth).clientId(), method, url, body, headers) return requestWithBody(method, url, body, headers, useAuth, null)
}
@V8Function
fun requestWithBody(
method: String,
url: String,
body: String,
headers: MutableMap<String, String>,
useAuth: Boolean,
options: MutableMap<String, Any?>?
): BatchBuilder {
val clientId = _package.getDefaultClient(useAuth).clientId()
return clientRequestWithBody(clientId, method, url, body, headers, options)
} }
@V8Function @V8Function
@@ -281,7 +467,16 @@ class PackageHttpImp : V8Package {
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
useAuth: Boolean = false useAuth: Boolean = false
): BatchBuilder = ): BatchBuilder =
clientGET(_package.getDefaultClient(useAuth).clientId(), url, headers) GET(url, headers, useAuth, null)
@V8Function
fun GET(
url: String,
headers: MutableMap<String, String>,
useAuth: Boolean,
options: MutableMap<String, Any?>?
): BatchBuilder =
clientGET(_package.getDefaultClient(useAuth).clientId(), url, headers, options)
@V8Function @V8Function
fun POST( fun POST(
@@ -290,7 +485,17 @@ class PackageHttpImp : V8Package {
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
useAuth: Boolean = false useAuth: Boolean = false
): BatchBuilder = ): BatchBuilder =
clientPOST(_package.getDefaultClient(useAuth).clientId(), url, body, headers) POST(url, body, headers, useAuth, null)
@V8Function
fun POST(
url: String,
body: String,
headers: MutableMap<String, String>,
useAuth: Boolean,
options: MutableMap<String, Any?>?
): BatchBuilder =
clientPOST(_package.getDefaultClient(useAuth).clientId(), url, body, headers, options)
@V8Function @V8Function
fun DUMMY(): BatchBuilder { fun DUMMY(): BatchBuilder {
@@ -310,7 +515,37 @@ class PackageHttpImp : V8Package {
url: String, url: String,
headers: MutableMap<String, String> = HashMap() headers: MutableMap<String, String> = HashMap()
): BatchBuilder { ): BatchBuilder {
_reqs.add(Pair(_package.getClient(clientId), RequestDescriptor(method, url, headers))) return clientRequest(clientId, method, url, headers, null)
}
@V8Function
fun clientRequest(
clientId: String?,
method: String,
url: String,
headers: MutableMap<String, String>,
options: MutableMap<String, Any?>?
): BatchBuilder {
val opts = PackageHttpImp.parseRequestOptions(options)
val respType =
if ((options?.get("useByteResponses") as? Boolean) == true) ReturnType.BYTES else ReturnType.STRING
_reqs.add(
Pair(
_package.getClient(clientId),
RequestDescriptor(
method = method,
url = url,
headers = headers,
body = null,
contentType = null,
respType = respType,
impersonateTarget = opts.impersonateTarget,
useBuiltInHeaders = opts.useBuiltInHeaders,
timeoutMs = opts.timeoutMs
)
)
)
return BatchBuilder(_package, _reqs) return BatchBuilder(_package, _reqs)
} }
@@ -322,10 +557,36 @@ class PackageHttpImp : V8Package {
body: String, body: String,
headers: MutableMap<String, String> = HashMap() headers: MutableMap<String, String> = HashMap()
): BatchBuilder { ): BatchBuilder {
return clientRequestWithBody(clientId, method, url, body, headers, null)
}
@V8Function
fun clientRequestWithBody(
clientId: String?,
method: String,
url: String,
body: String,
headers: MutableMap<String, String>,
options: MutableMap<String, Any?>?
): BatchBuilder {
val opts = PackageHttpImp.parseRequestOptions(options)
val respType =
if ((options?.get("useByteResponses") as? Boolean) == true) ReturnType.BYTES else ReturnType.STRING
_reqs.add( _reqs.add(
Pair( Pair(
_package.getClient(clientId), _package.getClient(clientId),
RequestDescriptor(method, url, headers, body) RequestDescriptor(
method = method,
url = url,
headers = headers,
body = body,
contentType = null,
respType = respType,
impersonateTarget = opts.impersonateTarget,
useBuiltInHeaders = opts.useBuiltInHeaders,
timeoutMs = opts.timeoutMs
)
) )
) )
return BatchBuilder(_package, _reqs) return BatchBuilder(_package, _reqs)
@@ -339,6 +600,15 @@ class PackageHttpImp : V8Package {
): BatchBuilder = ): BatchBuilder =
clientRequest(clientId, "GET", url, headers) clientRequest(clientId, "GET", url, headers)
@V8Function
fun clientGET(
clientId: String?,
url: String,
headers: MutableMap<String, String>,
options: MutableMap<String, Any?>?
): BatchBuilder =
clientRequest(clientId, "GET", url, headers, options)
@V8Function @V8Function
fun clientPOST( fun clientPOST(
clientId: String?, clientId: String?,
@@ -348,26 +618,46 @@ class PackageHttpImp : V8Package {
): BatchBuilder = ): BatchBuilder =
clientRequestWithBody(clientId, "POST", url, body, headers) clientRequestWithBody(clientId, "POST", url, body, headers)
@V8Function
fun clientPOST(
clientId: String?,
url: String,
body: String,
headers: MutableMap<String, String>,
options: MutableMap<String, Any?>?
): BatchBuilder =
clientRequestWithBody(clientId, "POST", url, body, headers, options)
@V8Function @V8Function
fun execute(): List<IBridgeHttpResponse?> { fun execute(): List<IBridgeHttpResponse?> {
return _package.autoParallelPool(_reqs, -1) { return _package.autoParallelPool(_reqs, -1) { pair ->
if (it.second.method == "DUMMY") { val client = pair.first
val descriptor = pair.second
if (descriptor.method == "DUMMY") {
return@autoParallelPool null return@autoParallelPool null
} }
if (it.second.body != null) {
it.first.requestWithBodyInternal( if (descriptor.body != null) {
it.second.method, client.requestWithBodyInternal(
it.second.url, descriptor.method,
it.second.body!!, descriptor.url,
it.second.headers, descriptor.body,
it.second.respType descriptor.headers,
descriptor.respType,
descriptor.impersonateTarget,
descriptor.useBuiltInHeaders,
descriptor.timeoutMs
) )
} else { } else {
it.first.requestInternal( client.requestInternal(
it.second.method, descriptor.method,
it.second.url, descriptor.url,
it.second.headers, descriptor.headers,
it.second.respType descriptor.respType,
descriptor.impersonateTarget,
descriptor.useBuiltInHeaders,
descriptor.timeoutMs
) )
} }
}.map { }.map {
@@ -401,7 +691,10 @@ class PackageHttpImp : V8Package {
private var sendCookies: Boolean = true private var sendCookies: Boolean = true
@Volatile @Volatile
private var persistCookies: Boolean = true private var updateCookies: Boolean = true
@Volatile
private var allowNewCookies: Boolean = true
@Volatile @Volatile
private var cookieJarPath: String? = null private var cookieJarPath: String? = null
@@ -449,12 +742,12 @@ class PackageHttpImp : V8Package {
@V8Function @V8Function
fun setDoUpdateCookies(update: Boolean) { fun setDoUpdateCookies(update: Boolean) {
persistCookies = update updateCookies = update
} }
@V8Function @V8Function
fun setDoAllowNewCookies(allow: Boolean) { fun setDoAllowNewCookies(allow: Boolean) {
persistCookies = allow allowNewCookies = allow
} }
@V8Function @V8Function
@@ -462,6 +755,16 @@ class PackageHttpImp : V8Package {
this.timeoutMs = timeoutMs this.timeoutMs = timeoutMs
} }
@V8Function
fun setDefaultImpersonateTarget(target: String) {
impersonateTarget = target
}
@V8Function
fun setUseBuiltInHeaders(enable: Boolean) {
useBuiltInHeaders = enable
}
@V8Function @V8Function
fun request( fun request(
method: String, method: String,
@@ -469,21 +772,48 @@ class PackageHttpImp : V8Package {
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
useBytes: Boolean = false useBytes: Boolean = false
): IBridgeHttpResponse = ): IBridgeHttpResponse =
requestInternal(method, url, headers, if (useBytes) ReturnType.BYTES else ReturnType.STRING) request(method, url, headers, useBytes, null)
@V8Function
fun request(
method: String,
url: String,
headers: MutableMap<String, String>,
useBytes: Boolean,
options: MutableMap<String, Any?>?
): IBridgeHttpResponse {
val opts = PackageHttpImp.parseRequestOptions(options)
val returnType = if (useBytes) ReturnType.BYTES else ReturnType.STRING
return requestInternal(
method,
url,
headers,
returnType,
opts.impersonateTarget,
opts.useBuiltInHeaders,
opts.timeoutMs
)
}
fun requestInternal( fun requestInternal(
method: String, method: String,
url: String, url: String,
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
returnType: ReturnType returnType: ReturnType,
impersonateTargetOverride: String? = null,
useBuiltInHeadersOverride: Boolean? = null,
timeoutMsOverride: Int? = null
): IBridgeHttpResponse { ): IBridgeHttpResponse {
applyDefaultHeaders(headers) return executeRequest(
return logExceptions { method,
catchHttp { url,
val resp = performCurl(method, url, headers, null) headers,
responseToBridge(resp, returnType) null,
} returnType,
} impersonateTargetOverride,
useBuiltInHeadersOverride,
timeoutMsOverride
)
} }
@V8Function @V8Function
@@ -494,28 +824,73 @@ class PackageHttpImp : V8Package {
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
useBytes: Boolean = false useBytes: Boolean = false
): IBridgeHttpResponse = ): IBridgeHttpResponse =
requestWithBodyInternal( requestWithBody(method, url, body, headers, useBytes, null)
@V8Function
fun requestWithBody(
method: String,
url: String,
body: String,
headers: MutableMap<String, String>,
useBytes: Boolean,
options: MutableMap<String, Any?>?
): IBridgeHttpResponse {
val opts = PackageHttpImp.parseRequestOptions(options)
val returnType = if (useBytes) ReturnType.BYTES else ReturnType.STRING
return requestWithBodyInternal(
method, method,
url, url,
body, body,
headers, headers,
if (useBytes) ReturnType.BYTES else ReturnType.STRING returnType,
opts.impersonateTarget,
opts.useBuiltInHeaders,
opts.timeoutMs
) )
}
fun requestWithBodyInternal( fun requestWithBodyInternal(
method: String, method: String,
url: String, url: String,
body: String, body: String,
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
returnType: ReturnType returnType: ReturnType,
impersonateTargetOverride: String? = null,
useBuiltInHeadersOverride: Boolean? = null,
timeoutMsOverride: Int? = null
): IBridgeHttpResponse { ): IBridgeHttpResponse {
applyDefaultHeaders(headers) return executeRequest(
return logExceptions { method,
catchHttp { url,
val resp = performCurl(method, url, headers, body.toByteArray()) headers,
responseToBridge(resp, returnType) body.toByteArray(),
} returnType,
} impersonateTargetOverride,
useBuiltInHeadersOverride,
timeoutMsOverride
)
}
fun requestWithBodyInternal(
method: String,
url: String,
body: ByteArray,
headers: MutableMap<String, String> = HashMap(),
returnType: ReturnType,
impersonateTargetOverride: String? = null,
useBuiltInHeadersOverride: Boolean? = null,
timeoutMsOverride: Int? = null
): IBridgeHttpResponse {
return executeRequest(
method,
url,
headers,
body,
returnType,
impersonateTargetOverride,
useBuiltInHeadersOverride,
timeoutMsOverride
)
} }
@V8Function @V8Function
@@ -524,20 +899,45 @@ class PackageHttpImp : V8Package {
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
useBytes: Boolean = false useBytes: Boolean = false
): IBridgeHttpResponse = ): IBridgeHttpResponse =
GETInternal(url, headers, if (useBytes) ReturnType.BYTES else ReturnType.STRING) GET(url, headers, useBytes, null)
@V8Function
fun GET(
url: String,
headers: MutableMap<String, String>,
useBytes: Boolean,
options: MutableMap<String, Any?>?
): IBridgeHttpResponse {
val opts = PackageHttpImp.parseRequestOptions(options)
val returnType = if (useBytes) ReturnType.BYTES else ReturnType.STRING
return GETInternal(
url,
headers,
returnType,
opts.impersonateTarget,
opts.useBuiltInHeaders,
opts.timeoutMs
)
}
fun GETInternal( fun GETInternal(
url: String, url: String,
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
returnType: ReturnType = ReturnType.STRING returnType: ReturnType = ReturnType.STRING,
impersonateTargetOverride: String? = null,
useBuiltInHeadersOverride: Boolean? = null,
timeoutMsOverride: Int? = null
): IBridgeHttpResponse { ): IBridgeHttpResponse {
applyDefaultHeaders(headers) return executeRequest(
return logExceptions { "GET",
catchHttp { url,
val resp = performCurl("GET", url, headers, null) headers,
responseToBridge(resp, returnType) null,
} returnType,
} impersonateTargetOverride,
useBuiltInHeadersOverride,
timeoutMsOverride
)
} }
@V8Function @V8Function
@@ -546,22 +946,70 @@ class PackageHttpImp : V8Package {
body: Any, body: Any,
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
useBytes: Boolean = false useBytes: Boolean = false
): IBridgeHttpResponse =
POST(url, body, headers, useBytes, null)
@V8Function
fun POST(
url: String,
body: Any,
headers: MutableMap<String, String>,
useBytes: Boolean,
options: MutableMap<String, Any?>?
): IBridgeHttpResponse { ): IBridgeHttpResponse {
val opts = PackageHttpImp.parseRequestOptions(options)
val returnType = if (useBytes) ReturnType.BYTES else ReturnType.STRING
return when (body) { return when (body) {
is V8ValueString -> is V8ValueString ->
POSTInternal(url, body.value, headers, if (useBytes) ReturnType.BYTES else ReturnType.STRING) POSTInternal(
url,
body.value,
headers,
returnType,
opts.impersonateTarget,
opts.useBuiltInHeaders,
opts.timeoutMs
)
is String -> is String ->
POSTInternal(url, body, headers, if (useBytes) ReturnType.BYTES else ReturnType.STRING) POSTInternal(
url,
body,
headers,
returnType,
opts.impersonateTarget,
opts.useBuiltInHeaders,
opts.timeoutMs
)
is V8ValueTypedArray -> is V8ValueTypedArray ->
POSTInternal(url, body.toBytes(), headers, if (useBytes) ReturnType.BYTES else ReturnType.STRING) POSTInternal(
url,
body.toBytes(),
headers,
returnType,
opts.impersonateTarget,
opts.useBuiltInHeaders,
opts.timeoutMs
)
is ByteArray -> is ByteArray ->
POSTInternal(url, body, headers, if (useBytes) ReturnType.BYTES else ReturnType.STRING) POSTInternal(
url,
body,
headers,
returnType,
opts.impersonateTarget,
opts.useBuiltInHeaders,
opts.timeoutMs
)
is ArrayList<*> -> is ArrayList<*> ->
POSTInternal( POSTInternal(
url, url,
body.map { (it as Double).toInt().toByte() }.toByteArray(), body.map { (it as Double).toInt().toByte() }.toByteArray(),
headers, headers,
if (useBytes) ReturnType.BYTES else ReturnType.STRING returnType,
opts.impersonateTarget,
opts.useBuiltInHeaders,
opts.timeoutMs
) )
else -> throw NotImplementedError("Body type ${body?.javaClass?.name} not implemented for POST") else -> throw NotImplementedError("Body type ${body?.javaClass?.name} not implemented for POST")
} }
@@ -571,55 +1019,101 @@ class PackageHttpImp : V8Package {
url: String, url: String,
body: String, body: String,
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
returnType: ReturnType = ReturnType.STRING returnType: ReturnType = ReturnType.STRING,
impersonateTargetOverride: String? = null,
useBuiltInHeadersOverride: Boolean? = null,
timeoutMsOverride: Int? = null
): IBridgeHttpResponse { ): IBridgeHttpResponse {
applyDefaultHeaders(headers) return executeRequest(
return logExceptions { "POST",
catchHttp { url,
val resp = performCurl("POST", url, headers, body.toByteArray()) headers,
responseToBridge(resp, returnType) body.toByteArray(),
} returnType,
} impersonateTargetOverride,
useBuiltInHeadersOverride,
timeoutMsOverride
)
} }
fun POSTInternal( fun POSTInternal(
url: String, url: String,
body: ByteArray, body: ByteArray,
headers: MutableMap<String, String> = HashMap(), headers: MutableMap<String, String> = HashMap(),
returnType: ReturnType = ReturnType.STRING returnType: ReturnType = ReturnType.STRING,
impersonateTargetOverride: String? = null,
useBuiltInHeadersOverride: Boolean? = null,
timeoutMsOverride: Int? = null
): IBridgeHttpResponse { ): IBridgeHttpResponse {
applyDefaultHeaders(headers) return executeRequest(
return logExceptions { "POST",
catchHttp { url,
val resp = performCurl("POST", url, headers, body) headers,
responseToBridge(resp, returnType) body,
} returnType,
} impersonateTargetOverride,
useBuiltInHeadersOverride,
timeoutMsOverride
)
} }
private fun performCurl( private fun performCurl(
method: String, method: String,
url: String, url: String,
headers: Map<String, String>, headers: Map<String, String>,
bodyBytes: ByteArray? bodyBytes: ByteArray?,
impersonateTargetOverride: String? = null,
useBuiltInHeadersOverride: Boolean? = null,
timeoutMsOverride: Int? = null
): Libcurl.Response { ): Libcurl.Response {
val jar = ensureCookieJarPath() val jar = ensureCookieJarPath()
val finalImpersonateTarget = impersonateTargetOverride ?: this.impersonateTarget
val finalUseBuiltInHeaders = useBuiltInHeadersOverride ?: this.useBuiltInHeaders
val finalTimeoutMs = timeoutMsOverride ?: this.timeoutMs
val req = Libcurl.Request( val req = Libcurl.Request(
url = url, url = url,
method = method, method = method,
headers = headers, headers = headers,
body = bodyBytes, body = bodyBytes,
impersonateTarget = impersonateTarget, impersonateTarget = finalImpersonateTarget,
useBuiltInHeaders = useBuiltInHeaders, useBuiltInHeaders = finalUseBuiltInHeaders,
timeoutMs = timeoutMs, timeoutMs = finalTimeoutMs,
cookieJarPath = jar, cookieJarPath = jar,
sendCookies = sendCookies, sendCookies = sendCookies,
persistCookies = persistCookies persistCookies = updateCookies && allowNewCookies
) )
return Libcurl.perform(req) return Libcurl.perform(req)
} }
private fun executeRequest(
method: String,
url: String,
headers: MutableMap<String, String>,
bodyBytes: ByteArray?,
returnType: ReturnType,
impersonateTargetOverride: String? = null,
useBuiltInHeadersOverride: Boolean? = null,
timeoutMsOverride: Int? = null
): IBridgeHttpResponse {
applyDefaultHeaders(headers)
return logExceptions {
catchHttp {
val resp = performCurl(
method,
url,
headers,
bodyBytes,
impersonateTargetOverride,
useBuiltInHeadersOverride,
timeoutMsOverride
)
responseToBridge(resp, returnType)
}
}
}
private fun responseToBridge( private fun responseToBridge(
resp: Libcurl.Response, resp: Libcurl.Response,
returnType: ReturnType returnType: ReturnType
@@ -754,7 +1248,10 @@ class PackageHttpImp : V8Package {
val headers: MutableMap<String, String>, val headers: MutableMap<String, String>,
val body: String? = null, val body: String? = null,
val contentType: String? = null, val contentType: String? = null,
val respType: ReturnType = ReturnType.STRING val respType: ReturnType = ReturnType.STRING,
val impersonateTarget: String? = null,
val useBuiltInHeaders: Boolean? = null,
val timeoutMs: Int? = null
) )
private fun catchHttp(handle: () -> BridgeHttpStringResponse): BridgeHttpStringResponse { private fun catchHttp(handle: () -> BridgeHttpStringResponse): BridgeHttpStringResponse {
@@ -783,5 +1280,47 @@ class PackageHttpImp : V8Package {
"content-disposition", "content-disposition",
"connection" "connection"
) )
internal data class RequestOptions(
val impersonateTarget: String? = null,
val useBuiltInHeaders: Boolean? = null,
val timeoutMs: Int? = null
)
internal fun parseRequestOptions(options: Map<String, Any?>?): RequestOptions {
if (options == null) return RequestOptions()
var impersonateTarget: String? = null
var useBuiltInHeaders: Boolean? = null
var timeoutMs: Int? = null
options["impersonateTarget"]?.let { v ->
val s = v as? String
if (!s.isNullOrBlank()) {
impersonateTarget = s
}
}
options["useBuiltInHeaders"]?.let { v ->
if (v is Boolean) {
useBuiltInHeaders = v
}
}
options["timeoutMs"]?.let { v ->
val n: Long? = when (v) {
is Int -> v.toLong()
is Long -> v
is Double -> v.toLong()
is Float -> v.toLong()
else -> null
}
if (n != null && n > 0 && n <= Int.MAX_VALUE) {
timeoutMs = n.toInt()
}
}
return RequestOptions(impersonateTarget, useBuiltInHeaders, timeoutMs)
}
} }
} }