tor-dirclient: Make Requestable return requests with String bodies.
It's simpler to always use a `String` to represent directory request bodies. We no longer need the `StringBody` trait.
This commit is contained in:
parent
2a7ba4ceb0
commit
cd6c4674dc
|
@ -1,5 +1,5 @@
|
||||||
DEPRECATED: `download()`
|
DEPRECATED: `download()`
|
||||||
ADDED: `send_request()`
|
ADDED: `send_request()`
|
||||||
BREAKING: `Requestable` now has an associated `Body` type
|
|
||||||
ADDED: `StringBody` trait
|
ADDED: `StringBody` trait
|
||||||
ADDED: `tor-dirclient::request::HsDescUploadRequest`.
|
ADDED: `tor-dirclient::request::HsDescUploadRequest`.
|
||||||
|
BREAKING: `Requestable::make_request` now returns `http::Request<String>`
|
||||||
|
|
|
@ -52,12 +52,9 @@ impl StringBody for &str {
|
||||||
|
|
||||||
/// A request for an object that can be served over the Tor directory system.
|
/// A request for an object that can be served over the Tor directory system.
|
||||||
pub trait Requestable {
|
pub trait Requestable {
|
||||||
/// The body type of the [`http::Request`].
|
|
||||||
type Body: StringBody;
|
|
||||||
|
|
||||||
/// Build an [`http::Request`] from this Requestable, if
|
/// Build an [`http::Request`] from this Requestable, if
|
||||||
/// it is well-formed.
|
/// it is well-formed.
|
||||||
fn make_request(&self) -> Result<http::Request<Self::Body>>;
|
fn make_request(&self) -> Result<http::Request<String>>;
|
||||||
|
|
||||||
/// Return true if partial downloads are potentially useful. This
|
/// Return true if partial downloads are potentially useful. This
|
||||||
/// is true for request types where we're going to be downloading
|
/// is true for request types where we're going to be downloading
|
||||||
|
@ -219,9 +216,7 @@ impl Default for ConsensusRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Requestable for ConsensusRequest {
|
impl Requestable for ConsensusRequest {
|
||||||
type Body = ();
|
fn make_request(&self) -> Result<http::Request<String>> {
|
||||||
|
|
||||||
fn make_request(&self) -> Result<http::Request<()>> {
|
|
||||||
// Build the URL.
|
// Build the URL.
|
||||||
let mut uri = "/tor/status-vote/current/consensus".to_string();
|
let mut uri = "/tor/status-vote/current/consensus".to_string();
|
||||||
match self.flavor {
|
match self.flavor {
|
||||||
|
@ -256,7 +251,7 @@ impl Requestable for ConsensusRequest {
|
||||||
req = req.header("X-Or-Diff-From-Consensus", &ids);
|
req = req.header("X-Or-Diff-From-Consensus", &ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(req.body(())?)
|
Ok(req.body(String::new())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn partial_docs_ok(&self) -> bool {
|
fn partial_docs_ok(&self) -> bool {
|
||||||
|
@ -304,9 +299,7 @@ impl AuthCertRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Requestable for AuthCertRequest {
|
impl Requestable for AuthCertRequest {
|
||||||
type Body = ();
|
fn make_request(&self) -> Result<http::Request<String>> {
|
||||||
|
|
||||||
fn make_request(&self) -> Result<http::Request<()>> {
|
|
||||||
if self.ids.is_empty() {
|
if self.ids.is_empty() {
|
||||||
return Err(RequestError::EmptyRequest);
|
return Err(RequestError::EmptyRequest);
|
||||||
}
|
}
|
||||||
|
@ -329,7 +322,7 @@ impl Requestable for AuthCertRequest {
|
||||||
let req = http::Request::builder().method("GET").uri(uri);
|
let req = http::Request::builder().method("GET").uri(uri);
|
||||||
let req = add_common_headers(req);
|
let req = add_common_headers(req);
|
||||||
|
|
||||||
Ok(req.body(())?)
|
Ok(req.body(String::new())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn partial_docs_ok(&self) -> bool {
|
fn partial_docs_ok(&self) -> bool {
|
||||||
|
@ -376,9 +369,7 @@ impl MicrodescRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Requestable for MicrodescRequest {
|
impl Requestable for MicrodescRequest {
|
||||||
type Body = ();
|
fn make_request(&self) -> Result<http::Request<String>> {
|
||||||
|
|
||||||
fn make_request(&self) -> Result<http::Request<()>> {
|
|
||||||
let d_encode_b64 = |d: &[u8; 32]| Base64Unpadded::encode_string(&d[..]);
|
let d_encode_b64 = |d: &[u8; 32]| Base64Unpadded::encode_string(&d[..]);
|
||||||
let ids = digest_list_stringify(&self.digests, d_encode_b64, "-")
|
let ids = digest_list_stringify(&self.digests, d_encode_b64, "-")
|
||||||
.ok_or(RequestError::EmptyRequest)?;
|
.ok_or(RequestError::EmptyRequest)?;
|
||||||
|
@ -387,7 +378,7 @@ impl Requestable for MicrodescRequest {
|
||||||
|
|
||||||
let req = add_common_headers(req);
|
let req = add_common_headers(req);
|
||||||
|
|
||||||
Ok(req.body(())?)
|
Ok(req.body(String::new())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn partial_docs_ok(&self) -> bool {
|
fn partial_docs_ok(&self) -> bool {
|
||||||
|
@ -453,9 +444,7 @@ impl RouterDescRequest {
|
||||||
|
|
||||||
#[cfg(feature = "routerdesc")]
|
#[cfg(feature = "routerdesc")]
|
||||||
impl Requestable for RouterDescRequest {
|
impl Requestable for RouterDescRequest {
|
||||||
type Body = ();
|
fn make_request(&self) -> Result<http::Request<String>> {
|
||||||
|
|
||||||
fn make_request(&self) -> Result<http::Request<()>> {
|
|
||||||
let mut uri = "/tor/server/".to_string();
|
let mut uri = "/tor/server/".to_string();
|
||||||
|
|
||||||
match self.requested_descriptors {
|
match self.requested_descriptors {
|
||||||
|
@ -475,7 +464,7 @@ impl Requestable for RouterDescRequest {
|
||||||
let req = http::Request::builder().method("GET").uri(uri);
|
let req = http::Request::builder().method("GET").uri(uri);
|
||||||
let req = add_common_headers(req);
|
let req = add_common_headers(req);
|
||||||
|
|
||||||
Ok(req.body(())?)
|
Ok(req.body(String::new())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn partial_docs_ok(&self) -> bool {
|
fn partial_docs_ok(&self) -> bool {
|
||||||
|
@ -521,14 +510,12 @@ impl RoutersOwnDescRequest {
|
||||||
|
|
||||||
#[cfg(feature = "routerdesc")]
|
#[cfg(feature = "routerdesc")]
|
||||||
impl Requestable for RoutersOwnDescRequest {
|
impl Requestable for RoutersOwnDescRequest {
|
||||||
type Body = ();
|
fn make_request(&self) -> Result<http::Request<String>> {
|
||||||
|
|
||||||
fn make_request(&self) -> Result<http::Request<()>> {
|
|
||||||
let uri = "/tor/server/authority.z";
|
let uri = "/tor/server/authority.z";
|
||||||
let req = http::Request::builder().method("GET").uri(uri);
|
let req = http::Request::builder().method("GET").uri(uri);
|
||||||
let req = add_common_headers(req);
|
let req = add_common_headers(req);
|
||||||
|
|
||||||
Ok(req.body(())?)
|
Ok(req.body(String::new())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn partial_docs_ok(&self) -> bool {
|
fn partial_docs_ok(&self) -> bool {
|
||||||
|
@ -569,16 +556,14 @@ impl HsDescDownloadRequest {
|
||||||
|
|
||||||
#[cfg(feature = "hs-client")]
|
#[cfg(feature = "hs-client")]
|
||||||
impl Requestable for HsDescDownloadRequest {
|
impl Requestable for HsDescDownloadRequest {
|
||||||
type Body = ();
|
fn make_request(&self) -> Result<http::Request<String>> {
|
||||||
|
|
||||||
fn make_request(&self) -> Result<http::Request<()>> {
|
|
||||||
let hsid = Base64Unpadded::encode_string(self.hsid.as_ref());
|
let hsid = Base64Unpadded::encode_string(self.hsid.as_ref());
|
||||||
// We hardcode version 3 here; if we ever have a v4 onion service
|
// We hardcode version 3 here; if we ever have a v4 onion service
|
||||||
// descriptor, it will need a different kind of Request.
|
// descriptor, it will need a different kind of Request.
|
||||||
let uri = format!("/tor/hs/3/{}", hsid);
|
let uri = format!("/tor/hs/3/{}", hsid);
|
||||||
let req = http::Request::builder().method("GET").uri(uri);
|
let req = http::Request::builder().method("GET").uri(uri);
|
||||||
let req = add_common_headers(req);
|
let req = add_common_headers(req);
|
||||||
Ok(req.body(())?)
|
Ok(req.body(String::new())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn partial_docs_ok(&self) -> bool {
|
fn partial_docs_ok(&self) -> bool {
|
||||||
|
@ -607,9 +592,7 @@ impl HsDescUploadRequest {
|
||||||
|
|
||||||
#[cfg(feature = "hs-service")]
|
#[cfg(feature = "hs-service")]
|
||||||
impl Requestable for HsDescUploadRequest {
|
impl Requestable for HsDescUploadRequest {
|
||||||
type Body = String;
|
fn make_request(&self) -> Result<http::Request<String>> {
|
||||||
|
|
||||||
fn make_request(&self) -> Result<http::Request<Self::Body>> {
|
|
||||||
/// The upload URI.
|
/// The upload URI.
|
||||||
const URI: &str = "/tor/hs/3/publish";
|
const URI: &str = "/tor/hs/3/publish";
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,8 @@
|
||||||
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use crate::request::StringBody;
|
|
||||||
|
|
||||||
/// Encode an HTTP request in a quick and dirty HTTP 1.0 format.
|
/// Encode an HTTP request in a quick and dirty HTTP 1.0 format.
|
||||||
pub(crate) fn encode_request<B: StringBody>(req: &http::Request<B>) -> String {
|
pub(crate) fn encode_request(req: &http::Request<String>) -> String {
|
||||||
let mut s = format!("{} {} HTTP/1.0\r\n", req.method(), req.uri());
|
let mut s = format!("{} {} HTTP/1.0\r\n", req.method(), req.uri());
|
||||||
|
|
||||||
for (key, val) in req.headers().iter() {
|
for (key, val) in req.headers().iter() {
|
||||||
|
@ -19,7 +17,7 @@ pub(crate) fn encode_request<B: StringBody>(req: &http::Request<B>) -> String {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
s.push_str("\r\n");
|
s.push_str("\r\n");
|
||||||
s.push_str(req.body().as_str());
|
s.push_str(req.body());
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,16 +36,7 @@ mod test {
|
||||||
//! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
|
//! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
fn build_request(body: String, headers: &[(&str, &str)]) -> http::Request<String> {
|
||||||
struct TestBody;
|
|
||||||
|
|
||||||
impl StringBody for TestBody {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
"hello"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_request<B: StringBody>(body: B, headers: &[(&str, &str)]) -> http::Request<B> {
|
|
||||||
let mut builder = http::Request::builder().method("GET").uri("/index.html");
|
let mut builder = http::Request::builder().method("GET").uri("/index.html");
|
||||||
|
|
||||||
for (name, value) in headers {
|
for (name, value) in headers {
|
||||||
|
@ -59,21 +48,21 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn format() {
|
fn format() {
|
||||||
fn chk_format<B: StringBody + Clone>(body: B, expected_body: &str) {
|
fn chk_format(body: String) {
|
||||||
let req = build_request(body.clone(), &[]);
|
let req = build_request(body.clone(), &[]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
encode_request(&req),
|
encode_request(&req),
|
||||||
format!("GET /index.html HTTP/1.0\r\n\r\n{expected_body}")
|
format!("GET /index.html HTTP/1.0\r\n\r\n{body}")
|
||||||
);
|
);
|
||||||
|
|
||||||
let req = build_request(body, &[("X-Marsupial", "Opossum")]);
|
let req = build_request(body.clone(), &[("X-Marsupial", "Opossum")]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
encode_request(&req),
|
encode_request(&req),
|
||||||
format!("GET /index.html HTTP/1.0\r\nx-marsupial: Opossum\r\n\r\n{expected_body}")
|
format!("GET /index.html HTTP/1.0\r\nx-marsupial: Opossum\r\n\r\n{body}")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
chk_format((), "");
|
chk_format(Default::default());
|
||||||
chk_format(TestBody, "hello");
|
chk_format("hello".into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ pub(crate) enum ClientRequest {
|
||||||
|
|
||||||
impl ClientRequest {
|
impl ClientRequest {
|
||||||
/// Turn a ClientRequest into a Requestable.
|
/// Turn a ClientRequest into a Requestable.
|
||||||
pub(crate) fn as_requestable(&self) -> &(dyn request::Requestable<Body = ()> + Send + Sync) {
|
pub(crate) fn as_requestable(&self) -> &(dyn request::Requestable + Send + Sync) {
|
||||||
use ClientRequest::*;
|
use ClientRequest::*;
|
||||||
match self {
|
match self {
|
||||||
Consensus(a) => a,
|
Consensus(a) => a,
|
||||||
|
|
Loading…
Reference in New Issue