我想在Rust中创建一个类似curl的函数。
到目前为止,这是我使用的代码:
match Url::parse(url) {
Ok(u) => {
match TcpStream::connect(u.host.as_slice(), 80) {
Ok(mut socket) => {
let req = format!(
"GET {:s} HTTP/1.1\r\nHost: {:s}\r\nAccept: */*\r\nContent-Length: 0\r\nContent-Type: aplication/x-www-form-urlencoded\r\n",
u.path.path.as_slice(), u.host
);
socket.write(req.as_bytes());
match socket.read_to_string() {
Ok(res) => println!("{}", res.as_slice()),
Err(e) => fail!("Error: {}", e)
};
drop(socket);
},
Err(e) => fail!("Error: {}", e)
};
},
Err(e) => fail!("Error: {}", e)
};
问题是,如果HTTP请求格式正确,
println!("{}", res.as_slice())
不会显示任何内容,包含任何网址。
如果格式不正确,相同的代码将显示403或400错误。这应该意味着套接字var是否填充良好?
问题出在哪里?服务器或请求?
顺便说一下,代码有点太长了,我想用宏试试!但是在做的时候会引发错误,例如:
try!(TcpStream::connect(u.host.as_slice(), 80)
答案 0 :(得分:3)
看起来您的请求确实 不正确,但服务器无法告诉您。
GET {:s} HTTP/1.1\r\nHost: {:s}\r\nAccept: */*\r\nContent-Length: 0\r\nContent-Type: aplication/x-www-form-urlencoded\r\n
你知道,HTTP请求应该在两个换行符中结束,即两个\r\n
序列。此外,GET请求不能具有正文(尽管大多数Web服务器可能会忽略它):
GET {:s} HTTP/1.1\r\nHost: {:s}\r\nAccept: */*\r\n\r\n
此请求应该有效。
对于try!
,您似乎试图在main()
函数或类似的东西中使用它,对吧? try!
旨在在出错时从函数返回,即:
try!(TcpStream::connect(u.host.as_slice(), 80))
被重写为
match TcpStream::connect(u.host.as_slice(), 80) {
Ok(s) => s,
Err(e) => return Err(e)
}
如果您的功能未返回Result
,则无效。所以你的代码看起来会更好:
extern crate url;
use std::io::{IoResult, File, TcpStream};
use url::Url;
fn download_file(url: &Url, file: &Path) -> IoResult<()> {
let mut socket = try!(TcpStream::connect(url.host.as_slice(), 80));
let req = format!(
"GET {:s} HTTP/1.1\r\nHost: {:s}\r\nAccept: */*\r\n\r\n",
url.path.path.as_slice(), url.host
);
try!(socket.write(req.as_bytes()));
let res = try!(socket.read_to_end());
let mut file = File::create(file);
try!(file.write(res.as_slice()));
Ok(())
}
fn main() {
let url = "http://kitten.jpg.to/";
match Url::parse(url) {
Ok(url) => match download_file(&url, &Path::new("/tmp/kitten_link.http")) {
Ok(_) => println!("Download successful"),
Err(e) => fail!("Error: {}", e)
},
Err(e) => fail!("Error: {}", e)
}
}
顺便说一句,你也不需要明确地删除套接字或其他东西。它们超出范围时会自动销毁。我还将read_to_string()
更改为read_to_end()
,因为二进制文件在通过String
后不正确。