ureq_proto/client/
prepare.rs

1use http::{header, HeaderMap, HeaderName, HeaderValue, Method, Request, Uri, Version};
2
3use crate::body::BodyWriter;
4use crate::client::amended::AmendedRequest;
5use crate::ext::{HeaderIterExt, MethodExt};
6use crate::{ArrayVec, Error};
7
8use super::state::{Prepare, SendRequest};
9use super::{BodyState, Call, CloseReason, Inner};
10
11impl Call<Prepare> {
12    /// Create a new Call instance from an HTTP request.
13    ///
14    /// This initializes a new Call state machine in the Prepare state,
15    /// setting up the necessary internal state based on the request properties.
16    pub fn new(request: Request<()>) -> Result<Self, Error> {
17        let mut close_reason = ArrayVec::from_fn(|_| CloseReason::ClientConnectionClose);
18
19        if request.version() == Version::HTTP_10 {
20            // request.analyze() in CallHolder::new() ensures the only versions are HTTP 1.0 and 1.1
21            close_reason.push(CloseReason::CloseDelimitedBody)
22        }
23
24        if request.headers().iter().has(header::CONNECTION, "close") {
25            close_reason.push(CloseReason::ClientConnectionClose);
26        }
27
28        let need_request_body = request.method().need_request_body();
29        let await_100_continue = request.headers().iter().has_expect_100();
30
31        let request = AmendedRequest::new(request);
32
33        let default_body_mode = if need_request_body {
34            BodyWriter::new_chunked()
35        } else {
36            BodyWriter::new_none()
37        };
38
39        let inner = Inner {
40            request,
41            analyzed: false,
42            state: BodyState {
43                writer: default_body_mode,
44                ..Default::default()
45            },
46            close_reason,
47            force_send_body: false,
48            force_recv_body: false,
49            await_100_continue,
50            status: None,
51            location: None,
52        };
53
54        Ok(Call::wrap(inner))
55    }
56
57    /// Inspect call method
58    pub fn method(&self) -> &Method {
59        self.inner.request.method()
60    }
61
62    /// Inspect call URI
63    pub fn uri(&self) -> &Uri {
64        self.inner.request.uri()
65    }
66
67    /// Inspect call HTTP version
68    pub fn version(&self) -> Version {
69        self.inner.request.version()
70    }
71
72    /// Inspect call headers
73    pub fn headers(&self) -> &HeaderMap {
74        self.inner.request.original_request_headers()
75    }
76
77    /// Set whether to allow non-standard HTTP methods.
78    ///
79    /// By default the methods are limited by the HTTP version.
80    pub fn allow_non_standard_methods(&mut self, v: bool) {
81        self.inner.state.allow_non_standard_methods = v;
82    }
83
84    /// Add more headers to the call
85    pub fn header<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
86    where
87        HeaderName: TryFrom<K>,
88        <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
89        HeaderValue: TryFrom<V>,
90        <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
91    {
92        self.inner.request.set_header(key, value)
93    }
94
95    /// Convert the state to send body despite method.
96    ///
97    /// Methods like GET, HEAD and DELETE should not have a request body.
98    /// Some broken APIs use bodies anyway, and this is an escape hatch to
99    /// interoperate with such services.
100    pub fn force_send_body(&mut self) {
101        self.inner.force_send_body = true;
102    }
103
104    /// Continue to the next call state.
105    pub fn proceed(self) -> Call<SendRequest> {
106        Call::wrap(self.inner)
107    }
108}