Skip to content

Commit a6a01db

Browse files
authored
Merge branch 'main' into fix_swoole_error
2 parents fe91f2d + 8b7bda5 commit a6a01db

227 files changed

Lines changed: 9115 additions & 430812 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

frameworks/actix-h2c/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "httparena-actix-h2c"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
actix-web = { version = "4.5" }
8+
serde = { version = "1", features = ["derive"] }
9+
serde_json = "1"
10+
num_cpus = "1"
11+
futures-util = "0.3"
12+
13+
[profile.release]
14+
opt-level = 3
15+
codegen-units = 1
16+
lto = "thin"
17+
panic = "abort"

frameworks/actix-h2c/Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM rust:1.94 AS build
2+
WORKDIR /app
3+
COPY Cargo.toml .
4+
RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release && rm -rf src/ target/release/httparena-actix-h2c* target/release/deps/httparena_actix_h2c*
5+
COPY src ./src
6+
RUN RUSTFLAGS="-C target-cpu=native" cargo build --release
7+
8+
FROM debian:bookworm-slim
9+
COPY --from=build /app/target/release/httparena-actix-h2c /server
10+
EXPOSE 8082
11+
CMD ["/server"]

frameworks/actix-h2c/meta.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"display_name": "actix",
3+
"language": "Rust",
4+
"type": "production",
5+
"engine": "actix",
6+
"description": "Actix-web 4 h2c-only listener on port 8082 using bind_auto_h2c. A middleware rejects HTTP/1.1 requests so the port serves HTTP/2 cleartext prior-knowledge exclusively. Handlers share the same shape as the main actix entry (serde_json per request).",
7+
"repo": "https://github.com/actix/actix-web",
8+
"enabled": true,
9+
"tests": [
10+
"baseline-h2c",
11+
"json-h2c"
12+
],
13+
"maintainers": []
14+
}

frameworks/actix-h2c/src/main.rs

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
fn cgroup_cpus() -> usize {
2+
std::fs::read_to_string("/sys/fs/cgroup/cpu.max")
3+
.ok()
4+
.and_then(|s| {
5+
let mut parts = s.trim().split(' ');
6+
let quota = parts.next()?;
7+
if quota == "max" { return None; }
8+
let period: usize = parts.next()?.parse().ok()?;
9+
let q: usize = quota.parse().ok()?;
10+
let cpus = q / period;
11+
if cpus >= 1 { Some(cpus) } else { None }
12+
})
13+
.unwrap_or_else(num_cpus::get)
14+
}
15+
16+
use actix_web::dev::{Service, ServiceRequest, ServiceResponse};
17+
use actix_web::http::header::{HeaderValue, SERVER};
18+
use actix_web::http::Version;
19+
use actix_web::{web, App, HttpResponse, HttpServer};
20+
use futures_util::future::{ready, Either};
21+
use serde::{Deserialize, Serialize};
22+
use std::io;
23+
24+
static SERVER_HDR: HeaderValue = HeaderValue::from_static("actix");
25+
26+
#[derive(Deserialize)]
27+
struct BaselineQuery {
28+
a: Option<i64>,
29+
b: Option<i64>,
30+
}
31+
32+
#[derive(Deserialize)]
33+
struct JsonQuery {
34+
m: Option<i64>,
35+
}
36+
37+
#[derive(Deserialize, Clone)]
38+
struct Rating {
39+
score: i64,
40+
count: i64,
41+
}
42+
43+
#[derive(Deserialize, Clone)]
44+
struct DatasetItem {
45+
id: i64,
46+
name: String,
47+
category: String,
48+
price: i64,
49+
quantity: i64,
50+
active: bool,
51+
tags: Vec<String>,
52+
rating: Rating,
53+
}
54+
55+
#[derive(Serialize, Clone)]
56+
struct RatingOut {
57+
score: i64,
58+
count: i64,
59+
}
60+
61+
#[derive(Serialize, Clone)]
62+
struct ProcessedItem {
63+
id: i64,
64+
name: String,
65+
category: String,
66+
price: i64,
67+
quantity: i64,
68+
active: bool,
69+
tags: Vec<String>,
70+
rating: RatingOut,
71+
total: i64,
72+
}
73+
74+
#[derive(Serialize)]
75+
struct JsonResponse {
76+
items: Vec<ProcessedItem>,
77+
count: usize,
78+
}
79+
80+
struct AppState {
81+
dataset: Vec<DatasetItem>,
82+
}
83+
84+
fn build_json_body(dataset: &[DatasetItem], count: usize, m: i64) -> Vec<u8> {
85+
let count = count.min(dataset.len());
86+
let items: Vec<ProcessedItem> = dataset[..count]
87+
.iter()
88+
.map(|d| ProcessedItem {
89+
id: d.id,
90+
name: d.name.clone(),
91+
category: d.category.clone(),
92+
price: d.price,
93+
quantity: d.quantity,
94+
active: d.active,
95+
tags: d.tags.clone(),
96+
rating: RatingOut {
97+
score: d.rating.score,
98+
count: d.rating.count,
99+
},
100+
total: d.price * d.quantity * m,
101+
})
102+
.collect();
103+
let resp = JsonResponse { count, items };
104+
serde_json::to_vec(&resp).unwrap_or_default()
105+
}
106+
107+
fn load_dataset() -> Vec<DatasetItem> {
108+
let path = std::env::var("DATASET_PATH").unwrap_or_else(|_| "/data/dataset.json".to_string());
109+
match std::fs::read_to_string(&path) {
110+
Ok(data) => serde_json::from_str(&data).unwrap_or_default(),
111+
Err(_) => Vec::new(),
112+
}
113+
}
114+
115+
async fn baseline2(query: web::Query<BaselineQuery>) -> HttpResponse {
116+
let sum = query.a.unwrap_or(0) + query.b.unwrap_or(0);
117+
HttpResponse::Ok()
118+
.insert_header((SERVER, SERVER_HDR.clone()))
119+
.content_type("text/plain")
120+
.body(sum.to_string())
121+
}
122+
123+
async fn json_endpoint(
124+
state: web::Data<AppState>,
125+
path: web::Path<usize>,
126+
query: web::Query<JsonQuery>,
127+
) -> HttpResponse {
128+
let count = path.into_inner().min(state.dataset.len());
129+
let m = query.m.unwrap_or(1);
130+
let body = build_json_body(&state.dataset, count, m);
131+
HttpResponse::Ok()
132+
.insert_header((SERVER, SERVER_HDR.clone()))
133+
.content_type("application/json")
134+
.body(body)
135+
}
136+
137+
#[actix_web::main]
138+
async fn main() -> io::Result<()> {
139+
let dataset = load_dataset();
140+
let state = web::Data::new(AppState { dataset });
141+
let workers = cgroup_cpus();
142+
143+
HttpServer::new(move || {
144+
App::new()
145+
.app_data(state.clone())
146+
// bind_auto_h2c accepts H1 and h2c on the same socket; this
147+
// middleware short-circuits H1 requests with 400 so the port
148+
// serves h2c exclusively from the app's perspective. The
149+
// validate.sh anti-cheat requires port 8082 to refuse HTTP/1.1.
150+
.wrap_fn(|req: ServiceRequest, srv| {
151+
if req.request().version() == Version::HTTP_11 {
152+
let (r, _pl) = req.into_parts();
153+
let resp = HttpResponse::BadRequest()
154+
.content_type("text/plain")
155+
.body("HTTP/2 cleartext prior-knowledge required");
156+
Either::Left(ready(Ok(ServiceResponse::new(r, resp))))
157+
} else {
158+
Either::Right(srv.call(req))
159+
}
160+
})
161+
.route("/baseline2", web::get().to(baseline2))
162+
.route("/json/{count}", web::get().to(json_endpoint))
163+
})
164+
.workers(workers)
165+
.bind_auto_h2c("0.0.0.0:8082")?
166+
.run()
167+
.await
168+
}

