Merge pull request #3 from Trivernis/feature/managing-cookies-and-headers
Feature/managing cookies and headerspull/4/head
commit
0e409754e7
@ -0,0 +1,102 @@
|
|||||||
|
use crate::api_core::common::OptionalStringNumber;
|
||||||
|
use crate::api_core::Endpoint;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
|
pub struct GetCookiesResponse {
|
||||||
|
pub cookies: Vec<[OptionalStringNumber; 5]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GetCookies;
|
||||||
|
|
||||||
|
impl Endpoint for GetCookies {
|
||||||
|
type Request = ();
|
||||||
|
type Response = GetCookiesResponse;
|
||||||
|
|
||||||
|
fn path() -> String {
|
||||||
|
String::from("manage_cookies/get_cookies")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
pub struct SetCookiesRequest {
|
||||||
|
pub cookies: Vec<[OptionalStringNumber; 5]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SetCookies;
|
||||||
|
|
||||||
|
impl Endpoint for SetCookies {
|
||||||
|
type Request = SetCookiesRequest;
|
||||||
|
type Response = ();
|
||||||
|
|
||||||
|
fn path() -> String {
|
||||||
|
String::from("manage_cookies/set_cookies")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CookieBuilder {
|
||||||
|
name: OptionalStringNumber,
|
||||||
|
value: OptionalStringNumber,
|
||||||
|
domain: OptionalStringNumber,
|
||||||
|
path: OptionalStringNumber,
|
||||||
|
expires: OptionalStringNumber,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CookieBuilder {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
name: String::new().into(),
|
||||||
|
value: String::new().into(),
|
||||||
|
domain: String::new().into(),
|
||||||
|
path: String::new().into(),
|
||||||
|
expires: OptionalStringNumber::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CookieBuilder {
|
||||||
|
pub fn name<S: ToString>(mut self, name: S) -> Self {
|
||||||
|
self.name = name.to_string().into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value<S: ToString>(mut self, value: S) -> Self {
|
||||||
|
self.value = value.to_string().into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn domain<S: ToString>(mut self, domain: S) -> Self {
|
||||||
|
self.domain = domain.to_string().into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path<S: ToString>(mut self, path: S) -> Self {
|
||||||
|
self.path = path.to_string().into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expires(mut self, expires: u64) -> Self {
|
||||||
|
self.expires = expires.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> [OptionalStringNumber; 5] {
|
||||||
|
[self.name, self.value, self.domain, self.path, self.expires]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
pub struct SetUserAgentRequest {
|
||||||
|
#[serde(rename = "user-agent")]
|
||||||
|
pub user_agent: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SetUserAgent;
|
||||||
|
|
||||||
|
impl Endpoint for SetUserAgent {
|
||||||
|
type Request = SetUserAgentRequest;
|
||||||
|
type Response = ();
|
||||||
|
|
||||||
|
fn path() -> String {
|
||||||
|
String::from("manage_headers/set_user_agent")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
use crate::api_core::common::OptionalStringNumber;
|
||||||
|
use crate::api_core::managing_cookies_and_http_headers::CookieBuilder;
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::Client;
|
||||||
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
pub struct Address {
|
||||||
|
client: Client,
|
||||||
|
domain: String,
|
||||||
|
path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Address {
|
||||||
|
pub(crate) fn from_str(client: Client, domain: &str) -> Self {
|
||||||
|
let (domain, path) = domain.split_once("/").unwrap_or((domain, "/"));
|
||||||
|
Self {
|
||||||
|
client,
|
||||||
|
domain: domain.to_string(),
|
||||||
|
path: path.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the path after the domain name
|
||||||
|
pub fn path(&self) -> &str {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the path of the domain that can be used for setting cookies
|
||||||
|
pub fn set_path<S: ToString>(&mut self, path: S) {
|
||||||
|
self.path = path.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets cookies for the domain
|
||||||
|
pub async fn set_cookies(&self, cookies: Vec<DomainCookie>) -> Result<()> {
|
||||||
|
let cookies = cookies
|
||||||
|
.into_iter()
|
||||||
|
.map(|cookie| {
|
||||||
|
let mut builder = CookieBuilder::default()
|
||||||
|
.domain(&self.domain)
|
||||||
|
.path(&self.path)
|
||||||
|
.name(cookie.name)
|
||||||
|
.value(cookie.value);
|
||||||
|
if let Some(expires) = cookie.expires {
|
||||||
|
builder =
|
||||||
|
builder.expires(expires.duration_since(UNIX_EPOCH).unwrap().as_secs());
|
||||||
|
}
|
||||||
|
builder.build()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
self.client.set_cookies(cookies).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns all cookies stored for this domain
|
||||||
|
pub async fn get_cookies(&self) -> Result<Vec<DomainCookie>> {
|
||||||
|
let response = self.client.get_cookies(&self.domain).await?;
|
||||||
|
let cookies = response
|
||||||
|
.cookies
|
||||||
|
.into_iter()
|
||||||
|
.map(DomainCookie::from)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(cookies)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct DomainCookie {
|
||||||
|
pub name: String,
|
||||||
|
pub value: String,
|
||||||
|
pub expires: Option<SystemTime>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DomainCookie {
|
||||||
|
/// Creates a new cookie that will be expire after the given instant or only last for the session
|
||||||
|
pub fn new<S1: ToString, S2: ToString>(
|
||||||
|
name: S1,
|
||||||
|
value: S2,
|
||||||
|
expires: Option<SystemTime>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
value: value.to_string(),
|
||||||
|
expires,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<[OptionalStringNumber; 5]> for DomainCookie {
|
||||||
|
fn from(cookie_entry: [OptionalStringNumber; 5]) -> Self {
|
||||||
|
let name = cookie_entry[0].string().unwrap_or("");
|
||||||
|
let value = cookie_entry[1].string().unwrap_or("");
|
||||||
|
let expires = cookie_entry[4]
|
||||||
|
.number()
|
||||||
|
.map(|n| UNIX_EPOCH + Duration::from_secs(n));
|
||||||
|
|
||||||
|
Self::new(name, value, expires)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
use super::super::common;
|
||||||
|
use hydrus_api::api_core::managing_cookies_and_http_headers::CookieBuilder;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_returns_cookies_for_a_domain() {
|
||||||
|
let client = common::get_client();
|
||||||
|
client.get_cookies("trivernis.net").await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_sets_cookies_for_a_domain() {
|
||||||
|
let client = common::get_client();
|
||||||
|
let cookie = CookieBuilder::default()
|
||||||
|
.name("my_cookie")
|
||||||
|
.value("my_value")
|
||||||
|
.domain("trivernis.net")
|
||||||
|
.path("/")
|
||||||
|
.build();
|
||||||
|
client.set_cookies(vec![cookie]).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_sets_the_user_agent() {
|
||||||
|
let client = common::get_client();
|
||||||
|
client
|
||||||
|
.set_user_agent("Mozilla/5.0 (compatible; Hydrus Client)")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
use super::super::common;
|
||||||
|
use hydrus_api::wrapper::address::{Address, DomainCookie};
|
||||||
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
|
fn get_address() -> Address {
|
||||||
|
let hydrus = common::get_hydrus();
|
||||||
|
|
||||||
|
hydrus.address("trivernis.net/some/path")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_sets_cookies() {
|
||||||
|
let address = get_address();
|
||||||
|
address
|
||||||
|
.set_cookies(vec![
|
||||||
|
DomainCookie::new("name", "value", None),
|
||||||
|
DomainCookie::new(
|
||||||
|
"name2",
|
||||||
|
"value2",
|
||||||
|
Some(SystemTime::now() + Duration::from_secs(30)),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_retrieves_cookies() {
|
||||||
|
let address = get_address();
|
||||||
|
address.get_cookies().await.unwrap();
|
||||||
|
}
|
Loading…
Reference in New Issue