Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
arloor committed Oct 22, 2024
2 parents d9fdeeb + 855e666 commit b479d65
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 96 deletions.
8 changes: 3 additions & 5 deletions .vscode/reverse_proxy.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
default_host:
- location: /v1/chat/completions
upstream:
scheme_and_authority: https://models.inference.ai.azure.com
replacement: /chat/completions
other_host:
url_base: https://models.inference.ai.azure.com/chat/completions
127.0.0.1:
- location: / # 默认为 /
upstream:
scheme_and_authority: https://www.baidu.com
replacement: / # 默认为 /
url_base: https://www.baidu.com/ # 当location以/结尾时,url_base也必须以/结尾
version: H1 # 可以填H1、H2、AUTO,默认为AUTO
40 changes: 21 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ Options:
便捷反向代理配置
例如:--append-upstream-url=https://cdnjs.cloudflare.com
则访问 https://your_domain/https://cdnjs.cloudflare.com 会被代理到 https://cdnjs.cloudflare.com
注意!这个url的PATH需要为空
-h, --help
Print help
```
Expand All @@ -122,9 +121,8 @@ curl https://ip.im/info -U "username:password" -x https://localhost:7788 --pro
YOUR_DOMAIN:
- location: / # 默认为 /
upstream:
scheme_and_authority: https://www.baidu.com # 末尾不包含 /
replacement: / # 默认为 /
version: AUTO # 可以填H1、H2、AUTO,默认为AUTO
url_base: https://www.baidu.com/ # 当location以/结尾时,url_base也必须以/结尾
version: H1 # 可以填H1、H2、AUTO,默认为AUTO
```
> 如果 `YOUR_DOMAIN``default_host` 则对所有的域名生效
Expand All @@ -133,41 +131,45 @@ YOUR_DOMAIN:
在github原始url前加上`https://YOUR_DOMAIN`,以便在国内访问raw.githubusercontent.com、github.com和gist.githubusercontent.com
增加 `--enable-github-proxy`,或手动置顶下面的反向代理配置文件:
启动参数中增加 `--enable-github-proxy`,相当于以下配置:
```yaml
default_host:
- location: /https://gist.githubusercontent.com
upstream:
scheme_and_authority: https://gist.githubusercontent.com
replacement:
url_base: https://gist.githubusercontent.com
- location: /https://gist.github.com
upstream:
scheme_and_authority: https://gist.github.com
replacement:
url_base: https://gist.github.com
- location: /https://github.com
upstream:
scheme_and_authority: https://github.com
replacement:
url_base: https://github.com
- location: /https://objects.githubusercontent.com
upstream:
scheme_and_authority: https://objects.githubusercontent.com
replacement:
url_base: https://objects.githubusercontent.com
- location: /https://raw.githubusercontent.com
upstream:
scheme_and_authority: https://raw.githubusercontent.com
replacement:
url_base: https://raw.githubusercontent.com
```
#### 例子2: 反向代理https://cdnjs.cloudflare.com
启动参数中增加 `--append-upstream-url=https://cdnjs.cloudflare.com`,相当于以下配置:
```yaml
default_host:
- location: /https://cdnjs.cloudflare.com
upstream:
url_base: https://cdnjs.cloudflare.com
```
#### 例子2: 改写Github Models的url为openai api的url格式
#### 例子3: 改写Github Models的url为openai api的url格式
```yaml
default_host:
- location: /v1/chat/completions
upstream:
scheme_and_authority: https://models.inference.ai.azure.com
replacement: /chat/completions
url_base: https://models.inference.ai.azure.com/chat/completions
```
## 可观测
Expand Down
104 changes: 52 additions & 52 deletions rust_http_proxy/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::tls_helper::tls_config;
use crate::{DynError, IDLE_TIMEOUT, REFRESH_INTERVAL};