frameworks/aleph/src/aleph_bench/core.clj

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,6 @@
135135
compression-body (when large-dataset
136136
(let [items (mapv #(process-item % 1) large-dataset)]
137137
(json/write-value-as-string {:items items :count (clojure.core/count items)})))
138-
static-cache (let [dir (io/file static-dir)]
139-
(when (.isDirectory dir)
140-
(into {}
141-
(map (fn [^java.io.File f]
142-
[(.getName f)
143-
{:ct (get-content-type (.getName f))
144-
:body (java.nio.file.Files/readAllBytes (.toPath f))}]))
145-
(.listFiles dir))))
146138
adapter (->NextJdbcAdapter)
147139
sqlite-tag-parser #(json/read-value % json/keyword-keys-object-mapper)
148140
sqlite-active #(== 1 (long %))
@@ -229,9 +221,11 @@
229221
dfd)
230222
empty-db-response)))]
231223
"/static/:filename" [(GET (fn [req]
232-
(let [name (get-in req [:params :filename])]
233-
(if-let [entry (and static-cache (get static-cache name))]
234-
{:status 200 :headers {hdr-ct (:ct entry) hdr-server server-name} :body (:body entry)}
224+
(let [name (get-in req [:params :filename])
225+
path (str "/data" (:uri req))
226+
f (io/file path)]
227+
(if (.isFile f)
228+
{:status 200 :headers {hdr-ct (get-content-type name) hdr-server server-name} :body (java.io.FileInputStream. path)}
235229
{:status 404 :body not-found-body}))))]
236230
"/" [(GET (fn [_] (text-response server-name)))]})]
237231

frameworks/bottle/Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM python:3.13-slim
2+
WORKDIR /app
3+
COPY requirements.txt .
4+
RUN pip install --no-cache-dir -r requirements.txt
5+
COPY . .
6+
EXPOSE 8080 8081
7+
CMD [ "python3", "launcher.py", "gunicorn", "--config", "gunicorn_conf.py", "app:app" ]

0 commit comments

Comments
 (0)