Skip to content

Commit d64d955

Browse files
committed
Rust: Add test cases for requests through hyper + http.
1 parent 78d0c5c commit d64d955

File tree

3 files changed

+126
-0
lines changed

3 files changed

+126
-0
lines changed

rust/ql/test/library-tests/dataflow/sources/TaintSources.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@
1919
| test.rs:72:26:72:37 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
2020
| test.rs:75:26:75:37 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
2121
| test.rs:78:24:78:35 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
22+
| test.rs:193:16:193:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs. |
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
qltest_cargo_check: true
22
qltest_dependencies:
33
- reqwest = { version = "0.12.9", features = ["blocking"] }
4+
- hyper = { version = "1.5.2", features = ["full"] }
5+
- hyper-util = { version = "0.1.10", features = ["full"] }
6+
- http-body-util = { version = "0.1.2" }
7+
- http = { version = "1.2.0" }
8+
- tokio = { version = "1.43.0", features = ["full"] }
9+
- futures = { version = "0.3" }

rust/ql/test/library-tests/dataflow/sources/test.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,122 @@ async fn test_reqwest() -> Result<(), reqwest::Error> {
8282

8383
Ok(())
8484
}
85+
86+
use std::io::Write;
87+
use http_body_util::BodyExt;
88+
89+
async fn test_hyper_http(case: i64) -> Result<(), Box<dyn std::error::Error>> {
90+
// using http + hyper libs to fetch a web page
91+
let address = "example.com:80";
92+
let url = "http://example.com/";
93+
94+
// create the connection
95+
println!("connecting to {}...", address);
96+
let stream = tokio::net::TcpStream::connect(address).await?;
97+
let io = hyper_util::rt::TokioIo::new(stream);
98+
let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await?;
99+
100+
// drive the HTTP connection
101+
tokio::task::spawn(async move {
102+
conn.await.expect("connection failed");
103+
});
104+
105+
// make the request
106+
println!("sending request...");
107+
let request = http::Request::builder().uri(url).body(String::from(""))?;
108+
let mut response = sender.send_request(request).await?; // $ MISSING: Alert[rust/summary/taint-sources]
109+
sink(&response); // $ MISSING: hasTaintFlow
110+
111+
if !response.status().is_success() {
112+
return Err("request failed".into())
113+
}
114+
115+
match case {
116+
1 => {
117+
sink(response.body()); // $ MISSING: hasTaintFlow
118+
sink(response.body_mut()); // $ MISSING: hasTaintFlow
119+
120+
let body = response.into_body();
121+
sink(&body); // $ MISSING: hasTaintFlow
122+
123+
println!("awaiting response...");
124+
let data = body.collect().await?;
125+
sink(&data); // $ MISSING: hasTaintFlow
126+
127+
let bytes = data.to_bytes();
128+
println!("bytes = {:?}", &bytes);
129+
sink(bytes); // $ MISSING: hasTaintFlow
130+
}
131+
2 => {
132+
println!("streaming response...");
133+
while let Some(frame) = response.frame().await {
134+
if let Some(data) = frame?.data_ref() {
135+
std::io::stdout().write_all(data);
136+
137+
sink(data); // $ MISSING: hasTaintFlow
138+
sink(data[0]); // $ MISSING: hasTaintFlow
139+
for byte in data {
140+
sink(byte); // $ MISSING: hasTaintFlow
141+
}
142+
}
143+
}
144+
}
145+
3 => {
146+
let headers = response.headers();
147+
148+
if headers.contains_key(http::header::CONTENT_TYPE) {
149+
println!("CONTENT_TYPE = {}", response.headers()[http::header::CONTENT_TYPE].to_str().unwrap());
150+
sink(&headers[http::header::CONTENT_TYPE]); // $ MISSING: hasTaintFlow
151+
sink(headers[http::header::CONTENT_TYPE].to_str().unwrap()); // $ MISSING: hasTaintFlow
152+
sink(headers[http::header::CONTENT_TYPE].as_bytes()); // $ MISSING: hasTaintFlow
153+
sink(headers.get(http::header::CONTENT_TYPE).unwrap()); // $ MISSING: hasTaintFlow
154+
}
155+
156+
if headers.contains_key("Content-type") {
157+
println!("Content-type = {}", response.headers().get("Content-type").unwrap().to_str().unwrap());
158+
sink(headers.get("Content-type").unwrap()); // $ MISSING: hasTaintFlow
159+
sink(headers.get("Content-type").unwrap().to_str().unwrap()); // $ MISSING: hasTaintFlow
160+
sink(headers.get("Content-type").unwrap().as_bytes()); // $ MISSING: hasTaintFlow
161+
sink(&headers["Content-type"]); // $ MISSING: hasTaintFlow
162+
}
163+
164+
if headers.contains_key(http::header::COOKIE) {
165+
sink(response.headers().get(http::header::COOKIE)); // $ MISSING: hasTaintFlow
166+
for cookie in headers.get_all(http::header::COOKIE) {
167+
println!("cookie = {}", cookie.to_str().unwrap());
168+
sink(cookie); // $ MISSING: hasTaintFlow
169+
sink(cookie.to_str().unwrap()); // $ MISSING: hasTaintFlow
170+
}
171+
}
172+
173+
let (parts, body) = response.into_parts();
174+
175+
if parts.headers.contains_key(http::header::CONTENT_TYPE) {
176+
println!("CONTENT_TYPE = {}", parts.headers[http::header::CONTENT_TYPE].to_str().unwrap());
177+
sink(&parts.headers[http::header::CONTENT_TYPE]); // $ MISSING: hasTaintFlow
178+
sink(parts.headers[http::header::CONTENT_TYPE].to_str().unwrap()); // $ MISSING: hasTaintFlow
179+
sink(parts.headers[http::header::CONTENT_TYPE].as_bytes()); // $ MISSING: hasTaintFlow
180+
sink(parts.headers.get(http::header::CONTENT_TYPE).unwrap()); // $ MISSING: hasTaintFlow
181+
}
182+
183+
sink(body); // $ MISSING: hasTaintFlow
184+
}
185+
_ => {}
186+
}
187+
188+
Ok(())
189+
}
190+
191+
#[tokio::main]
192+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
193+
let case = std::env::args().nth(1).unwrap_or(String::from("1")).parse::<i64>().unwrap(); // $ Alert[rust/summary/taint-sources]
194+
195+
println!("test_hyper_http...");
196+
match futures::executor::block_on(test_hyper_http(case)) {
197+
Ok(_) => println!("complete"),
198+
Err(e) => println!("error: {}", e),
199+
}
200+
println!("");
201+
202+
Ok(())
203+
}

0 commit comments

Comments
 (0)