refactor: remove custom requestHeaders

This commit is contained in:
lxien
2026-08-30 00:50:18 +08:00
parent 5a604d0476
commit 741649791d
14 changed files with 18 additions and 153 deletions
+15 -34
View File
@@ -11,7 +11,6 @@ use tokio_rustls::TlsAcceptor;
pub struct TlsTermPlugin {
local_addr: String,
host_header_rewrite: String,
request_headers: Vec<(String, String)>,
acceptor: TlsAcceptor,
}
@@ -30,13 +29,6 @@ impl TlsTermPlugin {
let tls_cfg = load_or_generate_https_server_config(&cfg.cert_file, &cfg.key_file, &cn)?;
let acceptor = TlsAcceptor::from(tls_cfg);
let request_headers: Vec<(String, String)> = cfg
.request_headers
.set
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect();
tracing::info!(
tunnel = %ctx.name,
%local_addr,
@@ -47,7 +39,6 @@ impl TlsTermPlugin {
Ok(Self {
local_addr,
host_header_rewrite: cfg.host_header_rewrite.clone(),
request_headers,
acceptor,
})
}
@@ -73,7 +64,7 @@ impl Plugin for TlsTermPlugin {
let (mut tls_r, mut tls_w) = tokio::io::split(tls);
let mut head = read_http_request_head(&mut tls_r).await?;
apply_request_rewrites(&mut head, &self.host_header_rewrite, &self.request_headers)?;
apply_host_rewrite(&mut head, &self.host_header_rewrite)?;
orbien_core::net::apply_x_forwarded_for(&mut head, &conn.src_addr, "https")?;
local.write_all(&head).await?;
@@ -114,11 +105,11 @@ async fn read_http_request_head<R: AsyncReadExt + Unpin>(stream: &mut R) -> Resu
}
}
fn apply_request_rewrites(
buf: &mut Vec<u8>,
host_rewrite: &str,
extra_headers: &[(String, String)],
) -> Result<()> {
fn apply_host_rewrite(buf: &mut Vec<u8>, host_rewrite: &str) -> Result<()> {
if host_rewrite.is_empty() {
return Ok(());
}
let text = String::from_utf8_lossy(buf);
let mut lines: Vec<String> = text.split_inclusive('\n').map(|s| s.to_string()).collect();
if lines.is_empty() {
@@ -131,27 +122,17 @@ fn apply_request_rewrites(
"\n"
};
if !host_rewrite.is_empty() {
let mut replaced = false;
for line in lines.iter_mut().skip(1) {
let trimmed = line.trim_start_matches([' ', '\t']);
if trimmed.len() >= 5 && trimmed.as_bytes()[..5].eq_ignore_ascii_case(b"host:") {
*line = format!("Host: {host_rewrite}{ending}");
replaced = true;
break;
}
}
if !replaced {
lines.insert(1, format!("Host: {host_rewrite}{ending}"));
let mut replaced = false;
for line in lines.iter_mut().skip(1) {
let trimmed = line.trim_start_matches([' ', '\t']);
if trimmed.len() >= 5 && trimmed.as_bytes()[..5].eq_ignore_ascii_case(b"host:") {
*line = format!("Host: {host_rewrite}{ending}");
replaced = true;
break;
}
}
for (k, v) in extra_headers {
let blank_idx = lines
.iter()
.position(|l| l == "\r\n" || l == "\n")
.unwrap_or(lines.len());
lines.insert(blank_idx, format!("{k}: {v}{ending}"));
if !replaced {
lines.insert(1, format!("Host: {host_rewrite}{ending}"));
}
*buf = lines.join("").into_bytes();
-4
View File
@@ -90,10 +90,6 @@ certFile = "./certs/portal.crt"
keyFile = "./certs/portal.key"
hostHeaderRewrite = "127.0.0.1"
[tunnels.plugin.requestHeaders.set]
X-Forwarded-Proto = "https"
X-Orbien-Tunnel = "portal"
[[tunnels]]
name = "socks5"
protocol = "tcp"
-9
View File
@@ -170,21 +170,12 @@ pub struct PluginConfig {
#[serde(default, rename = "hostHeaderRewrite", alias = "host_header_rewrite")]
pub host_header_rewrite: String,
#[serde(default, rename = "requestHeaders", alias = "request_headers")]
pub request_headers: PluginRequestHeaders,
#[serde(default)]
pub username: String,
#[serde(default)]
pub password: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct PluginRequestHeaders {
#[serde(default)]
pub set: std::collections::HashMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct TunnelTransportConfig {
#[serde(default)]
+1 -1
View File
@@ -3,7 +3,7 @@ mod env;
mod server;
pub use client::{
ClientConfig, ClientTlsConfig, PluginConfig, PluginRequestHeaders, TransportConfig,
ClientConfig, ClientTlsConfig, PluginConfig, TransportConfig,
TunnelConfig, TunnelTransportConfig,
};
pub use env::{contains_env_placeholders, expand_env_placeholders};
-2
View File
@@ -57,8 +57,6 @@ tunnel-tls-term=TLS terminate
tunnel-plugin-local-addr=Local address
tunnel-plugin-cert=Certificate path
tunnel-plugin-key=Key path
tunnel-plugin-request-headers=Extra request headers
tunnel-plugin-request-headers-hint=e.g. X-From: orbien, comma-separated
tunnel-plugin-username=Username
tunnel-plugin-password=Password
tunnel-copied=Copied to clipboard
-2
View File
@@ -55,8 +55,6 @@ tunnel-tls-term=TLS 终止
tunnel-plugin-local-addr=本地地址
tunnel-plugin-cert=证书路径
tunnel-plugin-key=私钥路径
tunnel-plugin-request-headers=追加请求头
tunnel-plugin-request-headers-hint=如 X-From: orbien,多项逗号分隔
tunnel-plugin-username=用户名
tunnel-plugin-password=密码
tunnel-copied=已复制到剪贴板
+2 -38
View File
@@ -1,10 +1,9 @@
use anyhow::{anyhow, Context, Result};
use orbien_client::ClientConfig;
use orbien_core::config::{
parse_host_port, ClientTlsConfig, PluginConfig, PluginRequestHeaders, TransportConfig,
TunnelConfig, TunnelTransportConfig,
parse_host_port, ClientTlsConfig, PluginConfig, TransportConfig, TunnelConfig,
TunnelTransportConfig,
};
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
@@ -298,35 +297,6 @@ fn split_csv(raw: &str) -> Vec<String> {
.collect()
}
fn parse_request_headers(raw: &str) -> PluginRequestHeaders {
let mut set = HashMap::new();
for part in raw.split(',') {
let part = part.trim();
if part.is_empty() {
continue;
}
let Some((name, value)) = part.split_once(':') else {
continue;
};
let name = name.trim();
if name.is_empty() {
continue;
}
set.insert(name.to_string(), value.trim().to_string());
}
PluginRequestHeaders { set }
}
fn format_request_headers(headers: &PluginRequestHeaders) -> String {
let mut names: Vec<&String> = headers.set.keys().collect();
names.sort();
names
.into_iter()
.map(|name| format!("{name}: {}", headers.set[name]))
.collect::<Vec<_>>()
.join(", ")
}
fn is_tls_term_plugin(plugin_type: &str) -> bool {
matches!(plugin_type.trim().to_ascii_lowercase().as_str(), "tls-term")
}
@@ -354,7 +324,6 @@ pub fn tunnel_from_parts(
plugin_cert_file: &str,
plugin_key_file: &str,
plugin_host_rewrite: &str,
plugin_request_headers: &str,
plugin_username: &str,
plugin_password: &str,
) -> Result<TunnelConfig> {
@@ -373,7 +342,6 @@ pub fn tunnel_from_parts(
cert_file: plugin_cert_file.trim().into(),
key_file: plugin_key_file.trim().into(),
host_header_rewrite: plugin_host_rewrite.trim().into(),
request_headers: parse_request_headers(plugin_request_headers),
username: String::new(),
password: String::new(),
})
@@ -466,9 +434,6 @@ pub fn tunnel_to_parts(p: &TunnelConfig) -> TunnelParts {
plugin_host_rewrite: tls_term
.map(|pl| pl.host_header_rewrite.clone())
.unwrap_or_default(),
plugin_request_headers: tls_term
.map(|pl| format_request_headers(&pl.request_headers))
.unwrap_or_default(),
plugin_username: socks5.map(|pl| pl.username.clone()).unwrap_or_default(),
plugin_password: socks5.map(|pl| pl.password.clone()).unwrap_or_default(),
}
@@ -494,7 +459,6 @@ pub struct TunnelParts {
pub plugin_cert_file: String,
pub plugin_key_file: String,
pub plugin_host_rewrite: String,
pub plugin_request_headers: String,
pub plugin_username: String,
pub plugin_password: String,
}
-9
View File
@@ -102,7 +102,6 @@ fn row_to_tunnel(row: &TunnelRow) -> anyhow::Result<orbien_core::config::TunnelC
row.plugin_cert_file.as_str(),
row.plugin_key_file.as_str(),
row.plugin_host_rewrite.as_str(),
row.plugin_request_headers.as_str(),
row.plugin_username.as_str(),
row.plugin_password.as_str(),
)
@@ -130,7 +129,6 @@ fn tunnel_to_row(p: &orbien_core::config::TunnelConfig) -> TunnelRow {
plugin_cert_file: parts.plugin_cert_file.into(),
plugin_key_file: parts.plugin_key_file.into(),
plugin_host_rewrite: parts.plugin_host_rewrite.into(),
plugin_request_headers: parts.plugin_request_headers.into(),
plugin_username: parts.plugin_username.into(),
plugin_password: parts.plugin_password.into(),
}
@@ -359,7 +357,6 @@ fn reset_tunnel_form(ui: &AppWindow) {
ui.set_tunnel_edit_plugin_cert_file("".into());
ui.set_tunnel_edit_plugin_key_file("".into());
ui.set_tunnel_edit_plugin_host_rewrite("".into());
ui.set_tunnel_edit_plugin_request_headers("".into());
ui.set_tunnel_edit_plugin_username("".into());
ui.set_tunnel_edit_plugin_password("".into());
ui.set_tunnel_edit_type_index(0);
@@ -389,7 +386,6 @@ fn fill_tunnel_form(ui: &AppWindow, row: &TunnelRow) {
ui.set_tunnel_edit_plugin_cert_file(row.plugin_cert_file.clone());
ui.set_tunnel_edit_plugin_key_file(row.plugin_key_file.clone());
ui.set_tunnel_edit_plugin_host_rewrite(row.plugin_host_rewrite.clone());
ui.set_tunnel_edit_plugin_request_headers(row.plugin_request_headers.clone());
ui.set_tunnel_edit_plugin_username(row.plugin_username.clone());
ui.set_tunnel_edit_plugin_password(row.plugin_password.clone());
ui.set_tunnel_show_advanced(false);
@@ -473,11 +469,6 @@ fn collect_tunnel_form(ui: &AppWindow) -> TunnelRow {
} else {
"".into()
},
plugin_request_headers: if plugin {
ui.get_tunnel_edit_plugin_request_headers()
} else {
"".into()
},
plugin_username: if is_socks5 {
ui.get_tunnel_edit_plugin_username()
} else {
-2
View File
@@ -122,7 +122,6 @@ export component AppWindow inherits Window {
in-out property <string> tunnel-edit-plugin-cert-file: "";
in-out property <string> tunnel-edit-plugin-key-file: "";
in-out property <string> tunnel-edit-plugin-host-rewrite: "";
in-out property <string> tunnel-edit-plugin-request-headers: "";
in-out property <string> tunnel-edit-plugin-username: "";
in-out property <string> tunnel-edit-plugin-password: "";
in-out property <int> tunnel-edit-type-index: 0;
@@ -261,7 +260,6 @@ export component AppWindow inherits Window {
edit-plugin-cert-file <=> root.tunnel-edit-plugin-cert-file;
edit-plugin-key-file <=> root.tunnel-edit-plugin-key-file;
edit-plugin-host-rewrite <=> root.tunnel-edit-plugin-host-rewrite;
edit-plugin-request-headers <=> root.tunnel-edit-plugin-request-headers;
edit-plugin-username <=> root.tunnel-edit-plugin-username;
edit-plugin-password <=> root.tunnel-edit-plugin-password;
edit-type-index <=> root.tunnel-edit-type-index;
-2
View File
@@ -28,7 +28,6 @@ export component TunnelPage inherits Rectangle {
in-out property <string> edit-plugin-cert-file: "";
in-out property <string> edit-plugin-key-file: "";
in-out property <string> edit-plugin-host-rewrite: "";
in-out property <string> edit-plugin-request-headers: "";
in-out property <string> edit-plugin-username: "";
in-out property <string> edit-plugin-password: "";
in-out property <int> edit-type-index: 0;
@@ -174,7 +173,6 @@ export component TunnelPage inherits Rectangle {
edit-plugin-cert-file <=> root.edit-plugin-cert-file;
edit-plugin-key-file <=> root.edit-plugin-key-file;
edit-plugin-host-rewrite <=> root.edit-plugin-host-rewrite;
edit-plugin-request-headers <=> root.edit-plugin-request-headers;
edit-plugin-username <=> root.edit-plugin-username;
edit-plugin-password <=> root.edit-plugin-password;
edit-type-index <=> root.edit-type-index;
-7
View File
@@ -22,7 +22,6 @@ export component TunnelEditor inherits Rectangle {
in-out property <string> edit-plugin-cert-file: "";
in-out property <string> edit-plugin-key-file: "";
in-out property <string> edit-plugin-host-rewrite: "";
in-out property <string> edit-plugin-request-headers: "";
in-out property <string> edit-plugin-username: "";
in-out property <string> edit-plugin-password: "";
in-out property <int> edit-type-index: 0;
@@ -335,12 +334,6 @@ export component TunnelEditor inherits Rectangle {
model: [Tr.proxy-protocol-off, "v1", "v2"];
current-index <=> root.edit-proxy-protocol-index;
}
if root.is-https && root.use-plugin: FormField {
label: Tr.tunnel-plugin-request-headers;
value <=> root.edit-plugin-request-headers;
placeholder: Tr.tunnel-plugin-request-headers-hint;
}
}
}
}
-1
View File
@@ -18,7 +18,6 @@ export struct TunnelRow {
plugin-cert-file: string,
plugin-key-file: string,
plugin-host-rewrite: string,
plugin-request-headers: string,
plugin-username: string,
plugin-password: string,
}
-21
View File
@@ -85,26 +85,6 @@ keyFile = "/path/to/key.pem"
hostHeaderRewrite = "127.0.0.1"
```
## 示例:TLS 终止时追加请求头
`tls-term` 下,向本地 HTTP 追加自定义请求头:
```toml
[[tunnels]]
name = "https-term"
protocol = "https"
domains = ["web.example.com"]
[tunnels.plugin]
type = "tls-term"
service = "127.0.0.1:80"
certFile = "/path/to/cert.pem"
keyFile = "/path/to/key.pem"
[tunnels.plugin.requestHeaders.set]
X-From = "orbien"
```
## 参数
| 参数 | 必填 | 默认值 | 说明 |
@@ -118,7 +98,6 @@ X-From = "orbien"
| `plugin.certFile` | 否 | | 证书路径;空则临时自签 |
| `plugin.keyFile` | 否 | | 私钥路径;空则临时自签 |
| `plugin.hostHeaderRewrite` | 否 | | 改写转发到本地服务的 Host;空表示不改 |
| `plugin.requestHeaders.set` | 否 | | 向后端追加请求头,键值对 |
| `transport.bandwidth` | 否 | `0` | 带宽上限(Mbps);`0` 表示不限制 |
| `transport.bandwidthLimitSide` | 否 | `client` | 限速端:`client` / `server` |
| `transport.proxyProtocolVersion` | 否 | | PROXY Protocol`v1` / `v2``tls-term` 不可用) |
@@ -88,26 +88,6 @@ keyFile = "/path/to/key.pem"
hostHeaderRewrite = "127.0.0.1"
```
## Example: Add request headers with TLS termination
Under `tls-term`, append custom request headers to local HTTP:
```toml
[[tunnels]]
name = "https-term"
protocol = "https"
domains = ["web.example.com"]
[tunnels.plugin]
type = "tls-term"
service = "127.0.0.1:80"
certFile = "/path/to/cert.pem"
keyFile = "/path/to/key.pem"
[tunnels.plugin.requestHeaders.set]
X-From = "orbien"
```
## Parameters
| Parameter | Required | Default | Description |
@@ -121,7 +101,6 @@ X-From = "orbien"
| `plugin.certFile` | No | | Certificate path; empty uses a temporary self-signed cert |
| `plugin.keyFile` | No | | Private key path; empty uses a temporary self-signed cert |
| `plugin.hostHeaderRewrite` | No | | Rewrite Host when forwarding to the local service; empty means no rewrite |
| `plugin.requestHeaders.set` | No | | Extra request headers to send to the backend; key-value pairs |
| `transport.bandwidth` | No | `0` | Bandwidth cap (Mbps); `0` means unlimited |
| `transport.bandwidthLimitSide` | No | `client` | Limit side: `client` / `server` |
| `transport.proxyProtocolVersion` | No | | PROXY Protocol: `v1` / `v2` (not available with `tls-term`) |