Skip to content

Commit 4a656fd

Browse files
added support for unix sockets (#346)
Co-authored-by: ggeorgiev_ <[email protected]>
1 parent 272a620 commit 4a656fd

File tree

3 files changed

+86
-15
lines changed

3 files changed

+86
-15
lines changed

curl-sys/build.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ fn main() {
235235
.file("curl/lib/vauth/vauth.c");
236236
}
237237

238+
if !windows {
239+
cfg.define("USE_UNIX_SOCKETS", None)
240+
.define("HAVE_SYS_UN_H", None);
241+
}
242+
238243
// Configure TLS backend. Since Cargo does not support mutually exclusive
239244
// features, make sure we only compile one vtls.
240245
if cfg!(feature = "mesalink") {

tests/easy.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -801,9 +801,30 @@ b",
801801
t!(h.borrow().perform());
802802
}
803803

804-
// Stupid test to check if unix_socket is callable
804+
#[cfg(not(windows))]
805805
#[test]
806806
fn check_unix_socket() {
807+
let s = Server::new_unix();
808+
s.receive(
809+
"\
810+
POST / HTTP/1.1\r\n\
811+
Host: localhost\r\n\
812+
Accept: */*\r\n\
813+
Content-Length: 5\r\n\
814+
Content-Type: application/x-www-form-urlencoded\r\n\
815+
\r\n\
816+
data\n",
817+
);
818+
s.send(
819+
"\
820+
HTTP/1.1 200 OK\r\n\
821+
\r\n",
822+
);
823+
807824
let mut h = handle();
808-
drop(h.unix_socket("/var/something.socks"));
825+
t!(h.unix_socket(s.path()));
826+
t!(h.url(&s.url("/")));
827+
t!(h.post(true));
828+
t!(h.post_fields_copy(b"data\n"));
829+
t!(h.perform());
809830
}

tests/server/mod.rs

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ use std::collections::HashSet;
44
use std::io::prelude::*;
55
use std::io::BufReader;
66
use std::net::{SocketAddr, TcpListener, TcpStream};
7+
use std::path::PathBuf;
78
use std::sync::mpsc::{channel, Receiver, Sender};
89
use std::thread;
910

1011
pub struct Server {
1112
messages: Option<Sender<Message>>,
12-
addr: SocketAddr,
13+
addr: Addr,
1314
thread: Option<thread::JoinHandle<()>>,
1415
}
1516

@@ -18,8 +19,13 @@ enum Message {
1819
Write(String),
1920
}
2021

21-
fn run(listener: &TcpListener, rx: &Receiver<Message>) {
22-
let mut socket = BufReader::new(listener.accept().unwrap().0);
22+
enum Addr {
23+
Tcp(SocketAddr),
24+
Unix(PathBuf),
25+
}
26+
27+
fn run(stream: impl Read + Write, rx: &Receiver<Message>) {
28+
let mut socket = BufReader::new(stream);
2329
for msg in rx.iter() {
2430
match msg {
2531
Message::Read(ref expected) => {
@@ -110,7 +116,7 @@ fn run(listener: &TcpListener, rx: &Receiver<Message>) {
110116

111117
let mut dst = Vec::new();
112118
t!(socket.read_to_end(&mut dst));
113-
assert!(dst.len() == 0);
119+
assert_eq!(dst.len(), 0);
114120
}
115121

116122
fn lines_match(expected: &str, mut actual: &str) -> bool {
@@ -133,40 +139,79 @@ impl Server {
133139
let listener = t!(TcpListener::bind("127.0.0.1:0"));
134140
let addr = t!(listener.local_addr());
135141
let (tx, rx) = channel();
136-
let thread = thread::spawn(move || run(&listener, &rx));
142+
let thread = thread::spawn(move || run(listener.accept().unwrap().0, &rx));
143+
Server {
144+
messages: Some(tx),
145+
addr: Addr::Tcp(addr),
146+
thread: Some(thread),
147+
}
148+
}
149+
150+
#[cfg(not(windows))]
151+
pub fn new_unix() -> Server {
152+
use std::os::unix::net::UnixListener;
153+
154+
let path = "/tmp/easy_server.sock";
155+
std::fs::remove_file(path).ok();
156+
let listener = t!(UnixListener::bind(path));
157+
let (tx, rx) = channel();
158+
let thread = thread::spawn(move || run(listener.incoming().next().unwrap().unwrap(), &rx));
137159
Server {
138160
messages: Some(tx),
139-
addr: addr,
161+
addr: Addr::Unix(path.into()),
140162
thread: Some(thread),
141163
}
142164
}
143165

144166
pub fn receive(&self, msg: &str) {
145-
let msg = msg.replace("$PORT", &self.addr.port().to_string());
146-
self.msg(Message::Read(msg));
167+
self.msg(Message::Read(self.replace_port(msg)));
168+
}
169+
170+
fn replace_port(&self, msg: &str) -> String {
171+
match &self.addr {
172+
Addr::Tcp(addr) => msg.replace("$PORT", &addr.port().to_string()),
173+
Addr::Unix(_) => msg.to_string(),
174+
}
147175
}
148176

149177
pub fn send(&self, msg: &str) {
150-
let msg = msg.replace("$PORT", &self.addr.port().to_string());
151-
self.msg(Message::Write(msg));
178+
self.msg(Message::Write(self.replace_port(msg)));
152179
}
153180

154181
fn msg(&self, msg: Message) {
155182
t!(self.messages.as_ref().unwrap().send(msg));
156183
}
157184

158185
pub fn addr(&self) -> &SocketAddr {
159-
&self.addr
186+
match &self.addr {
187+
Addr::Tcp(addr) => addr,
188+
Addr::Unix(_) => panic!("server is a UnixListener"),
189+
}
190+
}
191+
192+
#[cfg(not(windows))]
193+
pub fn path(&self) -> &str {
194+
match &self.addr {
195+
Addr::Tcp(_) => panic!("server is a TcpListener"),
196+
Addr::Unix(p) => p.as_os_str().to_str().unwrap(),
197+
}
160198
}
161199

162200
pub fn url(&self, path: &str) -> String {
163-
format!("http://{}{}", self.addr, path)
201+
match &self.addr {
202+
Addr::Tcp(addr) => format!("http://{}{}", addr, path),
203+
Addr::Unix(_) => format!("http://localhost{}", path),
204+
}
164205
}
165206
}
166207

167208
impl Drop for Server {
168209
fn drop(&mut self) {
169-
drop(TcpStream::connect(&self.addr));
210+
match &self.addr {
211+
Addr::Tcp(addr) => drop(TcpStream::connect(addr)),
212+
Addr::Unix(p) => t!(std::fs::remove_file(p)),
213+
}
214+
170215
drop(self.messages.take());
171216
let res = self.thread.take().unwrap().join();
172217
if !thread::panicking() {

0 commit comments

Comments
 (0)