fix: preserve webbricks params for startup ui requests
This commit is contained in:
parent
87ebf5a407
commit
39727f87f9
@ -87,8 +87,8 @@ class BricksHttp(private val context: BricksContext? = null) {
|
|||||||
authToken: String = ""
|
authToken: String = ""
|
||||||
): JsonObject {
|
): JsonObject {
|
||||||
val requestParams = params.withBackendContextIfNeeded(url)
|
val requestParams = params.withBackendContextIfNeeded(url)
|
||||||
val response = client.post(url) {
|
val requestUrl = url.withQueryParameters(requestParams)
|
||||||
appendQueryParameters(requestParams)
|
val response = client.post(requestUrl) {
|
||||||
contentType(ContentType.Application.Json)
|
contentType(ContentType.Application.Json)
|
||||||
setBody(body)
|
setBody(body)
|
||||||
if (authToken.isNotEmpty()) {
|
if (authToken.isNotEmpty()) {
|
||||||
@ -96,7 +96,7 @@ class BricksHttp(private val context: BricksContext? = null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val text = response.bodyAsText()
|
val text = response.bodyAsText()
|
||||||
response.throwIfHttpError(text, url)
|
response.throwIfHttpError(text, requestUrl)
|
||||||
return parseJsonObjectOrError(text)
|
return parseJsonObjectOrError(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,11 +109,11 @@ class BricksHttp(private val context: BricksContext? = null) {
|
|||||||
authToken: String = ""
|
authToken: String = ""
|
||||||
): String {
|
): String {
|
||||||
val requestParams = emptyMap<String, String>().withBackendContextIfNeeded(url)
|
val requestParams = emptyMap<String, String>().withBackendContextIfNeeded(url)
|
||||||
|
val requestUrl = url.withQueryParameters(requestParams)
|
||||||
val formBody = form.entries.joinToString("&") { (k, v) ->
|
val formBody = form.entries.joinToString("&") { (k, v) ->
|
||||||
"${k.encodeURLParameter()}=${v.encodeURLParameter()}"
|
"${k.encodeURLParameter()}=${v.encodeURLParameter()}"
|
||||||
}
|
}
|
||||||
val response = client.post(url) {
|
val response = client.post(requestUrl) {
|
||||||
appendQueryParameters(requestParams)
|
|
||||||
contentType(ContentType.Application.FormUrlEncoded)
|
contentType(ContentType.Application.FormUrlEncoded)
|
||||||
setBody(formBody)
|
setBody(formBody)
|
||||||
if (authToken.isNotEmpty()) {
|
if (authToken.isNotEmpty()) {
|
||||||
@ -121,7 +121,7 @@ class BricksHttp(private val context: BricksContext? = null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val text = response.bodyAsText()
|
val text = response.bodyAsText()
|
||||||
response.throwIfHttpError(text, url)
|
response.throwIfHttpError(text, requestUrl)
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,14 +134,14 @@ class BricksHttp(private val context: BricksContext? = null) {
|
|||||||
authToken: String = ""
|
authToken: String = ""
|
||||||
): String {
|
): String {
|
||||||
val requestParams = params.withBackendContextIfNeeded(url)
|
val requestParams = params.withBackendContextIfNeeded(url)
|
||||||
val response = client.get(url) {
|
val requestUrl = url.withQueryParameters(requestParams)
|
||||||
appendQueryParameters(requestParams)
|
val response = client.get(requestUrl) {
|
||||||
if (authToken.isNotEmpty()) {
|
if (authToken.isNotEmpty()) {
|
||||||
header(HttpHeaders.Authorization, "Bearer $authToken")
|
header(HttpHeaders.Authorization, "Bearer $authToken")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val text = response.bodyAsText()
|
val text = response.bodyAsText()
|
||||||
response.throwIfHttpError(text, url)
|
response.throwIfHttpError(text, requestUrl)
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,13 +175,23 @@ class BricksHttp(private val context: BricksContext? = null) {
|
|||||||
private fun Map<String, String>.withBackendContextIfNeeded(url: String): Map<String, String> =
|
private fun Map<String, String>.withBackendContextIfNeeded(url: String): Map<String, String> =
|
||||||
if (url.isWebBricksBackendResource()) withWebBricksRequestContext(this, requestContext) else this
|
if (url.isWebBricksBackendResource()) withWebBricksRequestContext(this, requestContext) else this
|
||||||
|
|
||||||
private fun HttpRequestBuilder.appendQueryParameters(params: Map<String, String>) {
|
private fun String.withQueryParameters(params: Map<String, String>): String {
|
||||||
url {
|
if (params.isEmpty()) return this
|
||||||
params.forEach { (k, v) ->
|
val fragmentIndex = indexOf('#')
|
||||||
parameters.remove(k)
|
val baseAndQuery = if (fragmentIndex >= 0) substring(0, fragmentIndex) else this
|
||||||
parameters.append(k, v)
|
val fragment = if (fragmentIndex >= 0) substring(fragmentIndex) else ""
|
||||||
}
|
val path = baseAndQuery.substringBefore('?')
|
||||||
|
val existingQuery = baseAndQuery.substringAfter('?', missingDelimiterValue = "")
|
||||||
|
val encodedOverrideKeys = params.keys.map { it.encodeURLParameter() }.toSet()
|
||||||
|
val preservedQuery = existingQuery
|
||||||
|
.split('&')
|
||||||
|
.filter { it.isNotBlank() }
|
||||||
|
.filter { entry -> entry.substringBefore('=').substringBefore('&') !in encodedOverrideKeys }
|
||||||
|
val appendedQuery = params.entries.map { (key, value) ->
|
||||||
|
"${key.encodeURLParameter()}=${value.encodeURLParameter()}"
|
||||||
}
|
}
|
||||||
|
val query = (preservedQuery + appendedQuery).joinToString("&")
|
||||||
|
return if (query.isBlank()) "$path$fragment" else "$path?$query$fragment"
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun HttpResponse.throwIfHttpError(body: String, requestUrl: String) {
|
private suspend fun HttpResponse.throwIfHttpError(body: String, requestUrl: String) {
|
||||||
|
|||||||
@ -57,7 +57,7 @@ The packaged macOS app also accepts the URL as its first argument:
|
|||||||
open build/compose/binaries/main/app/sageclient.app --args https://ai.atvoe.com/center.ui
|
open build/compose/binaries/main/app/sageclient.app --args https://ai.atvoe.com/center.ui
|
||||||
```
|
```
|
||||||
|
|
||||||
If the argument is an absolute `http://` or `https://` URL, `sageclient` uses the URL origin as `baseUrl` and loads the path/query part as the initial Bricks UI. If the argument is a relative path such as `/center.ui`, it uses `sage.baseUrl` and loads that path.
|
If the argument is an absolute `http://` or `https://` URL, `sageclient` uses the URL origin as `baseUrl` and loads the path/query part as the initial Bricks UI. If the argument is a relative path such as `/center.ui`, it uses `sage.baseUrl` and loads that path. The actual HTTP request is still issued through `BricksHttp`, so startup URLs ending in `.ui` / `.dspy` are requested with `_webbricks_=1`, `_width`, `_height`, `_is_mobile` and `_lang`; they must not be fetched as raw HTML/template pages.
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user