Skip to content

Commit

Permalink
refactor: improve http header performance
Browse files Browse the repository at this point in the history
  • Loading branch information
vicanso committed Mar 23, 2024
1 parent 9a728b2 commit 1d1b237
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 39 deletions.
2 changes: 1 addition & 1 deletion docs/introduction_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
description: Pingap 简述
---

Pingap提供了以toml的形式配置简单易用的反向代理,在pingora中的以下流程中接入调整,实现支持多location代理转发。特性如下:
Pingap是基于[pingora](https://github.com/cloudflare/pingora)开发的,pingora提供了各类模块便于rust开发者使用,但并不方便非rust开发者使用,因此pingap提供了以toml的形式配置简单易用的反向代理,在以下流程中接入调整,实现支持多location代理转发。特性如下:

- 可通过请求的路径与域名筛选对应的location
- 支持HTTP1与HTTP2
Expand Down
30 changes: 9 additions & 21 deletions src/proxy/location.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use super::Upstream;
use crate::{config::LocationConf, utils};
use bytes::Bytes;
use http::HeaderValue;
use http::{HeaderName, HeaderValue};
use regex::Regex;
use snafu::{ResultExt, Snafu};
use std::sync::Arc;
Expand All @@ -11,11 +10,6 @@ use substring::Substring;
pub enum Error {
#[snafu(display("Invalid error {message}"))]
Invalid { message: String },
#[snafu(display("Invalid header value {source}, {value}"))]
InvalidHeaderValue {
value: String,
source: http::header::InvalidHeaderValue,
},
#[snafu(display("Regex {source}, {value}"))]
Regex { value: String, source: regex::Error },
}
Expand Down Expand Up @@ -64,22 +58,16 @@ pub struct Location {
path_selector: PathSelector,
host: String,
reg_rewrite: Option<(Regex, String)>,
// TODO better performance for http header
headers: Option<Vec<(Bytes, Bytes)>>,
proxy_headers: Option<Vec<(Bytes, Bytes)>>,
headers: Option<Vec<(HeaderName, HeaderValue)>>,
proxy_headers: Option<Vec<(HeaderName, HeaderValue)>>,
pub upstream: Arc<Upstream>,
}

fn convert_headers(values: &Option<Vec<String>>) -> Result<Option<Vec<(Bytes, Bytes)>>> {
fn convert_headers(values: &Option<Vec<String>>) -> Result<Option<Vec<(HeaderName, HeaderValue)>>> {
if let Some(header_values) = values {
let mut arr = vec![];
for item in header_values {
if let Some([k, v]) = utils::split_to_two_trim(item, ":") {
let _ =
HeaderValue::from_str(&v).context(InvalidHeaderValueSnafu { value: v.clone() });
arr.push((Bytes::from(k), Bytes::from(v)));
}
}
let arr = utils::convert_headers(header_values).map_err(|err| Error::Invalid {
message: err.to_string(),
})?;
Ok(Some(arr))
} else {
Ok(None)
Expand Down Expand Up @@ -146,11 +134,11 @@ impl Location {
None
}
#[inline]
pub fn get_proxy_headers(&self) -> Option<Vec<(Bytes, Bytes)>> {
pub fn get_proxy_headers(&self) -> Option<Vec<(HeaderName, HeaderValue)>> {
self.proxy_headers.clone()
}
#[inline]
pub fn get_header(&self) -> Option<Vec<(Bytes, Bytes)>> {
pub fn get_header(&self) -> Option<Vec<(HeaderName, HeaderValue)>> {
self.headers.clone()
}
}
9 changes: 4 additions & 5 deletions src/proxy/response_data.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use bytes::Bytes;
use http::StatusCode;
use http::{HeaderName, HeaderValue, StatusCode};
use pingora::{http::ResponseHeader, proxy::Session};

#[derive(Default)]
Expand All @@ -8,17 +8,16 @@ pub struct ResponseData {
pub body: Bytes,
pub max_age: Option<u32>,
pub created_at: Option<u64>,
// TODO better performance for http header
pub headers: Option<Vec<(Bytes, Bytes)>>,
pub headers: Option<Vec<(HeaderName, HeaderValue)>>,
}

impl ResponseData {
pub async fn send(&self, session: &mut Session) -> pingora::Result<usize> {
let mut resp = ResponseHeader::build(self.status, Some(4))?;
resp.insert_header(http::header::CONTENT_LENGTH, self.body.len().to_string())?;
if let Some(headers) = &self.headers {
for (name, value) in headers.iter() {
resp.insert_header(name.to_owned(), value.to_vec())?;
for (name, value) in headers {
resp.insert_header(name.to_owned(), value)?;
}
}
let buf = self.body.clone();
Expand Down
20 changes: 8 additions & 12 deletions src/proxy/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,20 +279,16 @@ impl Server {
hostname: HOST_NAME.to_string(),
})
.unwrap_or_default();
let headers = utils::convert_headers(&[
"Content-Type: application/json; charset=utf-8".to_string(),
"Cache-Control: private, no-store".to_string(),
])
.unwrap_or_default();

ResponseData {
status: StatusCode::OK,
body: Bytes::from(buf),
headers: Some(vec![
(
Bytes::from("Content-Type"),
Bytes::from("application/json; charset=utf-8"),
),
(
Bytes::from("Cache-Control"),
Bytes::from("private, no-store"),
),
]),
headers: Some(headers),
..Default::default()
}
}
Expand Down Expand Up @@ -359,7 +355,7 @@ impl ProxyHttp for Server {
if let Some(arr) = lo.get_proxy_headers() {
for (k, v) in arr {
// v validate for HeaderValue, so always no error
let _ = header.insert_header(k, v.to_vec());
let _ = header.insert_header(k, v);
}
}
let peer = lo
Expand Down Expand Up @@ -398,7 +394,7 @@ impl ProxyHttp for Server {
if let Some(arr) = lo.get_header() {
for (k, v) in arr {
// v validate for HeaderValue, so always no error
let _ = upstream_response.insert_header(k, v.to_vec());
let _ = upstream_response.insert_header(k, v);
}
}
}
Expand Down
32 changes: 32 additions & 0 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
use http::{HeaderName, HeaderValue};
use snafu::{ResultExt, Snafu};
use std::str::FromStr;

#[derive(Debug, Snafu)]
pub enum Error {
InvalidHeaderValue {
value: String,
source: http::header::InvalidHeaderValue,
},
#[snafu(display("Invalid header name {source}, {value}"))]
InvalidHeaderName {
value: String,
source: http::header::InvalidHeaderName,
},
}
type Result<T, E = Error> = std::result::Result<T, E>;

pub fn split_to_two_trim(value: &str, pat: &str) -> Option<[String; 2]> {
let arr: Vec<&str> = value.split(pat).collect();
if arr.len() < 2 {
Expand All @@ -8,6 +26,20 @@ pub fn split_to_two_trim(value: &str, pat: &str) -> Option<[String; 2]> {
Some([arr[0].trim().to_string(), value])
}

pub fn convert_headers(header_values: &[String]) -> Result<Vec<(HeaderName, HeaderValue)>> {
let mut arr = vec![];
for item in header_values {
if let Some([k, v]) = split_to_two_trim(item, ":") {
let name =
HeaderName::from_str(&k).context(InvalidHeaderNameSnafu { value: k.clone() })?;
let value =
HeaderValue::from_str(&v).context(InvalidHeaderValueSnafu { value: v.clone() })?;
arr.push((name, value));
}
}
Ok(arr)
}

const NAME: &str = env!("CARGO_PKG_NAME");
const VERSION: &str = env!("CARGO_PKG_VERSION");

Expand Down

0 comments on commit 1d1b237

Please sign in to comment.