pub(crate) const DEFAULT_HOST: &str = "default_host";
const GITHUB_SCHEME_AND_AUTHORITY: [&str; 5] = [
const GITHUB_URL_BASE: [&str; 5] = [
"https://github.com",
"https://gist.githubusercontent.com",
"https://gist.github.com",
Expand Down Expand Up @@ -187,7 +187,7 @@ fn parse_reverse_proxy_config(
None => HashMap::new(),
};
if enable_github_proxy {
GITHUB_SCHEME_AND_AUTHORITY.iter().for_each(|domain| {
GITHUB_URL_BASE.iter().for_each(|domain| {
append_upstream_url.push((*domain).to_owned());
});
}
Expand All @@ -204,18 +204,17 @@ fn parse_reverse_proxy_config(
return;
}
let upstream_url_tmp = upstream_url.to_string();
let scheme_and_authority =
let upstream_url_base =
truncate_string(upstream_url_tmp.as_str(), upstream_url.path().len());
let path = match upstream_url.path() {
"/" => "",
other => other,
};

vec.push(LocationConfig {
location: "/".to_string() + scheme_and_authority + path,
location: "/".to_string() + upstream_url_base + path,
upstream: crate::reverse::Upstream {
scheme_and_authority: (*scheme_and_authority).to_owned(),
replacement: path.to_string(),
url_base: (*upstream_url_base).to_owned() + path,
version: crate::reverse::Version::Auto,
},
});
Expand All @@ -230,12 +229,55 @@ fn parse_reverse_proxy_config(
locations
.iter_mut()
.for_each(|(_, reverse_proxy_configs)| reverse_proxy_configs.sort());
for ele in &locations {
for location_config in ele.1 {
if location_config.location.is_empty() {
return Err("location is empty, location should start with '/'".into());
}
if location_config.location.ends_with('/')
&& !location_config.upstream.url_base.ends_with('/')
{
return Err(format!(
"location ends with '/', but upstream_url_base not: {}",
location_config.upstream.url_base
)
.into());
}
match location_config.upstream.url_base.parse::<Uri>() {
Ok(upstream_url_base) => {
if upstream_url_base.scheme().is_none() {
return Err(format!(
"wrong upstream_url_base: {} --- scheme is empty",
location_config.upstream.url_base
)
.into());
}
if upstream_url_base.authority().is_none() {
return Err(format!(
"wrong upstream_url_base: {} --- authority is empty",
location_config.upstream.url_base
)
.into());
}
if upstream_url_base.query().is_some() {
return Err(format!(
"wrong upstream_url_base: {} --- query is not empty",
location_config.upstream.url_base
)
.into());
}
}
Err(e) => {
return Err(format!("parse upstream upstream_url_base error:{}", e).into())
}
}
}
}
let mut redirect_bachpaths = Vec::<RedirectBackpaths>::new();
for (host, locations) in &locations {
for location in locations {
redirect_bachpaths.push(RedirectBackpaths {
redirect_url: location.upstream.scheme_and_authority.clone()
+ location.upstream.replacement.as_str(),
redirect_url: location.upstream.url_base.clone(),
host: host.clone(),
location: location.location.clone(),
});
Expand Down Expand Up @@ -275,47 +317,6 @@ pub(crate) fn load_config() -> Result<Config, DynError> {
}
info!("hostname seems to be {}", param.hostname);
let config = Config::try_from(param)?;
for ele in &config.reverse_proxy_config.locations {
for location_config in ele.1 {
match location_config.upstream.scheme_and_authority.parse::<Uri>() {
Ok(scheme_and_authority) => {
if scheme_and_authority.scheme().is_none() {
return Err(format!(
"wrong scheme_and_authority: {} --- scheme is empty",
location_config.upstream.scheme_and_authority
)
.into());
}
if scheme_and_authority.authority().is_none() {
return Err(format!(
"wrong scheme_and_authority: {} --- authority is empty",
location_config.upstream.scheme_and_authority
)
.into());
}
if scheme_and_authority.path() != "/"
|| location_config.upstream.scheme_and_authority.ends_with("/")
{
return Err(format!(
"wrong scheme_and_authority: {} --- path is not empty",
location_config.upstream.scheme_and_authority
)
.into());
}
if scheme_and_authority.query().is_some() {
return Err(format!(
"wrong scheme_and_authority: {} --- query is not empty",
location_config.upstream.scheme_and_authority
)
.into());
}
}
Err(e) => {
return Err(format!("parse upstream scheme_and_authority error:{}", e).into())
}
}
}
}
log_config(&config);
info!("auto close connection after idle for {:?}", IDLE_TIMEOUT);
Ok(config)
Expand Down Expand Up @@ -344,13 +345,12 @@ fn log_config(config: &Config) {
.for_each(|reverse_proxy_config| {
for ele in reverse_proxy_config.1 {
info!(
" {:<70} -> {}{}**",
" {:<70} -> {}**",
format!(
"http(s)://{}:port{}**",
reverse_proxy_config.0, ele.location
),
ele.upstream.scheme_and_authority,
ele.upstream.replacement
ele.upstream.url_base,
);
}
});
Expand Down
22 changes: 5 additions & 17 deletions rust_http_proxy/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,7 @@ impl ProxyHandler {
client: client_socket_addr.ip().to_canonical().to_string(),
origin: origin_scheme_host_port.to_string()
+ location_config.location.as_str(),
upstream: location_config.upstream.scheme_and_authority.clone()
+ location_config.upstream.replacement.as_str(),
upstream: location_config.upstream.url_base.clone(),
}))
.inc();
self.metrics
Expand Down Expand Up @@ -483,19 +482,11 @@ fn build_upstream_req(
Some(path_and_query) => path_and_query.as_str(),
None => "",
};
let url = format!(
"{}{}",
location_config.upstream.scheme_and_authority.clone(),
location_config.upstream.replacement.clone()
+ &path_and_query[location_config.location.len()..]
);
let url = location_config.upstream.url_base.clone()
+ &path_and_query[location_config.location.len()..];

let mut builder = Request::builder().method(method).uri(url).version(
if !location_config
.upstream
.scheme_and_authority
.starts_with("https:")
{
if !location_config.upstream.url_base.starts_with("https:") {
match location_config.upstream.version {
reverse::Version::H1 => Version::HTTP_11,
reverse::Version::H2 => Version::HTTP_2,
Expand Down Expand Up @@ -658,10 +649,7 @@ fn ensure_absolute(
.parse::<Uri>()
.map_err(|e| io::Error::new(ErrorKind::InvalidData, e))?;
if redirect_url.scheme_str().is_none() {
Ok(format!(
"{}{}",
context.upstream.scheme_and_authority, location
))
Ok(format!("{}{}", context.upstream.url_base, location))
} else {
Ok(location.to_string())
}
Expand Down
4 changes: 1 addition & 3 deletions rust_http_proxy/src/reverse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ impl std::cmp::Ord for LocationConfig {

#[derive(Serialize, Deserialize, Eq, PartialEq, PartialOrd)]
pub(crate) struct Upstream {
pub(crate) scheme_and_authority: String, // https://google.com
#[serde(default = "root")]
pub(crate) replacement: String, // /
pub(crate) url_base: String, // https://google.com
#[serde(default = "default_version")]
pub(crate) version: Version,
}
Expand Down

0 comments on commit b479d65

Please sign in to comment.