use crate::error;
use crate::error::Error;
use crate::http::{request::Request, response::Response, Scheme};
pub mod connector;
use connector::Connector;
pub struct Requester {
connector: Box<dyn Connector>,
}
impl Requester {
pub fn new(connector: Box<dyn Connector>) -> Self {
Requester { connector }
}
pub fn send_request(&self, request: Request) -> Result<Response, Error> {
let request_str = request.build();
for server in request.servers {
let server_str = server.to_string();
log::info!("Trying server {}", server_str);
let result = match request.scheme {
Scheme::Http => self.connector.http_request(server, &request_str),
Scheme::Https => self.connector.https_request(
server,
request.url.domain().unwrap(),
&request_str,
),
};
match result {
Ok(response) => return Response::from_buffer(&response),
Err(err) => {
log::warn!("Request to {} failed with error {}", server_str, err);
continue;
}
}
}
error!("no server worked for request")
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
http::{headers::Headers, Method},
requester::connector::RegularConnector,
};
use httptest::{matchers::*, responders::*, Expectation, Server};
use serde::{Deserialize, Serialize};
use serde_json;
use url::Url;
#[derive(Serialize, Deserialize)]
struct TestType {
name: String,
age: u32,
}
#[test]
fn get_request_ok() {
let server = get_json_server();
let uri = server.url("/foo");
let url = Url::parse(&uri.to_string()).unwrap();
let request = Request::new(url, Method::Get, Headers::new()).unwrap();
let requester = Requester::new(Box::new(RegularConnector::new(10)));
let response = requester.send_request(request).unwrap();
assert_eq!(response.status_code, 200);
assert_eq!(
response
.headers
.get("content-type")
.unwrap()
.first()
.unwrap(),
"application/json"
);
let body: TestType = serde_json::from_str(&response.body.unwrap()).unwrap();
assert_eq!(body.name, "Bob");
assert_eq!(body.age, 25);
}
fn get_json_server() -> Server {
let server = Server::run();
let responder = status_code(200)
.body(r#"{"name":"Bob", "age":25}"#)
.append_header("Content-Type", "application/json");
let expectation = Expectation::matching(request::method_path("GET", "/foo"));
server.expect(expectation.respond_with(responder));
server
}
}