Skip to main content

Request

Struct Request 

Source
pub struct Request {
    pub method: String,
    pub path: String,
    pub query: Vec<(String, String)>,
    pub headers: Vec<(String, String)>,
    pub body: Vec<u8>,
    pub remote: Option<IpAddr>,
}
Expand description

A request as the router sees it: method, path without query, decoded query pairs, headers, and the body.

Fields§

§method: String

GET, POST, … as received (a HEAD arrives as GET).

§path: String

The path without the query string.

§query: Vec<(String, String)>

The query pairs, percent-decoded, in order.

§headers: Vec<(String, String)>

Header names and values as received; looked up case-insensitively.

§body: Vec<u8>

The body, raw.

§remote: Option<IpAddr>

The address the request came from, when it came over a socket. A request built in this process (a test, the Cockpit composing a call) has none, and is this machine’s.

Implementations§

Source§

impl Request

Source

pub fn parse_target(method: &str, target: &str, body: Vec<u8>) -> Self

Split a request target (/api/v1/objects?kind=rule) into path and decoded pairs.

use majordomus_cli::http::Request;
let r = Request::parse_target("GET", "/api/v1/search?query=Git%20is&limit=2", vec![]);
assert_eq!(r.path, "/api/v1/search");
assert_eq!(r.query, vec![("query".to_string(), "Git is".to_string()), ("limit".to_string(), "2".to_string())]);
Source

pub fn bind(method: HttpMethod, path: &str, input: &Value) -> Self

The request that carries input to a capability’s route the way the binding says: GET puts every top-level property that is not null on the query string (a scalar as its text, anything else as JSON), POST sends the input as the body. The inverse of the router’s binding, so a benchmark case reaches the route as a client would send it.

use majordomus_cli::capability::HttpMethod;
use majordomus_cli::http::Request;
use serde_json::json;
let r = Request::bind(HttpMethod::Get, "/api/v1/search", &json!({ "query": "a b", "limit": 2, "kind": null }));
assert_eq!(r.path, "/api/v1/search");
assert_eq!(r.query, vec![("query".to_string(), "a b".to_string()), ("limit".to_string(), "2".to_string())]);
let p = Request::bind(HttpMethod::Post, "/api/v1/peers/announce", &json!({ "intent": "x" }));
assert_eq!(p.body, br#"{"intent":"x"}"#);
Source

pub fn target(&self) -> String

The request target this request would be sent as: the path with the query string, percent-encoded.

use majordomus_cli::capability::HttpMethod;
use majordomus_cli::http::Request;
let r = Request::bind(HttpMethod::Get, "/api/v1/search", &serde_json::json!({ "query": "a b&c" }));
assert_eq!(r.target(), "/api/v1/search?query=a%20b%26c");
Source

pub fn with_headers(self, headers: Vec<(String, String)>) -> Self

The same request with its headers.

Source

pub fn with_remote(self, address: Option<IpAddr>) -> Self

The same request, as having come from address.

use majordomus_cli::http::Request;
let r = Request::parse_target("GET", "/", vec![]).with_remote(Some("10.0.0.2".parse().unwrap()));
assert_eq!(r.remote, Some("10.0.0.2".parse().unwrap()));
Source

pub fn is_remote(&self) -> bool

Did this request come from another host?

Loopback is this machine, in either family and in the IPv4-mapped IPv6 form a dual-stack socket reports. A request with no address was built in this process.

use majordomus_cli::http::Request;
let r = |a: &str| Request::parse_target("POST", "/", vec![]).with_remote(Some(a.parse().unwrap()));
assert!(!r("127.0.0.1").is_remote());
assert!(!r("::1").is_remote());
assert!(!r("::ffff:127.0.0.1").is_remote());
assert!(r("192.168.100.30").is_remote());
assert!(r("100.92.246.32").is_remote());
assert!(r("::ffff:10.0.0.2").is_remote());
assert!(!Request::parse_target("POST", "/", vec![]).is_remote());
Source

pub fn header(&self, name: &str) -> Option<&str>

A header value, by case-insensitive name.

use majordomus_cli::http::Request;
let r = Request::parse_target("POST", "/mcp", vec![])
    .with_headers(vec![("Mcp-Session-Id".into(), "abc".into())]);
assert_eq!(r.header("mcp-session-id"), Some("abc"));
assert_eq!(r.header("x-none"), None);

Trait Implementations§

Source§

impl Clone for Request

Source§

fn clone(&self) -> Request

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Request

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more