Add custom HTTP headers for subscription updates

https://github.com/2dust/v2rayNG/pull/5856
This commit is contained in:
2dust committed 2026-07-17 14:30:39 +08:00
1 parent 69cf1e70c1
commit 1eaea8e161
9 files changed
+49 -21

No files matched your search

@@ -6,5 +6,6 @@ data class UrlContentRequest(
val httpPort: Int = 0,
val proxyUsername: String? = null,
val proxyPassword: String? = null,
val userAgent: String? = null
val userAgent: String? = null,
val requestHeaders: String? = null
)
@@ -13,5 +13,6 @@ data class SubscriptionItem(
var filter: String? = null,
var allowInsecureUrl: Boolean = false,
var userAgent: String? = null,
var requestHeaders: String? = null,
)
@@ -557,6 +557,7 @@ object AngConfigManager {
}
LogUtil.i(AppConfig.TAG, url)
val userAgent = it.subscription.userAgent
val requestHeaders = it.subscription.requestHeaders
val proxyUsername = SettingsManager.getSocksUsername()
val proxyPassword = SettingsManager.getSocksPassword()
@@ -566,6 +567,7 @@ object AngConfigManager {
UrlContentRequest(
url = url,
userAgent = userAgent,
requestHeaders = requestHeaders,
timeout = 15000,
httpPort = httpPort,
proxyUsername = proxyUsername,
@@ -581,7 +583,8 @@ object AngConfigManager {
HttpUtil.getUrlContentWithUserAgent(
UrlContentRequest(
url = url,
userAgent = userAgent
userAgent = userAgent,
requestHeaders = requestHeaders
)
)
} catch (e: Exception) {
@@ -75,7 +75,6 @@ class SubEditActivity : BaseComponentActivity() {
}
private fun saveServer(subItem: SubscriptionItem): Boolean {
val intervalMinutes = subItem.updateInterval
if (TextUtils.isEmpty(subItem.remarks)) {
toast(R.string.sub_setting_remarks)
@@ -94,6 +93,11 @@ class SubEditActivity : BaseComponentActivity() {
}
}
if (subItem.autoUpdate && subItem.updateInterval < AppConfig.SUBSCRIPTION_MIN_INTERVAL_MINUTES) {
toast(R.string.toast_invalid_update_interval)
return false
}
MmkvManager.encodeSubscription(editSubId, subItem)
SubscriptionUpdater.syncOne(subId = editSubId)
SettingsChangeManager.makeSetupGroupTab()
@@ -123,11 +127,11 @@ fun SubEditScreen(
onSave: (SubscriptionItem) -> Boolean,
onDelete: () -> Unit
) {
val context = LocalContext.current
//val context = LocalContext.current
var remarks by rememberSaveable { mutableStateOf(initial.remarks.orEmpty()) }
var url by rememberSaveable { mutableStateOf(initial.url.orEmpty()) }
var userAgent by rememberSaveable { mutableStateOf(initial.userAgent.orEmpty()) }
var requestHeaders by rememberSaveable { mutableStateOf(initial.requestHeaders.orEmpty()) }
var filter by rememberSaveable { mutableStateOf(initial.filter ?: "") }
var enabled by rememberSaveable { mutableStateOf(initial.enabled) }
var autoUpdate by rememberSaveable { mutableStateOf(initial.autoUpdate) }
@@ -145,25 +149,11 @@ fun SubEditScreen(
subItem.remarks = remarks
subItem.url = url
subItem.userAgent = userAgent
subItem.requestHeaders = requestHeaders
subItem.filter = filter
subItem.enabled = enabled
subItem.autoUpdate = autoUpdate
val intervalInput = updateInterval.trim()
val intervalMinutes = intervalInput.toLongOrNull()
if (autoUpdate) {
if (intervalMinutes == null) {
subItem.updateInterval = SubscriptionItem().updateInterval
} else if (intervalMinutes < AppConfig.SUBSCRIPTION_MIN_INTERVAL_MINUTES) {
context.toast(context.getString(R.string.toast_invalid_update_interval))
return null
} else {
subItem.updateInterval = intervalMinutes
}
} else {
if (intervalMinutes != null && intervalMinutes >= AppConfig.SUBSCRIPTION_MIN_INTERVAL_MINUTES) {
subItem.updateInterval = intervalMinutes
}
}
subItem.updateInterval = updateInterval.toLong()
subItem.prevProfile = prevProfile
subItem.nextProfile = nextProfile
subItem.allowInsecureUrl = allowInsecureUrl
@@ -203,6 +193,7 @@ fun SubEditScreen(
FormTextField(stringResource(R.string.sub_setting_remarks), remarks, { remarks = it })
FormTextField(stringResource(R.string.sub_setting_url), url, { url = it })
FormTextField(stringResource(R.string.sub_setting_user_agent), userAgent, { userAgent = it })
FormTextField(stringResource(R.string.sub_setting_request_headers), requestHeaders, { requestHeaders = it })
FormTextField(stringResource(R.string.sub_setting_filter), filter, { filter = it })
SettingsSwitchItem(
title = stringResource(R.string.sub_setting_enable),
@@ -164,6 +164,16 @@ object HttpUtil {
applyEmbeddedBasicAuthHeader(currentUrl, requestBuilder)
val headersMap = JsonUtil.parseHeadersToMap(request.requestHeaders)
for ((key, value) in headersMap) {
LogUtil.d(AppConfig.TAG, "Adding custom header: $key = $value")
try {
requestBuilder.header(key, value)
} catch (_: IllegalArgumentException) {
}
}
if (request.httpPort != 0 && !request.proxyUsername.isNullOrBlank() && !request.proxyPassword.isNullOrBlank()) {
requestBuilder.header("Proxy-Authorization", Credentials.basic(request.proxyUsername, request.proxyPassword))
}
@@ -92,4 +92,23 @@ object JsonUtil {
return null
}
}
fun parseHeadersToMap(headersJson: String?): Map<String, String> {
val headerMap = mutableMapOf<String, String>()
val jsonObject = parseString(headersJson) ?: return headerMap
try {
for ((key, jsonElement) in jsonObject.entrySet()) {
if (key.isNullOrBlank() || jsonElement == null || jsonElement.isJsonNull) {
continue
}
val value = if (jsonElement.isJsonPrimitive) jsonElement.asString else jsonElement.toString()
if (value.isNotBlank()) {
headerMap[key] = value
}
}
} catch (e: Exception) {
LogUtil.e(AppConfig.TAG, "Failed to parse headers JSON", e)
}
return headerMap
}
}
@@ -305,6 +305,7 @@
<string name="sub_setting_remarks">备注</string>
<string name="sub_setting_url">可选地址 (url)</string>
<string name="sub_setting_user_agent">User Agent</string>
<string name="sub_setting_request_headers">请求头(JSON 格式)</string>
<string name="sub_setting_filter">别名正则过滤</string>
<string name="sub_setting_enable">启用更新</string>
<string name="sub_auto_update">启用自动更新</string>
@@ -304,6 +304,7 @@
<string name="sub_setting_remarks">備註</string>
<string name="sub_setting_url">可選位址(url)</string>
<string name="sub_setting_user_agent">User Agent</string>
<string name="sub_setting_request_headers">請求頭(JSON 格式)</string>
<string name="sub_setting_filter">別名正規過濾</string>
<string name="sub_setting_enable">啟用更新</string>
<string name="sub_auto_update">啟用自動更新</string>
@@ -311,6 +311,7 @@
<string name="sub_setting_remarks">remarks</string>
<string name="sub_setting_url">Optional URL</string>
<string name="sub_setting_user_agent">User Agent</string>
<string name="sub_setting_request_headers">Request Headers (JSON format)</string>
<string name="sub_setting_filter">Remarks regular filter</string>
<string name="sub_setting_enable">Enable update</string>
<string name="sub_auto_update">Enable automatic update</string>