mirror of
https://git.proxmox.com/git/rustc
synced 2026-03-29 06:59:48 +00:00
298 lines
8.1 KiB
Rust
298 lines
8.1 KiB
Rust
#![cfg(unix)]
|
|
|
|
use std::collections::HashMap;
|
|
use std::io::{Cursor, Read};
|
|
use std::time::Duration;
|
|
|
|
use curl::easy::{Easy, List};
|
|
use curl::multi::Multi;
|
|
|
|
macro_rules! t {
|
|
($e:expr) => {
|
|
match $e {
|
|
Ok(e) => e,
|
|
Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
|
|
}
|
|
};
|
|
}
|
|
|
|
use crate::server::Server;
|
|
mod server;
|
|
|
|
#[test]
|
|
fn smoke() {
|
|
let m = Multi::new();
|
|
let mut e = Easy::new();
|
|
|
|
let s = Server::new();
|
|
s.receive(
|
|
"\
|
|
GET / HTTP/1.1\r\n\
|
|
Host: 127.0.0.1:$PORT\r\n\
|
|
Accept: */*\r\n\
|
|
\r\n",
|
|
);
|
|
s.send("HTTP/1.1 200 OK\r\n\r\n");
|
|
|
|
t!(e.url(&s.url("/")));
|
|
let _e = t!(m.add(e));
|
|
while t!(m.perform()) > 0 {
|
|
t!(m.wait(&mut [], Duration::from_secs(1)));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn smoke2() {
|
|
let m = Multi::new();
|
|
|
|
let s1 = Server::new();
|
|
s1.receive(
|
|
"\
|
|
GET / HTTP/1.1\r\n\
|
|
Host: 127.0.0.1:$PORT\r\n\
|
|
Accept: */*\r\n\
|
|
\r\n",
|
|
);
|
|
s1.send("HTTP/1.1 200 OK\r\n\r\n");
|
|
|
|
let s2 = Server::new();
|
|
s2.receive(
|
|
"\
|
|
GET / HTTP/1.1\r\n\
|
|
Host: 127.0.0.1:$PORT\r\n\
|
|
Accept: */*\r\n\
|
|
\r\n",
|
|
);
|
|
s2.send("HTTP/1.1 200 OK\r\n\r\n");
|
|
|
|
let mut e1 = Easy::new();
|
|
t!(e1.url(&s1.url("/")));
|
|
let _e1 = t!(m.add(e1));
|
|
let mut e2 = Easy::new();
|
|
t!(e2.url(&s2.url("/")));
|
|
let _e2 = t!(m.add(e2));
|
|
|
|
while t!(m.perform()) > 0 {
|
|
t!(m.wait(&mut [], Duration::from_secs(1)));
|
|
}
|
|
|
|
let mut done = 0;
|
|
m.messages(|msg| {
|
|
msg.result().unwrap().unwrap();
|
|
done += 1;
|
|
});
|
|
assert_eq!(done, 2);
|
|
}
|
|
|
|
#[test]
|
|
fn upload_lots() {
|
|
use curl::multi::{Events, Socket, SocketEvents};
|
|
|
|
#[derive(Debug)]
|
|
enum Message {
|
|
Timeout(Option<Duration>),
|
|
Wait(Socket, SocketEvents, usize),
|
|
}
|
|
|
|
let mut m = Multi::new();
|
|
let poll = t!(mio::Poll::new());
|
|
let (tx, rx) = mio_extras::channel::channel();
|
|
let tx2 = tx.clone();
|
|
t!(m.socket_function(move |socket, events, token| {
|
|
t!(tx2.send(Message::Wait(socket, events, token)));
|
|
}));
|
|
t!(m.timer_function(move |dur| {
|
|
t!(tx.send(Message::Timeout(dur)));
|
|
true
|
|
}));
|
|
|
|
let s = Server::new();
|
|
s.receive(&format!(
|
|
"\
|
|
PUT / HTTP/1.1\r\n\
|
|
Host: 127.0.0.1:$PORT\r\n\
|
|
Accept: */*\r\n\
|
|
Content-Length: 131072\r\n\
|
|
\r\n\
|
|
{}\n",
|
|
vec!["a"; 128 * 1024 - 1].join("")
|
|
));
|
|
s.send(
|
|
"\
|
|
HTTP/1.1 200 OK\r\n\
|
|
\r\n",
|
|
);
|
|
|
|
let mut data = vec![b'a'; 128 * 1024 - 1];
|
|
data.push(b'\n');
|
|
let mut data = Cursor::new(data);
|
|
let mut list = List::new();
|
|
t!(list.append("Expect:"));
|
|
let mut h = Easy::new();
|
|
t!(h.url(&s.url("/")));
|
|
t!(h.put(true));
|
|
t!(h.read_function(move |buf| Ok(data.read(buf).unwrap())));
|
|
t!(h.in_filesize(128 * 1024));
|
|
t!(h.upload(true));
|
|
t!(h.http_headers(list));
|
|
|
|
t!(poll.register(&rx, mio::Token(0), mio::Ready::all(), mio::PollOpt::level()));
|
|
|
|
let e = t!(m.add(h));
|
|
|
|
assert!(t!(m.perform()) > 0);
|
|
let mut next_token = 1;
|
|
let mut token_map = HashMap::new();
|
|
let mut cur_timeout = None;
|
|
let mut events = mio::Events::with_capacity(128);
|
|
let mut running = true;
|
|
|
|
while running {
|
|
let n = t!(poll.poll(&mut events, cur_timeout));
|
|
|
|
if n == 0 && t!(m.timeout()) == 0 {
|
|
running = false;
|
|
}
|
|
|
|
for event in events.iter() {
|
|
while event.token() == mio::Token(0) {
|
|
match rx.try_recv() {
|
|
Ok(Message::Timeout(dur)) => cur_timeout = dur,
|
|
Ok(Message::Wait(socket, events, token)) => {
|
|
let evented = mio::unix::EventedFd(&socket);
|
|
if events.remove() {
|
|
token_map.remove(&token).unwrap();
|
|
} else {
|
|
let mut e = mio::Ready::empty();
|
|
if events.input() {
|
|
e |= mio::Ready::readable();
|
|
}
|
|
if events.output() {
|
|
e |= mio::Ready::writable();
|
|
}
|
|
if token == 0 {
|
|
let token = next_token;
|
|
next_token += 1;
|
|
t!(m.assign(socket, token));
|
|
token_map.insert(token, socket);
|
|
t!(poll.register(
|
|
&evented,
|
|
mio::Token(token),
|
|
e,
|
|
mio::PollOpt::level()
|
|
));
|
|
} else {
|
|
t!(poll.reregister(
|
|
&evented,
|
|
mio::Token(token),
|
|
e,
|
|
mio::PollOpt::level()
|
|
));
|
|
}
|
|
}
|
|
}
|
|
Err(_) => break,
|
|
}
|
|
}
|
|
|
|
if event.token() == mio::Token(0) {
|
|
continue;
|
|
}
|
|
|
|
let token = event.token();
|
|
let socket = token_map[&token.into()];
|
|
let mut e = Events::new();
|
|
if event.readiness().is_readable() {
|
|
e.input(true);
|
|
}
|
|
if event.readiness().is_writable() {
|
|
e.output(true);
|
|
}
|
|
if mio::unix::UnixReady::from(event.readiness()).is_error() {
|
|
e.error(true);
|
|
}
|
|
let remaining = t!(m.action(socket, &e));
|
|
if remaining == 0 {
|
|
running = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut done = 0;
|
|
m.messages(|m| {
|
|
m.result().unwrap().unwrap();
|
|
done += 1;
|
|
});
|
|
assert_eq!(done, 1);
|
|
|
|
let mut e = t!(m.remove(e));
|
|
assert_eq!(t!(e.response_code()), 200);
|
|
}
|
|
|
|
// Tests passing raw file descriptors to Multi::wait. The test is limited to Linux only as the
|
|
// semantics of the underlying poll(2) system call used by curl apparently differ on other
|
|
// platforms, making the test fail.
|
|
#[cfg(target_os = "linux")]
|
|
#[test]
|
|
fn waitfds() {
|
|
use curl::multi::WaitFd;
|
|
use std::fs::File;
|
|
use std::os::unix::io::AsRawFd;
|
|
|
|
let filenames = ["/dev/null", "/dev/zero", "/dev/urandom"];
|
|
let files: Vec<File> = filenames
|
|
.iter()
|
|
.map(|filename| File::open(filename).unwrap())
|
|
.collect();
|
|
let mut waitfds: Vec<WaitFd> = files
|
|
.iter()
|
|
.map(|f| {
|
|
let mut waitfd = WaitFd::new();
|
|
waitfd.set_fd(f.as_raw_fd());
|
|
waitfd.poll_on_read(true);
|
|
waitfd
|
|
})
|
|
.collect();
|
|
|
|
let m = Multi::new();
|
|
let events = t!(m.wait(&mut waitfds, Duration::from_secs(1)));
|
|
assert_eq!(events, 3);
|
|
for waitfd in waitfds {
|
|
assert!(waitfd.received_read());
|
|
}
|
|
}
|
|
|
|
// Tests passing raw file descriptors to Multi::wait. The test is limited to Linux only as the
|
|
// semantics of the underlying poll(2) system call used by curl apparently differ on other
|
|
// platforms, making the test fail.
|
|
#[cfg(feature = "poll_7_68_0")]
|
|
#[cfg(target_os = "linux")]
|
|
#[test]
|
|
fn pollfds() {
|
|
use curl::multi::WaitFd;
|
|
use std::fs::File;
|
|
use std::os::unix::io::AsRawFd;
|
|
|
|
let filenames = ["/dev/null", "/dev/zero", "/dev/urandom"];
|
|
let files: Vec<File> = filenames
|
|
.iter()
|
|
.map(|filename| File::open(filename).unwrap())
|
|
.collect();
|
|
let mut waitfds: Vec<WaitFd> = files
|
|
.iter()
|
|
.map(|f| {
|
|
let mut waitfd = WaitFd::new();
|
|
waitfd.set_fd(f.as_raw_fd());
|
|
waitfd.poll_on_read(true);
|
|
waitfd
|
|
})
|
|
.collect();
|
|
|
|
let m = Multi::new();
|
|
let events = t!(m.poll(&mut waitfds, Duration::from_secs(1)));
|
|
assert_eq!(events, 3);
|
|
for waitfd in waitfds {
|
|
assert!(waitfd.received_read());
|
|
}
|
|
}
|