1
0
mirror of https://github.com/actix/actix-extras.git synced 2025-08-31 19:37:00 +02:00

Deploying to gh-pages from @ 1e682e7a59 🚀

This commit is contained in:
robjtede
2022-08-24 17:10:06 +00:00
parent 677c856277
commit a717748964
200 changed files with 8532 additions and 8481 deletions

View File

@@ -55,60 +55,60 @@
<span id="53">53</span>
<span id="54">54</span>
<span id="55">55</span>
</pre><pre class="rust"><code><span class="doccomment">/// An enum signifying that some of type `T` is allowed, or `All` (anything is allowed).</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">AllOrSome</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> {
<span class="doccomment">/// Everything is allowed. Usually equivalent to the `*` value.</span>
<span class="ident">All</span>,
</pre><pre class="rust"><code><span class="doccomment">/// An enum signifying that some of type `T` is allowed, or `All` (anything is allowed).
</span><span class="attribute">#[derive(Debug, Clone, PartialEq, Eq)]
</span><span class="kw">pub enum </span>AllOrSome&lt;T&gt; {
<span class="doccomment">/// Everything is allowed. Usually equivalent to the `*` value.
</span>All,
<span class="doccomment">/// Only some of `T` is allowed</span>
<span class="prelude-val">Some</span>(<span class="ident">T</span>),
<span class="doccomment">/// Only some of `T` is allowed
</span><span class="prelude-val">Some</span>(T),
}
<span class="doccomment">/// Default as `AllOrSome::All`.</span>
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> <span class="ident">Default</span> <span class="kw">for</span> <span class="ident">AllOrSome</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">default</span>() -&gt; <span class="self">Self</span> {
<span class="ident">AllOrSome::All</span>
<span class="doccomment">/// Default as `AllOrSome::All`.
</span><span class="kw">impl</span>&lt;T&gt; Default <span class="kw">for </span>AllOrSome&lt;T&gt; {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
AllOrSome::All
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> <span class="ident">AllOrSome</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> {
<span class="doccomment">/// Returns whether this is an `All` variant.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">is_all</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">bool</span> {
<span class="macro">matches!</span>(<span class="self">self</span>, <span class="ident">AllOrSome::All</span>)
<span class="kw">impl</span>&lt;T&gt; AllOrSome&lt;T&gt; {
<span class="doccomment">/// Returns whether this is an `All` variant.
</span><span class="kw">pub fn </span>is_all(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="macro">matches!</span>(<span class="self">self</span>, AllOrSome::All)
}
<span class="doccomment">/// Returns whether this is a `Some` variant.</span>
<span class="attribute">#[<span class="ident">allow</span>(<span class="ident">dead_code</span>)]</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">is_some</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">bool</span> {
<span class="op">!</span><span class="self">self</span>.<span class="ident">is_all</span>()
<span class="doccomment">/// Returns whether this is a `Some` variant.
</span><span class="attribute">#[allow(dead_code)]
</span><span class="kw">pub fn </span>is_some(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
!<span class="self">self</span>.is_all()
}
<span class="doccomment">/// Provides a shared reference to `T` if variant is `Some`.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">as_ref</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="kw-2">&amp;</span><span class="ident">T</span><span class="op">&gt;</span> {
<span class="kw">match</span> <span class="kw-2">*</span><span class="self">self</span> {
<span class="ident">AllOrSome::All</span> =&gt; <span class="prelude-val">None</span>,
<span class="ident">AllOrSome::Some</span>(<span class="kw-2">ref</span> <span class="ident">t</span>) =&gt; <span class="prelude-val">Some</span>(<span class="ident">t</span>),
<span class="doccomment">/// Provides a shared reference to `T` if variant is `Some`.
</span><span class="kw">pub fn </span>as_ref(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>T&gt; {
<span class="kw">match </span><span class="kw-2">*</span><span class="self">self </span>{
AllOrSome::All =&gt; <span class="prelude-val">None</span>,
AllOrSome::Some(<span class="kw-2">ref </span>t) =&gt; <span class="prelude-val">Some</span>(t),
}
}
<span class="doccomment">/// Provides a mutable reference to `T` if variant is `Some`.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">as_mut</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="kw-2">&amp;mut</span> <span class="ident">T</span><span class="op">&gt;</span> {
<span class="kw">match</span> <span class="kw-2">*</span><span class="self">self</span> {
<span class="ident">AllOrSome::All</span> =&gt; <span class="prelude-val">None</span>,
<span class="ident">AllOrSome::Some</span>(<span class="kw-2">ref</span> <span class="kw-2">mut</span> <span class="ident">t</span>) =&gt; <span class="prelude-val">Some</span>(<span class="ident">t</span>),
<span class="doccomment">/// Provides a mutable reference to `T` if variant is `Some`.
</span><span class="kw">pub fn </span>as_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;mut </span>T&gt; {
<span class="kw">match </span><span class="kw-2">*</span><span class="self">self </span>{
AllOrSome::All =&gt; <span class="prelude-val">None</span>,
AllOrSome::Some(<span class="kw-2">ref mut </span>t) =&gt; <span class="prelude-val">Some</span>(t),
}
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">tests</span>() {
<span class="macro">assert!</span>(<span class="ident">AllOrSome</span>::<span class="op">&lt;</span>()<span class="op">&gt;</span><span class="ident">::All</span>.<span class="ident">is_all</span>());
<span class="macro">assert!</span>(<span class="op">!</span><span class="ident">AllOrSome</span>::<span class="op">&lt;</span>()<span class="op">&gt;</span><span class="ident">::All</span>.<span class="ident">is_some</span>());
<span class="attribute">#[cfg(test)]
#[test]
</span><span class="kw">fn </span>tests() {
<span class="macro">assert!</span>(AllOrSome::&lt;()&gt;::All.is_all());
<span class="macro">assert!</span>(!AllOrSome::&lt;()&gt;::All.is_some());
<span class="macro">assert!</span>(<span class="op">!</span><span class="ident">AllOrSome::Some</span>(()).<span class="ident">is_all</span>());
<span class="macro">assert!</span>(<span class="ident">AllOrSome::Some</span>(()).<span class="ident">is_some</span>());
<span class="macro">assert!</span>(!AllOrSome::Some(()).is_all());
<span class="macro">assert!</span>(AllOrSome::Some(()).is_some());
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_cors" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_cors" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

File diff suppressed because it is too large Load Diff

View File

@@ -49,54 +49,54 @@
<span id="47">47</span>
<span id="48">48</span>
<span id="49">49</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">actix_web</span>::{<span class="ident">http::StatusCode</span>, <span class="ident">HttpResponse</span>, <span class="ident">ResponseError</span>};
<span class="kw">use</span> <span class="ident">derive_more</span>::{<span class="ident">Display</span>, <span class="ident">Error</span>};
</pre><pre class="rust"><code><span class="kw">use </span>actix_web::{http::StatusCode, HttpResponse, ResponseError};
<span class="kw">use </span>derive_more::{Display, Error};
<span class="doccomment">/// Errors that can occur when processing CORS guarded requests.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">Display</span>, <span class="ident">Error</span>)]</span>
<span class="attribute">#[<span class="ident">non_exhaustive</span>]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">CorsError</span> {
<span class="doccomment">/// Allowed origin argument must not be wildcard (`*`).</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;`allowed_origin` argument must not be wildcard (`*`)&quot;</span>)]</span>
<span class="ident">WildcardOrigin</span>,
<span class="doccomment">/// Errors that can occur when processing CORS guarded requests.
</span><span class="attribute">#[derive(Debug, Clone, Display, Error)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>CorsError {
<span class="doccomment">/// Allowed origin argument must not be wildcard (`*`).
</span><span class="attribute">#[display(fmt = <span class="string">&quot;`allowed_origin` argument must not be wildcard (`*`)&quot;</span>)]
</span>WildcardOrigin,
<span class="doccomment">/// Request header `Origin` is required but was not provided.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Request header `Origin` is required but was not provided&quot;</span>)]</span>
<span class="ident">MissingOrigin</span>,
<span class="doccomment">/// Request header `Origin` is required but was not provided.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Request header `Origin` is required but was not provided&quot;</span>)]
</span>MissingOrigin,
<span class="doccomment">/// Request header `Access-Control-Request-Method` is required but is missing.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Request header `Access-Control-Request-Method` is required but is missing&quot;</span>)]</span>
<span class="ident">MissingRequestMethod</span>,
<span class="doccomment">/// Request header `Access-Control-Request-Method` is required but is missing.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Request header `Access-Control-Request-Method` is required but is missing&quot;</span>)]
</span>MissingRequestMethod,
<span class="doccomment">/// Request header `Access-Control-Request-Method` has an invalid value.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Request header `Access-Control-Request-Method` has an invalid value&quot;</span>)]</span>
<span class="ident">BadRequestMethod</span>,
<span class="doccomment">/// Request header `Access-Control-Request-Method` has an invalid value.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Request header `Access-Control-Request-Method` has an invalid value&quot;</span>)]
</span>BadRequestMethod,
<span class="doccomment">/// Request header `Access-Control-Request-Headers` has an invalid value.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Request header `Access-Control-Request-Headers` has an invalid value&quot;</span>)]</span>
<span class="ident">BadRequestHeaders</span>,
<span class="doccomment">/// Request header `Access-Control-Request-Headers` has an invalid value.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Request header `Access-Control-Request-Headers` has an invalid value&quot;</span>)]
</span>BadRequestHeaders,
<span class="doccomment">/// Origin is not allowed to make this request.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Origin is not allowed to make this request&quot;</span>)]</span>
<span class="ident">OriginNotAllowed</span>,
<span class="doccomment">/// Origin is not allowed to make this request.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Origin is not allowed to make this request&quot;</span>)]
</span>OriginNotAllowed,
<span class="doccomment">/// Request method is not allowed.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Requested method is not allowed&quot;</span>)]</span>
<span class="ident">MethodNotAllowed</span>,
<span class="doccomment">/// Request method is not allowed.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Requested method is not allowed&quot;</span>)]
</span>MethodNotAllowed,
<span class="doccomment">/// One or more request headers are not allowed.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;One or more request headers are not allowed&quot;</span>)]</span>
<span class="ident">HeadersNotAllowed</span>,
<span class="doccomment">/// One or more request headers are not allowed.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;One or more request headers are not allowed&quot;</span>)]
</span>HeadersNotAllowed,
}
<span class="kw">impl</span> <span class="ident">ResponseError</span> <span class="kw">for</span> <span class="ident">CorsError</span> {
<span class="kw">fn</span> <span class="ident">status_code</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">StatusCode</span> {
<span class="ident">StatusCode::BAD_REQUEST</span>
<span class="kw">impl </span>ResponseError <span class="kw">for </span>CorsError {
<span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
StatusCode::BAD_REQUEST
}
<span class="kw">fn</span> <span class="ident">error_response</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">HttpResponse</span> {
<span class="ident">HttpResponse::with_body</span>(<span class="self">self</span>.<span class="ident">status_code</span>(), <span class="self">self</span>.<span class="ident">to_string</span>()).<span class="ident">map_into_boxed_body</span>()
<span class="kw">fn </span>error_response(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; HttpResponse {
HttpResponse::with_body(<span class="self">self</span>.status_code(), <span class="self">self</span>.to_string()).map_into_boxed_body()
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_cors" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_cors" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -383,388 +383,388 @@
<span id="381">381</span>
<span id="382">382</span>
<span id="383">383</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">collections::HashSet</span>, <span class="ident">convert::TryFrom</span>, <span class="ident">convert::TryInto</span>, <span class="ident">fmt</span>, <span class="ident">rc::Rc</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{collections::HashSet, convert::TryFrom, convert::TryInto, fmt, rc::Rc};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">dev::RequestHead</span>,
<span class="ident">error::Result</span>,
<span class="ident">http</span>::{
<span class="ident">header</span>::{<span class="self">self</span>, <span class="ident">HeaderMap</span>, <span class="ident">HeaderName</span>, <span class="ident">HeaderValue</span>},
<span class="ident">Method</span>,
<span class="kw">use </span>actix_web::{
dev::RequestHead,
error::Result,
http::{
header::{<span class="self">self</span>, HeaderMap, HeaderName, HeaderValue},
Method,
},
};
<span class="kw">use</span> <span class="ident">once_cell::sync::Lazy</span>;
<span class="kw">use</span> <span class="ident">smallvec::SmallVec</span>;
<span class="kw">use </span>once_cell::sync::Lazy;
<span class="kw">use </span>smallvec::SmallVec;
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">AllOrSome</span>, <span class="ident">CorsError</span>};
<span class="kw">use crate</span>::{AllOrSome, CorsError};
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Clone</span>)]</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct</span> <span class="ident">OriginFn</span> {
<span class="attribute">#[<span class="ident">allow</span>(<span class="ident">clippy::type_complexity</span>)]</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">boxed_fn</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="kw">dyn</span> <span class="ident">Fn</span>(<span class="kw-2">&amp;</span><span class="ident">HeaderValue</span>, <span class="kw-2">&amp;</span><span class="ident">RequestHead</span>) -&gt; <span class="ident">bool</span><span class="op">&gt;</span>,
<span class="attribute">#[derive(Clone)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>OriginFn {
<span class="attribute">#[allow(clippy::type_complexity)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) boxed_fn: Rc&lt;<span class="kw">dyn </span>Fn(<span class="kw-2">&amp;</span>HeaderValue, <span class="kw-2">&amp;</span>RequestHead) -&gt; bool&gt;,
}
<span class="kw">impl</span> <span class="ident">Default</span> <span class="kw">for</span> <span class="ident">OriginFn</span> {
<span class="doccomment">/// Dummy default for use in tiny_vec. Do not use.</span>
<span class="kw">fn</span> <span class="ident">default</span>() -&gt; <span class="self">Self</span> {
<span class="kw">let</span> <span class="ident">boxed_fn</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="kw">dyn</span> <span class="ident">Fn</span>(<span class="kw-2">&amp;</span><span class="kw">_</span>, <span class="kw-2">&amp;</span><span class="kw">_</span>) -&gt; <span class="kw">_</span><span class="op">&gt;</span> <span class="op">=</span> <span class="ident">Rc::new</span>(<span class="op">|</span><span class="ident">_origin</span>, <span class="ident">_req_head</span><span class="op">|</span> <span class="bool-val">false</span>);
<span class="self">Self</span> { <span class="ident">boxed_fn</span> }
<span class="kw">impl </span>Default <span class="kw">for </span>OriginFn {
<span class="doccomment">/// Dummy default for use in tiny_vec. Do not use.
</span><span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="kw">let </span>boxed_fn: Rc&lt;<span class="kw">dyn </span>Fn(<span class="kw-2">&amp;</span><span class="kw">_</span>, <span class="kw-2">&amp;</span><span class="kw">_</span>) -&gt; <span class="kw">_</span>&gt; = Rc::new(|_origin, _req_head| <span class="bool-val">false</span>);
<span class="self">Self </span>{ boxed_fn }
}
}
<span class="kw">impl</span> <span class="ident">fmt::Debug</span> <span class="kw">for</span> <span class="ident">OriginFn</span> {
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="ident">f</span>.<span class="ident">write_str</span>(<span class="string">&quot;origin_fn&quot;</span>)
<span class="kw">impl </span>fmt::Debug <span class="kw">for </span>OriginFn {
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
f.write_str(<span class="string">&quot;origin_fn&quot;</span>)
}
}
<span class="doccomment">/// Try to parse header value as HTTP method.</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">header_value_try_into_method</span>(<span class="ident">hdr</span>: <span class="kw-2">&amp;</span><span class="ident">HeaderValue</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Method</span><span class="op">&gt;</span> {
<span class="ident">hdr</span>.<span class="ident">to_str</span>()
.<span class="ident">ok</span>()
.<span class="ident">and_then</span>(<span class="op">|</span><span class="ident">meth</span><span class="op">|</span> <span class="ident">Method::try_from</span>(<span class="ident">meth</span>).<span class="ident">ok</span>())
<span class="doccomment">/// Try to parse header value as HTTP method.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>header_value_try_into_method(hdr: <span class="kw-2">&amp;</span>HeaderValue) -&gt; <span class="prelude-ty">Option</span>&lt;Method&gt; {
hdr.to_str()
.ok()
.and_then(|meth| Method::try_from(meth).ok())
}
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct</span> <span class="ident">Inner</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">allowed_origins</span>: <span class="ident">AllOrSome</span><span class="op">&lt;</span><span class="ident">HashSet</span><span class="op">&lt;</span><span class="ident">HeaderValue</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">allowed_origins_fns</span>: <span class="ident">SmallVec</span><span class="op">&lt;</span>[<span class="ident">OriginFn</span>; <span class="number">4</span>]<span class="op">&gt;</span>,
<span class="attribute">#[derive(Debug, Clone)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>Inner {
<span class="kw">pub</span>(<span class="kw">crate</span>) allowed_origins: AllOrSome&lt;HashSet&lt;HeaderValue&gt;&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) allowed_origins_fns: SmallVec&lt;[OriginFn; <span class="number">4</span>]&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">allowed_methods</span>: <span class="ident">HashSet</span><span class="op">&lt;</span><span class="ident">Method</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">allowed_methods_baked</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">HeaderValue</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) allowed_methods: HashSet&lt;Method&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) allowed_methods_baked: <span class="prelude-ty">Option</span>&lt;HeaderValue&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">allowed_headers</span>: <span class="ident">AllOrSome</span><span class="op">&lt;</span><span class="ident">HashSet</span><span class="op">&lt;</span><span class="ident">HeaderName</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">allowed_headers_baked</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">HeaderValue</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) allowed_headers: AllOrSome&lt;HashSet&lt;HeaderName&gt;&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) allowed_headers_baked: <span class="prelude-ty">Option</span>&lt;HeaderValue&gt;,
<span class="doccomment">/// `All` will echo back `Access-Control-Request-Header` list.</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">expose_headers</span>: <span class="ident">AllOrSome</span><span class="op">&lt;</span><span class="ident">HashSet</span><span class="op">&lt;</span><span class="ident">HeaderName</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">expose_headers_baked</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">HeaderValue</span><span class="op">&gt;</span>,
<span class="doccomment">/// `All` will echo back `Access-Control-Request-Header` list.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) expose_headers: AllOrSome&lt;HashSet&lt;HeaderName&gt;&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) expose_headers_baked: <span class="prelude-ty">Option</span>&lt;HeaderValue&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">max_age</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">usize</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">preflight</span>: <span class="ident">bool</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">send_wildcard</span>: <span class="ident">bool</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">supports_credentials</span>: <span class="ident">bool</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">vary_header</span>: <span class="ident">bool</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) max_age: <span class="prelude-ty">Option</span>&lt;usize&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) preflight: bool,
<span class="kw">pub</span>(<span class="kw">crate</span>) send_wildcard: bool,
<span class="kw">pub</span>(<span class="kw">crate</span>) supports_credentials: bool,
<span class="kw">pub</span>(<span class="kw">crate</span>) vary_header: bool,
}
<span class="kw">static</span> <span class="ident">EMPTY_ORIGIN_SET</span>: <span class="ident">Lazy</span><span class="op">&lt;</span><span class="ident">HashSet</span><span class="op">&lt;</span><span class="ident">HeaderValue</span><span class="op">&gt;</span><span class="op">&gt;</span> <span class="op">=</span> <span class="ident">Lazy::new</span>(<span class="ident">HashSet::new</span>);
<span class="kw">static </span>EMPTY_ORIGIN_SET: Lazy&lt;HashSet&lt;HeaderValue&gt;&gt; = Lazy::new(HashSet::new);
<span class="kw">impl</span> <span class="ident">Inner</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">validate_origin</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">RequestHead</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">CorsError</span><span class="op">&gt;</span> {
<span class="comment">// return early if all origins are allowed or get ref to allowed origins set</span>
<span class="attribute">#[<span class="ident">allow</span>(<span class="ident">clippy::mutable_key_type</span>)]</span>
<span class="kw">let</span> <span class="ident">allowed_origins</span> <span class="op">=</span> <span class="kw">match</span> <span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">allowed_origins</span> {
<span class="ident">AllOrSome::All</span> <span class="kw">if</span> <span class="self">self</span>.<span class="ident">allowed_origins_fns</span>.<span class="ident">is_empty</span>() =&gt; <span class="kw">return</span> <span class="prelude-val">Ok</span>(()),
<span class="ident">AllOrSome::Some</span>(<span class="ident">allowed_origins</span>) =&gt; <span class="ident">allowed_origins</span>,
<span class="comment">// only function origin validators are defined</span>
<span class="kw">_</span> =&gt; <span class="kw-2">&amp;</span><span class="ident">EMPTY_ORIGIN_SET</span>,
<span class="kw">impl </span>Inner {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>validate_origin(<span class="kw-2">&amp;</span><span class="self">self</span>, req: <span class="kw-2">&amp;</span>RequestHead) -&gt; <span class="prelude-ty">Result</span>&lt;(), CorsError&gt; {
<span class="comment">// return early if all origins are allowed or get ref to allowed origins set
</span><span class="attribute">#[allow(clippy::mutable_key_type)]
</span><span class="kw">let </span>allowed_origins = <span class="kw">match </span><span class="kw-2">&amp;</span><span class="self">self</span>.allowed_origins {
AllOrSome::All <span class="kw">if </span><span class="self">self</span>.allowed_origins_fns.is_empty() =&gt; <span class="kw">return </span><span class="prelude-val">Ok</span>(()),
AllOrSome::Some(allowed_origins) =&gt; allowed_origins,
<span class="comment">// only function origin validators are defined
</span><span class="kw">_ </span>=&gt; <span class="kw-2">&amp;</span>EMPTY_ORIGIN_SET,
};
<span class="comment">// get origin header and try to parse as string</span>
<span class="kw">match</span> <span class="ident">req</span>.<span class="ident">headers</span>().<span class="ident">get</span>(<span class="ident">header::ORIGIN</span>) {
<span class="comment">// origin header exists and is a string</span>
<span class="prelude-val">Some</span>(<span class="ident">origin</span>) =&gt; {
<span class="kw">if</span> <span class="ident">allowed_origins</span>.<span class="ident">contains</span>(<span class="ident">origin</span>) <span class="op">|</span><span class="op">|</span> <span class="self">self</span>.<span class="ident">validate_origin_fns</span>(<span class="ident">origin</span>, <span class="ident">req</span>) {
<span class="comment">// get origin header and try to parse as string
</span><span class="kw">match </span>req.headers().get(header::ORIGIN) {
<span class="comment">// origin header exists and is a string
</span><span class="prelude-val">Some</span>(origin) =&gt; {
<span class="kw">if </span>allowed_origins.contains(origin) || <span class="self">self</span>.validate_origin_fns(origin, req) {
<span class="prelude-val">Ok</span>(())
} <span class="kw">else</span> {
<span class="prelude-val">Err</span>(<span class="ident">CorsError::OriginNotAllowed</span>)
} <span class="kw">else </span>{
<span class="prelude-val">Err</span>(CorsError::OriginNotAllowed)
}
}
<span class="comment">// origin header is missing</span>
<span class="comment">// note: with our implementation, the origin header is required for OPTIONS request or</span>
<span class="comment">// else this would be unreachable</span>
<span class="prelude-val">None</span> =&gt; <span class="prelude-val">Err</span>(<span class="ident">CorsError::MissingOrigin</span>),
<span class="comment">// origin header is missing
// note: with our implementation, the origin header is required for OPTIONS request or
// else this would be unreachable
</span><span class="prelude-val">None </span>=&gt; <span class="prelude-val">Err</span>(CorsError::MissingOrigin),
}
}
<span class="doccomment">/// Accepts origin if _ANY_ functions return true. Only called when Origin exists.</span>
<span class="kw">fn</span> <span class="ident">validate_origin_fns</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">origin</span>: <span class="kw-2">&amp;</span><span class="ident">HeaderValue</span>, <span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">RequestHead</span>) -&gt; <span class="ident">bool</span> {
<span class="self">self</span>.<span class="ident">allowed_origins_fns</span>
.<span class="ident">iter</span>()
.<span class="ident">any</span>(<span class="op">|</span><span class="ident">origin_fn</span><span class="op">|</span> (<span class="ident">origin_fn</span>.<span class="ident">boxed_fn</span>)(<span class="ident">origin</span>, <span class="ident">req</span>))
<span class="doccomment">/// Accepts origin if _ANY_ functions return true. Only called when Origin exists.
</span><span class="kw">fn </span>validate_origin_fns(<span class="kw-2">&amp;</span><span class="self">self</span>, origin: <span class="kw-2">&amp;</span>HeaderValue, req: <span class="kw-2">&amp;</span>RequestHead) -&gt; bool {
<span class="self">self</span>.allowed_origins_fns
.iter()
.any(|origin_fn| (origin_fn.boxed_fn)(origin, req))
}
<span class="doccomment">/// Only called if origin exists and always after it&#39;s validated.</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">access_control_allow_origin</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">RequestHead</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">HeaderValue</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">origin</span> <span class="op">=</span> <span class="ident">req</span>.<span class="ident">headers</span>().<span class="ident">get</span>(<span class="ident">header::ORIGIN</span>);
<span class="doccomment">/// Only called if origin exists and always after it&#39;s validated.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>access_control_allow_origin(<span class="kw-2">&amp;</span><span class="self">self</span>, req: <span class="kw-2">&amp;</span>RequestHead) -&gt; <span class="prelude-ty">Option</span>&lt;HeaderValue&gt; {
<span class="kw">let </span>origin = req.headers().get(header::ORIGIN);
<span class="kw">match</span> <span class="self">self</span>.<span class="ident">allowed_origins</span> {
<span class="ident">AllOrSome::All</span> =&gt; {
<span class="kw">if</span> <span class="self">self</span>.<span class="ident">send_wildcard</span> {
<span class="prelude-val">Some</span>(<span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;*&quot;</span>))
} <span class="kw">else</span> {
<span class="comment">// see note below about why `.cloned()` is correct</span>
<span class="ident">origin</span>.<span class="ident">cloned</span>()
<span class="kw">match </span><span class="self">self</span>.allowed_origins {
AllOrSome::All =&gt; {
<span class="kw">if </span><span class="self">self</span>.send_wildcard {
<span class="prelude-val">Some</span>(HeaderValue::from_static(<span class="string">&quot;*&quot;</span>))
} <span class="kw">else </span>{
<span class="comment">// see note below about why `.cloned()` is correct
</span>origin.cloned()
}
}
<span class="ident">AllOrSome::Some</span>(<span class="kw">_</span>) =&gt; {
<span class="comment">// since origin (if it exists) is known to be allowed if this method is called</span>
<span class="comment">// then cloning the option is all that is required to be used as an echoed back</span>
<span class="comment">// header value (or omitted if None)</span>
<span class="ident">origin</span>.<span class="ident">cloned</span>()
AllOrSome::Some(<span class="kw">_</span>) =&gt; {
<span class="comment">// since origin (if it exists) is known to be allowed if this method is called
// then cloning the option is all that is required to be used as an echoed back
// header value (or omitted if None)
</span>origin.cloned()
}
}
}
<span class="doccomment">/// Use in preflight checks and therefore operates on header list in</span>
<span class="doccomment">/// `Access-Control-Request-Headers` not the actual header set.</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">validate_allowed_method</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">RequestHead</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">CorsError</span><span class="op">&gt;</span> {
<span class="comment">// extract access control header and try to parse as method</span>
<span class="kw">let</span> <span class="ident">request_method</span> <span class="op">=</span> <span class="ident">req</span>
.<span class="ident">headers</span>()
.<span class="ident">get</span>(<span class="ident">header::ACCESS_CONTROL_REQUEST_METHOD</span>)
.<span class="ident">map</span>(<span class="ident">header_value_try_into_method</span>);
<span class="doccomment">/// Use in preflight checks and therefore operates on header list in
/// `Access-Control-Request-Headers` not the actual header set.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>validate_allowed_method(<span class="kw-2">&amp;</span><span class="self">self</span>, req: <span class="kw-2">&amp;</span>RequestHead) -&gt; <span class="prelude-ty">Result</span>&lt;(), CorsError&gt; {
<span class="comment">// extract access control header and try to parse as method
</span><span class="kw">let </span>request_method = req
.headers()
.get(header::ACCESS_CONTROL_REQUEST_METHOD)
.map(header_value_try_into_method);
<span class="kw">match</span> <span class="ident">request_method</span> {
<span class="comment">// method valid and allowed</span>
<span class="prelude-val">Some</span>(<span class="prelude-val">Some</span>(<span class="ident">method</span>)) <span class="kw">if</span> <span class="self">self</span>.<span class="ident">allowed_methods</span>.<span class="ident">contains</span>(<span class="kw-2">&amp;</span><span class="ident">method</span>) =&gt; <span class="prelude-val">Ok</span>(()),
<span class="kw">match </span>request_method {
<span class="comment">// method valid and allowed
</span><span class="prelude-val">Some</span>(<span class="prelude-val">Some</span>(method)) <span class="kw">if </span><span class="self">self</span>.allowed_methods.contains(<span class="kw-2">&amp;</span>method) =&gt; <span class="prelude-val">Ok</span>(()),
<span class="comment">// method valid but not allowed</span>
<span class="prelude-val">Some</span>(<span class="prelude-val">Some</span>(<span class="kw">_</span>)) =&gt; <span class="prelude-val">Err</span>(<span class="ident">CorsError::MethodNotAllowed</span>),
<span class="comment">// method valid but not allowed
</span><span class="prelude-val">Some</span>(<span class="prelude-val">Some</span>(<span class="kw">_</span>)) =&gt; <span class="prelude-val">Err</span>(CorsError::MethodNotAllowed),
<span class="comment">// method invalid</span>
<span class="prelude-val">Some</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(<span class="ident">CorsError::BadRequestMethod</span>),
<span class="comment">// method invalid
</span><span class="prelude-val">Some</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(CorsError::BadRequestMethod),
<span class="comment">// method missing so this is not a preflight request</span>
<span class="prelude-val">None</span> =&gt; <span class="prelude-val">Err</span>(<span class="ident">CorsError::MissingRequestMethod</span>),
<span class="comment">// method missing so this is not a preflight request
</span><span class="prelude-val">None </span>=&gt; <span class="prelude-val">Err</span>(CorsError::MissingRequestMethod),
}
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">validate_allowed_headers</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">RequestHead</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">CorsError</span><span class="op">&gt;</span> {
<span class="comment">// return early if all headers are allowed or get ref to allowed origins set</span>
<span class="attribute">#[<span class="ident">allow</span>(<span class="ident">clippy::mutable_key_type</span>)]</span>
<span class="kw">let</span> <span class="ident">allowed_headers</span> <span class="op">=</span> <span class="kw">match</span> <span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">allowed_headers</span> {
<span class="ident">AllOrSome::All</span> =&gt; <span class="kw">return</span> <span class="prelude-val">Ok</span>(()),
<span class="ident">AllOrSome::Some</span>(<span class="ident">allowed_headers</span>) =&gt; <span class="ident">allowed_headers</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>validate_allowed_headers(<span class="kw-2">&amp;</span><span class="self">self</span>, req: <span class="kw-2">&amp;</span>RequestHead) -&gt; <span class="prelude-ty">Result</span>&lt;(), CorsError&gt; {
<span class="comment">// return early if all headers are allowed or get ref to allowed origins set
</span><span class="attribute">#[allow(clippy::mutable_key_type)]
</span><span class="kw">let </span>allowed_headers = <span class="kw">match </span><span class="kw-2">&amp;</span><span class="self">self</span>.allowed_headers {
AllOrSome::All =&gt; <span class="kw">return </span><span class="prelude-val">Ok</span>(()),
AllOrSome::Some(allowed_headers) =&gt; allowed_headers,
};
<span class="comment">// extract access control header as string</span>
<span class="comment">// header format should be comma separated header names</span>
<span class="kw">let</span> <span class="ident">request_headers</span> <span class="op">=</span> <span class="ident">req</span>
.<span class="ident">headers</span>()
.<span class="ident">get</span>(<span class="ident">header::ACCESS_CONTROL_REQUEST_HEADERS</span>)
.<span class="ident">map</span>(<span class="op">|</span><span class="ident">hdr</span><span class="op">|</span> <span class="ident">hdr</span>.<span class="ident">to_str</span>());
<span class="comment">// extract access control header as string
// header format should be comma separated header names
</span><span class="kw">let </span>request_headers = req
.headers()
.get(header::ACCESS_CONTROL_REQUEST_HEADERS)
.map(|hdr| hdr.to_str());
<span class="kw">match</span> <span class="ident">request_headers</span> {
<span class="comment">// header list is valid string</span>
<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(<span class="ident">headers</span>)) =&gt; {
<span class="comment">// the set is ephemeral we take care not to mutate the</span>
<span class="comment">// inserted keys so this lint exception is acceptable</span>
<span class="attribute">#[<span class="ident">allow</span>(<span class="ident">clippy::mutable_key_type</span>)]</span>
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">request_headers</span> <span class="op">=</span> <span class="ident">HashSet::with_capacity</span>(<span class="number">8</span>);
<span class="kw">match </span>request_headers {
<span class="comment">// header list is valid string
</span><span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(headers)) =&gt; {
<span class="comment">// the set is ephemeral we take care not to mutate the
// inserted keys so this lint exception is acceptable
</span><span class="attribute">#[allow(clippy::mutable_key_type)]
</span><span class="kw">let </span><span class="kw-2">mut </span>request_headers = HashSet::with_capacity(<span class="number">8</span>);
<span class="comment">// try to convert each header name in the comma-separated list</span>
<span class="kw">for</span> <span class="ident">hdr</span> <span class="kw">in</span> <span class="ident">headers</span>.<span class="ident">split</span>(<span class="string">&#39;,&#39;</span>) {
<span class="kw">match</span> <span class="ident">hdr</span>.<span class="ident">trim</span>().<span class="ident">try_into</span>() {
<span class="prelude-val">Ok</span>(<span class="ident">hdr</span>) =&gt; <span class="ident">request_headers</span>.<span class="ident">insert</span>(<span class="ident">hdr</span>),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="kw">return</span> <span class="prelude-val">Err</span>(<span class="ident">CorsError::BadRequestHeaders</span>),
<span class="comment">// try to convert each header name in the comma-separated list
</span><span class="kw">for </span>hdr <span class="kw">in </span>headers.split(<span class="string">&#39;,&#39;</span>) {
<span class="kw">match </span>hdr.trim().try_into() {
<span class="prelude-val">Ok</span>(hdr) =&gt; request_headers.insert(hdr),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(CorsError::BadRequestHeaders),
};
}
<span class="comment">// header list must contain 1 or more header name</span>
<span class="kw">if</span> <span class="ident">request_headers</span>.<span class="ident">is_empty</span>() {
<span class="kw">return</span> <span class="prelude-val">Err</span>(<span class="ident">CorsError::BadRequestHeaders</span>);
<span class="comment">// header list must contain 1 or more header name
</span><span class="kw">if </span>request_headers.is_empty() {
<span class="kw">return </span><span class="prelude-val">Err</span>(CorsError::BadRequestHeaders);
}
<span class="comment">// request header list must be a subset of allowed headers</span>
<span class="kw">if</span> <span class="op">!</span><span class="ident">request_headers</span>.<span class="ident">is_subset</span>(<span class="ident">allowed_headers</span>) {
<span class="kw">return</span> <span class="prelude-val">Err</span>(<span class="ident">CorsError::HeadersNotAllowed</span>);
<span class="comment">// request header list must be a subset of allowed headers
</span><span class="kw">if </span>!request_headers.is_subset(allowed_headers) {
<span class="kw">return </span><span class="prelude-val">Err</span>(CorsError::HeadersNotAllowed);
}
<span class="prelude-val">Ok</span>(())
}
<span class="comment">// header list is not a string</span>
<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(<span class="kw">_</span>)) =&gt; <span class="prelude-val">Err</span>(<span class="ident">CorsError::BadRequestHeaders</span>),
<span class="comment">// header list is not a string
</span><span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(<span class="kw">_</span>)) =&gt; <span class="prelude-val">Err</span>(CorsError::BadRequestHeaders),
<span class="comment">// header list missing</span>
<span class="prelude-val">None</span> =&gt; <span class="prelude-val">Ok</span>(()),
<span class="comment">// header list missing
</span><span class="prelude-val">None </span>=&gt; <span class="prelude-val">Ok</span>(()),
}
}
}
<span class="doccomment">/// Add CORS related request headers to response&#39;s Vary header.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// See &lt;https://fetch.spec.whatwg.org/#cors-protocol-and-http-caches&gt;.</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">add_vary_header</span>(<span class="ident">headers</span>: <span class="kw-2">&amp;mut</span> <span class="ident">HeaderMap</span>) {
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="kw">match</span> <span class="ident">headers</span>.<span class="ident">get</span>(<span class="ident">header::VARY</span>) {
<span class="prelude-val">Some</span>(<span class="ident">hdr</span>) =&gt; {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">val</span>: <span class="ident">Vec</span><span class="op">&lt;</span><span class="ident">u8</span><span class="op">&gt;</span> <span class="op">=</span> <span class="ident">Vec::with_capacity</span>(<span class="ident">hdr</span>.<span class="ident">len</span>() <span class="op">+</span> <span class="number">71</span>);
<span class="ident">val</span>.<span class="ident">extend</span>(<span class="ident">hdr</span>.<span class="ident">as_bytes</span>());
<span class="ident">val</span>.<span class="ident">extend</span>(<span class="string">b&quot;, Origin, Access-Control-Request-Method, Access-Control-Request-Headers&quot;</span>);
<span class="ident">val</span>.<span class="ident">try_into</span>().<span class="ident">unwrap</span>()
<span class="doccomment">/// Add CORS related request headers to response&#39;s Vary header.
///
/// See &lt;https://fetch.spec.whatwg.org/#cors-protocol-and-http-caches&gt;.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>add_vary_header(headers: <span class="kw-2">&amp;mut </span>HeaderMap) {
<span class="kw">let </span>value = <span class="kw">match </span>headers.get(header::VARY) {
<span class="prelude-val">Some</span>(hdr) =&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>val: Vec&lt;u8&gt; = Vec::with_capacity(hdr.len() + <span class="number">71</span>);
val.extend(hdr.as_bytes());
val.extend(<span class="string">b&quot;, Origin, Access-Control-Request-Method, Access-Control-Request-Headers&quot;</span>);
val.try_into().unwrap()
}
<span class="prelude-val">None</span> =&gt; <span class="ident">HeaderValue::from_static</span>(
<span class="prelude-val">None </span>=&gt; HeaderValue::from_static(
<span class="string">&quot;Origin, Access-Control-Request-Method, Access-Control-Request-Headers&quot;</span>,
),
};
<span class="ident">headers</span>.<span class="ident">insert</span>(<span class="ident">header::VARY</span>, <span class="ident">value</span>);
headers.insert(header::VARY, value);
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">test</span> {
<span class="kw">use</span> <span class="ident">std::rc::Rc</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>test {
<span class="kw">use </span>std::rc::Rc;
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">dev::Transform</span>,
<span class="ident">http</span>::{
<span class="ident">header</span>::{<span class="self">self</span>, <span class="ident">HeaderValue</span>},
<span class="ident">Method</span>, <span class="ident">StatusCode</span>,
<span class="kw">use </span>actix_web::{
dev::Transform,
http::{
header::{<span class="self">self</span>, HeaderValue},
Method, StatusCode,
},
<span class="ident">test</span>::{<span class="self">self</span>, <span class="ident">TestRequest</span>},
test::{<span class="self">self</span>, TestRequest},
};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::Cors</span>;
<span class="kw">use </span><span class="kw">crate</span>::Cors;
<span class="kw">fn</span> <span class="ident">val_as_str</span>(<span class="ident">val</span>: <span class="kw-2">&amp;</span><span class="ident">HeaderValue</span>) -&gt; <span class="kw-2">&amp;</span><span class="ident">str</span> {
<span class="ident">val</span>.<span class="ident">to_str</span>().<span class="ident">unwrap</span>()
<span class="kw">fn </span>val_as_str(val: <span class="kw-2">&amp;</span>HeaderValue) -&gt; <span class="kw-2">&amp;</span>str {
val.to_str().unwrap()
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_validate_not_allowed_origin</span>() {
<span class="kw">let</span> <span class="ident">cors</span> <span class="op">=</span> <span class="ident">Cors::default</span>()
.<span class="ident">allowed_origin</span>(<span class="string">&quot;https://www.example.com&quot;</span>)
.<span class="ident">new_transform</span>(<span class="ident">test::ok_service</span>())
.<span class="kw">await</span>
.<span class="ident">unwrap</span>();
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_validate_not_allowed_origin() {
<span class="kw">let </span>cors = Cors::default()
.allowed_origin(<span class="string">&quot;https://www.example.com&quot;</span>)
.new_transform(test::ok_service())
.<span class="kw">await
</span>.unwrap();
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::get</span>()
.<span class="ident">insert_header</span>((<span class="ident">header::ORIGIN</span>, <span class="string">&quot;https://www.unknown.com&quot;</span>))
.<span class="ident">insert_header</span>((<span class="ident">header::ACCESS_CONTROL_REQUEST_HEADERS</span>, <span class="string">&quot;DNT&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let </span>req = TestRequest::get()
.insert_header((header::ORIGIN, <span class="string">&quot;https://www.unknown.com&quot;</span>))
.insert_header((header::ACCESS_CONTROL_REQUEST_HEADERS, <span class="string">&quot;DNT&quot;</span>))
.to_srv_request();
<span class="macro">assert!</span>(<span class="ident">cors</span>.<span class="ident">inner</span>.<span class="ident">validate_origin</span>(<span class="ident">req</span>.<span class="ident">head</span>()).<span class="ident">is_err</span>());
<span class="macro">assert!</span>(<span class="ident">cors</span>.<span class="ident">inner</span>.<span class="ident">validate_allowed_method</span>(<span class="ident">req</span>.<span class="ident">head</span>()).<span class="ident">is_err</span>());
<span class="macro">assert!</span>(<span class="ident">cors</span>.<span class="ident">inner</span>.<span class="ident">validate_allowed_headers</span>(<span class="ident">req</span>.<span class="ident">head</span>()).<span class="ident">is_err</span>());
<span class="macro">assert!</span>(cors.inner.validate_origin(req.head()).is_err());
<span class="macro">assert!</span>(cors.inner.validate_allowed_method(req.head()).is_err());
<span class="macro">assert!</span>(cors.inner.validate_allowed_headers(req.head()).is_err());
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_preflight</span>() {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">cors</span> <span class="op">=</span> <span class="ident">Cors::default</span>()
.<span class="ident">allow_any_origin</span>()
.<span class="ident">send_wildcard</span>()
.<span class="ident">max_age</span>(<span class="number">3600</span>)
.<span class="ident">allowed_methods</span>(<span class="macro">vec!</span>[<span class="ident">Method::GET</span>, <span class="ident">Method::OPTIONS</span>, <span class="ident">Method::POST</span>])
.<span class="ident">allowed_headers</span>(<span class="macro">vec!</span>[<span class="ident">header::AUTHORIZATION</span>, <span class="ident">header::ACCEPT</span>])
.<span class="ident">allowed_header</span>(<span class="ident">header::CONTENT_TYPE</span>)
.<span class="ident">new_transform</span>(<span class="ident">test::ok_service</span>())
.<span class="kw">await</span>
.<span class="ident">unwrap</span>();
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_preflight() {
<span class="kw">let </span><span class="kw-2">mut </span>cors = Cors::default()
.allow_any_origin()
.send_wildcard()
.max_age(<span class="number">3600</span>)
.allowed_methods(<span class="macro">vec!</span>[Method::GET, Method::OPTIONS, Method::POST])
.allowed_headers(<span class="macro">vec!</span>[header::AUTHORIZATION, header::ACCEPT])
.allowed_header(header::CONTENT_TYPE)
.new_transform(test::ok_service())
.<span class="kw">await
</span>.unwrap();
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::default</span>()
.<span class="ident">method</span>(<span class="ident">Method::OPTIONS</span>)
.<span class="ident">insert_header</span>((<span class="string">&quot;Origin&quot;</span>, <span class="string">&quot;https://www.example.com&quot;</span>))
.<span class="ident">insert_header</span>((<span class="ident">header::ACCESS_CONTROL_REQUEST_HEADERS</span>, <span class="string">&quot;X-Not-Allowed&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let </span>req = TestRequest::default()
.method(Method::OPTIONS)
.insert_header((<span class="string">&quot;Origin&quot;</span>, <span class="string">&quot;https://www.example.com&quot;</span>))
.insert_header((header::ACCESS_CONTROL_REQUEST_HEADERS, <span class="string">&quot;X-Not-Allowed&quot;</span>))
.to_srv_request();
<span class="macro">assert!</span>(<span class="ident">cors</span>.<span class="ident">inner</span>.<span class="ident">validate_allowed_method</span>(<span class="ident">req</span>.<span class="ident">head</span>()).<span class="ident">is_err</span>());
<span class="macro">assert!</span>(<span class="ident">cors</span>.<span class="ident">inner</span>.<span class="ident">validate_allowed_headers</span>(<span class="ident">req</span>.<span class="ident">head</span>()).<span class="ident">is_err</span>());
<span class="kw">let</span> <span class="ident">resp</span> <span class="op">=</span> <span class="ident">test::call_service</span>(<span class="kw-2">&amp;</span><span class="ident">cors</span>, <span class="ident">req</span>).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(<span class="ident">resp</span>.<span class="ident">status</span>(), <span class="ident">StatusCode::OK</span>);
<span class="macro">assert!</span>(cors.inner.validate_allowed_method(req.head()).is_err());
<span class="macro">assert!</span>(cors.inner.validate_allowed_headers(req.head()).is_err());
<span class="kw">let </span>resp = test::call_service(<span class="kw-2">&amp;</span>cors, req).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::OK);
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::default</span>()
.<span class="ident">method</span>(<span class="ident">Method::OPTIONS</span>)
.<span class="ident">insert_header</span>((<span class="string">&quot;Origin&quot;</span>, <span class="string">&quot;https://www.example.com&quot;</span>))
.<span class="ident">insert_header</span>((<span class="ident">header::ACCESS_CONTROL_REQUEST_METHOD</span>, <span class="string">&quot;put&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let </span>req = TestRequest::default()
.method(Method::OPTIONS)
.insert_header((<span class="string">&quot;Origin&quot;</span>, <span class="string">&quot;https://www.example.com&quot;</span>))
.insert_header((header::ACCESS_CONTROL_REQUEST_METHOD, <span class="string">&quot;put&quot;</span>))
.to_srv_request();
<span class="macro">assert!</span>(<span class="ident">cors</span>.<span class="ident">inner</span>.<span class="ident">validate_allowed_method</span>(<span class="ident">req</span>.<span class="ident">head</span>()).<span class="ident">is_err</span>());
<span class="macro">assert!</span>(<span class="ident">cors</span>.<span class="ident">inner</span>.<span class="ident">validate_allowed_headers</span>(<span class="ident">req</span>.<span class="ident">head</span>()).<span class="ident">is_ok</span>());
<span class="macro">assert!</span>(cors.inner.validate_allowed_method(req.head()).is_err());
<span class="macro">assert!</span>(cors.inner.validate_allowed_headers(req.head()).is_ok());
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::default</span>()
.<span class="ident">method</span>(<span class="ident">Method::OPTIONS</span>)
.<span class="ident">insert_header</span>((<span class="string">&quot;Origin&quot;</span>, <span class="string">&quot;https://www.example.com&quot;</span>))
.<span class="ident">insert_header</span>((<span class="ident">header::ACCESS_CONTROL_REQUEST_METHOD</span>, <span class="string">&quot;POST&quot;</span>))
.<span class="ident">insert_header</span>((
<span class="ident">header::ACCESS_CONTROL_REQUEST_HEADERS</span>,
<span class="kw">let </span>req = TestRequest::default()
.method(Method::OPTIONS)
.insert_header((<span class="string">&quot;Origin&quot;</span>, <span class="string">&quot;https://www.example.com&quot;</span>))
.insert_header((header::ACCESS_CONTROL_REQUEST_METHOD, <span class="string">&quot;POST&quot;</span>))
.insert_header((
header::ACCESS_CONTROL_REQUEST_HEADERS,
<span class="string">&quot;AUTHORIZATION,ACCEPT&quot;</span>,
))
.<span class="ident">to_srv_request</span>();
.to_srv_request();
<span class="kw">let</span> <span class="ident">resp</span> <span class="op">=</span> <span class="ident">test::call_service</span>(<span class="kw-2">&amp;</span><span class="ident">cors</span>, <span class="ident">req</span>).<span class="kw">await</span>;
<span class="kw">let </span>resp = test::call_service(<span class="kw-2">&amp;</span>cors, req).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(
<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="string">b&quot;*&quot;</span>[..]),
<span class="ident">resp</span>.<span class="ident">headers</span>()
.<span class="ident">get</span>(<span class="ident">header::ACCESS_CONTROL_ALLOW_ORIGIN</span>)
.<span class="ident">map</span>(<span class="ident">HeaderValue::as_bytes</span>)
resp.headers()
.get(header::ACCESS_CONTROL_ALLOW_ORIGIN)
.map(HeaderValue::as_bytes)
);
<span class="macro">assert_eq!</span>(
<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="string">b&quot;3600&quot;</span>[..]),
<span class="ident">resp</span>.<span class="ident">headers</span>()
.<span class="ident">get</span>(<span class="ident">header::ACCESS_CONTROL_MAX_AGE</span>)
.<span class="ident">map</span>(<span class="ident">HeaderValue::as_bytes</span>)
resp.headers()
.get(header::ACCESS_CONTROL_MAX_AGE)
.map(HeaderValue::as_bytes)
);
<span class="kw">let</span> <span class="ident">hdr</span> <span class="op">=</span> <span class="ident">resp</span>
.<span class="ident">headers</span>()
.<span class="ident">get</span>(<span class="ident">header::ACCESS_CONTROL_ALLOW_HEADERS</span>)
.<span class="ident">map</span>(<span class="ident">val_as_str</span>)
.<span class="ident">unwrap</span>();
<span class="macro">assert!</span>(<span class="ident">hdr</span>.<span class="ident">contains</span>(<span class="string">&quot;authorization&quot;</span>));
<span class="macro">assert!</span>(<span class="ident">hdr</span>.<span class="ident">contains</span>(<span class="string">&quot;accept&quot;</span>));
<span class="macro">assert!</span>(<span class="ident">hdr</span>.<span class="ident">contains</span>(<span class="string">&quot;content-type&quot;</span>));
<span class="kw">let </span>hdr = resp
.headers()
.get(header::ACCESS_CONTROL_ALLOW_HEADERS)
.map(val_as_str)
.unwrap();
<span class="macro">assert!</span>(hdr.contains(<span class="string">&quot;authorization&quot;</span>));
<span class="macro">assert!</span>(hdr.contains(<span class="string">&quot;accept&quot;</span>));
<span class="macro">assert!</span>(hdr.contains(<span class="string">&quot;content-type&quot;</span>));
<span class="kw">let</span> <span class="ident">methods</span> <span class="op">=</span> <span class="ident">resp</span>
.<span class="ident">headers</span>()
.<span class="ident">get</span>(<span class="ident">header::ACCESS_CONTROL_ALLOW_METHODS</span>)
.<span class="ident">unwrap</span>()
.<span class="ident">to_str</span>()
.<span class="ident">unwrap</span>();
<span class="macro">assert!</span>(<span class="ident">methods</span>.<span class="ident">contains</span>(<span class="string">&quot;POST&quot;</span>));
<span class="macro">assert!</span>(<span class="ident">methods</span>.<span class="ident">contains</span>(<span class="string">&quot;GET&quot;</span>));
<span class="macro">assert!</span>(<span class="ident">methods</span>.<span class="ident">contains</span>(<span class="string">&quot;OPTIONS&quot;</span>));
<span class="kw">let </span>methods = resp
.headers()
.get(header::ACCESS_CONTROL_ALLOW_METHODS)
.unwrap()
.to_str()
.unwrap();
<span class="macro">assert!</span>(methods.contains(<span class="string">&quot;POST&quot;</span>));
<span class="macro">assert!</span>(methods.contains(<span class="string">&quot;GET&quot;</span>));
<span class="macro">assert!</span>(methods.contains(<span class="string">&quot;OPTIONS&quot;</span>));
<span class="ident">Rc::get_mut</span>(<span class="kw-2">&amp;mut</span> <span class="ident">cors</span>.<span class="ident">inner</span>).<span class="ident">unwrap</span>().<span class="ident">preflight</span> <span class="op">=</span> <span class="bool-val">false</span>;
Rc::get_mut(<span class="kw-2">&amp;mut </span>cors.inner).unwrap().preflight = <span class="bool-val">false</span>;
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::default</span>()
.<span class="ident">method</span>(<span class="ident">Method::OPTIONS</span>)
.<span class="ident">insert_header</span>((<span class="string">&quot;Origin&quot;</span>, <span class="string">&quot;https://www.example.com&quot;</span>))
.<span class="ident">insert_header</span>((<span class="ident">header::ACCESS_CONTROL_REQUEST_METHOD</span>, <span class="string">&quot;POST&quot;</span>))
.<span class="ident">insert_header</span>((
<span class="ident">header::ACCESS_CONTROL_REQUEST_HEADERS</span>,
<span class="kw">let </span>req = TestRequest::default()
.method(Method::OPTIONS)
.insert_header((<span class="string">&quot;Origin&quot;</span>, <span class="string">&quot;https://www.example.com&quot;</span>))
.insert_header((header::ACCESS_CONTROL_REQUEST_METHOD, <span class="string">&quot;POST&quot;</span>))
.insert_header((
header::ACCESS_CONTROL_REQUEST_HEADERS,
<span class="string">&quot;AUTHORIZATION,ACCEPT&quot;</span>,
))
.<span class="ident">to_srv_request</span>();
.to_srv_request();
<span class="kw">let</span> <span class="ident">resp</span> <span class="op">=</span> <span class="ident">test::call_service</span>(<span class="kw-2">&amp;</span><span class="ident">cors</span>, <span class="ident">req</span>).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(<span class="ident">resp</span>.<span class="ident">status</span>(), <span class="ident">StatusCode::OK</span>);
<span class="kw">let </span>resp = test::call_service(<span class="kw-2">&amp;</span>cors, req).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::OK);
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">allow_fn_origin_equals_head_origin</span>() {
<span class="kw">let</span> <span class="ident">cors</span> <span class="op">=</span> <span class="ident">Cors::default</span>()
.<span class="ident">allowed_origin_fn</span>(<span class="op">|</span><span class="ident">origin</span>, <span class="ident">head</span><span class="op">|</span> {
<span class="kw">let</span> <span class="ident">head_origin</span> <span class="op">=</span> <span class="ident">head</span>
.<span class="ident">headers</span>()
.<span class="ident">get</span>(<span class="ident">header::ORIGIN</span>)
.<span class="ident">expect</span>(<span class="string">&quot;unwrapping origin header should never fail in allowed_origin_fn&quot;</span>);
<span class="macro">assert!</span>(<span class="ident">origin</span> <span class="op">==</span> <span class="ident">head_origin</span>);
<span class="bool-val">true</span>
})
.<span class="ident">allow_any_method</span>()
.<span class="ident">allow_any_header</span>()
.<span class="ident">new_transform</span>(<span class="ident">test::status_service</span>(<span class="ident">StatusCode::NO_CONTENT</span>))
.<span class="kw">await</span>
.<span class="ident">unwrap</span>();
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>allow_fn_origin_equals_head_origin() {
<span class="kw">let </span>cors = Cors::default()
.allowed_origin_fn(|origin, head| {
<span class="kw">let </span>head_origin = head
.headers()
.get(header::ORIGIN)
.expect(<span class="string">&quot;unwrapping origin header should never fail in allowed_origin_fn&quot;</span>);
<span class="macro">assert!</span>(origin == head_origin);
<span class="bool-val">true
</span>})
.allow_any_method()
.allow_any_header()
.new_transform(test::status_service(StatusCode::NO_CONTENT))
.<span class="kw">await
</span>.unwrap();
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::default</span>()
.<span class="ident">method</span>(<span class="ident">Method::OPTIONS</span>)
.<span class="ident">insert_header</span>((<span class="string">&quot;Origin&quot;</span>, <span class="string">&quot;https://www.example.com&quot;</span>))
.<span class="ident">insert_header</span>((<span class="ident">header::ACCESS_CONTROL_REQUEST_METHOD</span>, <span class="string">&quot;POST&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let</span> <span class="ident">resp</span> <span class="op">=</span> <span class="ident">test::call_service</span>(<span class="kw-2">&amp;</span><span class="ident">cors</span>, <span class="ident">req</span>).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(<span class="ident">resp</span>.<span class="ident">status</span>(), <span class="ident">StatusCode::OK</span>);
<span class="kw">let </span>req = TestRequest::default()
.method(Method::OPTIONS)
.insert_header((<span class="string">&quot;Origin&quot;</span>, <span class="string">&quot;https://www.example.com&quot;</span>))
.insert_header((header::ACCESS_CONTROL_REQUEST_METHOD, <span class="string">&quot;POST&quot;</span>))
.to_srv_request();
<span class="kw">let </span>resp = test::call_service(<span class="kw-2">&amp;</span>cors, req).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::OK);
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::default</span>()
.<span class="ident">method</span>(<span class="ident">Method::GET</span>)
.<span class="ident">insert_header</span>((<span class="string">&quot;Origin&quot;</span>, <span class="string">&quot;https://www.example.com&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let</span> <span class="ident">resp</span> <span class="op">=</span> <span class="ident">test::call_service</span>(<span class="kw-2">&amp;</span><span class="ident">cors</span>, <span class="ident">req</span>).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(<span class="ident">resp</span>.<span class="ident">status</span>(), <span class="ident">StatusCode::NO_CONTENT</span>);
<span class="kw">let </span>req = TestRequest::default()
.method(Method::GET)
.insert_header((<span class="string">&quot;Origin&quot;</span>, <span class="string">&quot;https://www.example.com&quot;</span>))
.to_srv_request();
<span class="kw">let </span>resp = test::call_service(<span class="kw-2">&amp;</span>cors, req).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::NO_CONTENT);
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_cors" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_cors" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -60,65 +60,65 @@
<span id="58">58</span>
<span id="59">59</span>
<span id="60">60</span>
</pre><pre class="rust"><code><span class="doccomment">//! Cross-Origin Resource Sharing (CORS) controls for Actix Web.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! This middleware can be applied to both applications and resources. Once built, a</span>
<span class="doccomment">//! [`Cors`] builder can be used as an argument for Actix Web&#39;s `App::wrap()`,</span>
<span class="doccomment">//! `Scope::wrap()`, or `Resource::wrap()` methods.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! This CORS middleware automatically handles `OPTIONS` preflight requests.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! # Example</span>
<span class="doccomment">//! ```no_run</span>
<span class="doccomment">//! use actix_cors::Cors;</span>
<span class="doccomment">//! use actix_web::{get, http, web, App, HttpRequest, HttpResponse, HttpServer};</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! #[get(&quot;/index.html&quot;)]</span>
<span class="doccomment">//! async fn index(req: HttpRequest) -&gt; &amp;&#39;static str {</span>
<span class="doccomment">//! &quot;&lt;p&gt;Hello World!&lt;/p&gt;&quot;</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! #[actix_web::main]</span>
<span class="doccomment">//! async fn main() -&gt; std::io::Result&lt;()&gt; {</span>
<span class="doccomment">//! HttpServer::new(|| {</span>
<span class="doccomment">//! let cors = Cors::default()</span>
<span class="doccomment">//! .allowed_origin(&quot;https://www.rust-lang.org/&quot;)</span>
<span class="doccomment">//! .allowed_origin_fn(|origin, _req_head| {</span>
<span class="doccomment">//! origin.as_bytes().ends_with(b&quot;.rust-lang.org&quot;)</span>
<span class="doccomment">//! })</span>
<span class="doccomment">//! .allowed_methods(vec![&quot;GET&quot;, &quot;POST&quot;])</span>
<span class="doccomment">//! .allowed_headers(vec![http::header::AUTHORIZATION, http::header::ACCEPT])</span>
<span class="doccomment">//! .allowed_header(http::header::CONTENT_TYPE)</span>
<span class="doccomment">//! .max_age(3600);</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! App::new()</span>
<span class="doccomment">//! .wrap(cors)</span>
<span class="doccomment">//! .service(index)</span>
<span class="doccomment">//! })</span>
<span class="doccomment">//! .bind((&quot;127.0.0.1&quot;, 8080))?</span>
<span class="doccomment">//! .run()</span>
<span class="doccomment">//! .await;</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! Ok(())</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//! ```</span>
</pre><pre class="rust"><code><span class="doccomment">//! Cross-Origin Resource Sharing (CORS) controls for Actix Web.
//!
//! This middleware can be applied to both applications and resources. Once built, a
//! [`Cors`] builder can be used as an argument for Actix Web&#39;s `App::wrap()`,
//! `Scope::wrap()`, or `Resource::wrap()` methods.
//!
//! This CORS middleware automatically handles `OPTIONS` preflight requests.
//!
//! # Example
//! ```no_run
//! use actix_cors::Cors;
//! use actix_web::{get, http, web, App, HttpRequest, HttpResponse, HttpServer};
//!
//! #[get(&quot;/index.html&quot;)]
//! async fn index(req: HttpRequest) -&gt; &amp;&#39;static str {
//! &quot;&lt;p&gt;Hello World!&lt;/p&gt;&quot;
//! }
//!
//! #[actix_web::main]
//! async fn main() -&gt; std::io::Result&lt;()&gt; {
//! HttpServer::new(|| {
//! let cors = Cors::default()
//! .allowed_origin(&quot;https://www.rust-lang.org/&quot;)
//! .allowed_origin_fn(|origin, _req_head| {
//! origin.as_bytes().ends_with(b&quot;.rust-lang.org&quot;)
//! })
//! .allowed_methods(vec![&quot;GET&quot;, &quot;POST&quot;])
//! .allowed_headers(vec![http::header::AUTHORIZATION, http::header::ACCEPT])
//! .allowed_header(http::header::CONTENT_TYPE)
//! .max_age(3600);
//!
//! App::new()
//! .wrap(cors)
//! .service(index)
//! })
//! .bind((&quot;127.0.0.1&quot;, 8080))?
//! .run()
//! .await;
//!
//! Ok(())
//! }
//! ```
<span class="attribute">#![<span class="ident">forbid</span>(<span class="ident">unsafe_code</span>)]</span>
<span class="attribute">#![<span class="ident">deny</span>(<span class="ident">rust_2018_idioms</span>, <span class="ident">nonstandard_style</span>)]</span>
<span class="attribute">#![<span class="ident">warn</span>(<span class="ident">future_incompatible</span>, <span class="ident">missing_docs</span>, <span class="ident">missing_debug_implementations</span>)]</span>
<span class="attribute">#![<span class="ident">doc</span>(<span class="ident">html_logo_url</span> <span class="op">=</span> <span class="string">&quot;https://actix.rs/img/logo.png&quot;</span>)]</span>
<span class="attribute">#![<span class="ident">doc</span>(<span class="ident">html_favicon_url</span> <span class="op">=</span> <span class="string">&quot;https://actix.rs/favicon.ico&quot;</span>)]</span>
</span><span class="attribute">#![forbid(unsafe_code)]
#![deny(rust_2018_idioms, nonstandard_style)]
#![warn(future_incompatible, missing_docs, missing_debug_implementations)]
#![doc(html_logo_url = <span class="string">&quot;https://actix.rs/img/logo.png&quot;</span>)]
#![doc(html_favicon_url = <span class="string">&quot;https://actix.rs/favicon.ico&quot;</span>)]
<span class="kw">mod</span> <span class="ident">all_or_some</span>;
<span class="kw">mod</span> <span class="ident">builder</span>;
<span class="kw">mod</span> <span class="ident">error</span>;
<span class="kw">mod</span> <span class="ident">inner</span>;
<span class="kw">mod</span> <span class="ident">middleware</span>;
</span><span class="kw">mod </span>all_or_some;
<span class="kw">mod </span>builder;
<span class="kw">mod </span>error;
<span class="kw">mod </span>inner;
<span class="kw">mod </span>middleware;
<span class="kw">use</span> <span class="ident">all_or_some::AllOrSome</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident">builder::Cors</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident">error::CorsError</span>;
<span class="kw">use</span> <span class="ident">inner</span>::{<span class="ident">Inner</span>, <span class="ident">OriginFn</span>};
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident">middleware::CorsMiddleware</span>;
<span class="kw">use </span>all_or_some::AllOrSome;
<span class="kw">pub use </span>builder::Cors;
<span class="kw">pub use </span>error::CorsError;
<span class="kw">use </span>inner::{Inner, OriginFn};
<span class="kw">pub use </span>middleware::CorsMiddleware;
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_cors" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_cors" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -263,268 +263,268 @@
<span id="261">261</span>
<span id="262">262</span>
<span id="263">263</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">collections::HashSet</span>, <span class="ident">rc::Rc</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{collections::HashSet, rc::Rc};
<span class="kw">use</span> <span class="ident">actix_utils::future::ok</span>;
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">body</span>::{<span class="ident">EitherBody</span>, <span class="ident">MessageBody</span>},
<span class="ident">dev</span>::{<span class="ident">forward_ready</span>, <span class="ident">Service</span>, <span class="ident">ServiceRequest</span>, <span class="ident">ServiceResponse</span>},
<span class="ident">http</span>::{
<span class="ident">header</span>::{<span class="self">self</span>, <span class="ident">HeaderValue</span>},
<span class="ident">Method</span>,
<span class="kw">use </span>actix_utils::future::ok;
<span class="kw">use </span>actix_web::{
body::{EitherBody, MessageBody},
dev::{forward_ready, Service, ServiceRequest, ServiceResponse},
http::{
header::{<span class="self">self</span>, HeaderValue},
Method,
},
<span class="ident">Error</span>, <span class="ident">HttpResponse</span>, <span class="prelude-ty">Result</span>,
Error, HttpResponse, <span class="prelude-ty">Result</span>,
};
<span class="kw">use</span> <span class="ident">futures_util::future</span>::{<span class="ident">FutureExt</span> <span class="kw">as</span> <span class="kw">_</span>, <span class="ident">LocalBoxFuture</span>};
<span class="kw">use</span> <span class="ident">log::debug</span>;
<span class="kw">use </span>futures_util::future::{FutureExt <span class="kw">as _</span>, LocalBoxFuture};
<span class="kw">use </span>log::debug;
<span class="kw">use</span> <span class="kw">crate</span>::{
<span class="ident">builder::intersperse_header_values</span>,
<span class="ident">inner</span>::{<span class="ident">add_vary_header</span>, <span class="ident">header_value_try_into_method</span>},
<span class="ident">AllOrSome</span>, <span class="ident">Inner</span>,
<span class="kw">use crate</span>::{
builder::intersperse_header_values,
inner::{add_vary_header, header_value_try_into_method},
AllOrSome, Inner,
};
<span class="doccomment">/// Service wrapper for Cross-Origin Resource Sharing support.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// This struct contains the settings for CORS requests to be validated and for responses to</span>
<span class="doccomment">/// be generated.</span>
<span class="attribute">#[<span class="ident">doc</span>(<span class="ident">hidden</span>)]</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">CorsMiddleware</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">service</span>: <span class="ident">S</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">inner</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">Inner</span><span class="op">&gt;</span>,
<span class="doccomment">/// Service wrapper for Cross-Origin Resource Sharing support.
///
/// This struct contains the settings for CORS requests to be validated and for responses to
/// be generated.
</span><span class="attribute">#[doc(hidden)]
#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>CorsMiddleware&lt;S&gt; {
<span class="kw">pub</span>(<span class="kw">crate</span>) service: S,
<span class="kw">pub</span>(<span class="kw">crate</span>) inner: Rc&lt;Inner&gt;,
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> <span class="ident">CorsMiddleware</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="doccomment">/// Returns true if request is `OPTIONS` and contains an `Access-Control-Request-Method` header.</span>
<span class="kw">fn</span> <span class="ident">is_request_preflight</span>(<span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">ServiceRequest</span>) -&gt; <span class="ident">bool</span> {
<span class="comment">// check request method is OPTIONS</span>
<span class="kw">if</span> <span class="ident">req</span>.<span class="ident">method</span>() <span class="op">!</span><span class="op">=</span> <span class="ident">Method::OPTIONS</span> {
<span class="kw">return</span> <span class="bool-val">false</span>;
<span class="kw">impl</span>&lt;S&gt; CorsMiddleware&lt;S&gt; {
<span class="doccomment">/// Returns true if request is `OPTIONS` and contains an `Access-Control-Request-Method` header.
</span><span class="kw">fn </span>is_request_preflight(req: <span class="kw-2">&amp;</span>ServiceRequest) -&gt; bool {
<span class="comment">// check request method is OPTIONS
</span><span class="kw">if </span>req.method() != Method::OPTIONS {
<span class="kw">return </span><span class="bool-val">false</span>;
}
<span class="comment">// check follow-up request method is present and valid</span>
<span class="kw">if</span> <span class="ident">req</span>
.<span class="ident">headers</span>()
.<span class="ident">get</span>(<span class="ident">header::ACCESS_CONTROL_REQUEST_METHOD</span>)
.<span class="ident">and_then</span>(<span class="ident">header_value_try_into_method</span>)
.<span class="ident">is_none</span>()
<span class="comment">// check follow-up request method is present and valid
</span><span class="kw">if </span>req
.headers()
.get(header::ACCESS_CONTROL_REQUEST_METHOD)
.and_then(header_value_try_into_method)
.is_none()
{
<span class="kw">return</span> <span class="bool-val">false</span>;
<span class="kw">return </span><span class="bool-val">false</span>;
}
<span class="bool-val">true</span>
}
<span class="bool-val">true
</span>}
<span class="doccomment">/// Validates preflight request headers against configuration and constructs preflight response.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Checks:</span>
<span class="doccomment">/// - `Origin` header is acceptable;</span>
<span class="doccomment">/// - `Access-Control-Request-Method` header is acceptable;</span>
<span class="doccomment">/// - `Access-Control-Request-Headers` header is acceptable.</span>
<span class="kw">fn</span> <span class="ident">handle_preflight</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">req</span>: <span class="ident">ServiceRequest</span>) -&gt; <span class="ident">ServiceResponse</span> {
<span class="kw">let</span> <span class="ident">inner</span> <span class="op">=</span> <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">inner</span>);
<span class="doccomment">/// Validates preflight request headers against configuration and constructs preflight response.
///
/// Checks:
/// - `Origin` header is acceptable;
/// - `Access-Control-Request-Method` header is acceptable;
/// - `Access-Control-Request-Headers` header is acceptable.
</span><span class="kw">fn </span>handle_preflight(<span class="kw-2">&amp;</span><span class="self">self</span>, req: ServiceRequest) -&gt; ServiceResponse {
<span class="kw">let </span>inner = Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.inner);
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Err</span>(<span class="ident">err</span>) <span class="op">=</span> <span class="ident">inner</span>
.<span class="ident">validate_origin</span>(<span class="ident">req</span>.<span class="ident">head</span>())
.<span class="ident">and_then</span>(<span class="op">|</span><span class="kw">_</span><span class="op">|</span> <span class="ident">inner</span>.<span class="ident">validate_allowed_method</span>(<span class="ident">req</span>.<span class="ident">head</span>()))
.<span class="ident">and_then</span>(<span class="op">|</span><span class="kw">_</span><span class="op">|</span> <span class="ident">inner</span>.<span class="ident">validate_allowed_headers</span>(<span class="ident">req</span>.<span class="ident">head</span>()))
<span class="kw">if let </span><span class="prelude-val">Err</span>(err) = inner
.validate_origin(req.head())
.and_then(|<span class="kw">_</span>| inner.validate_allowed_method(req.head()))
.and_then(|<span class="kw">_</span>| inner.validate_allowed_headers(req.head()))
{
<span class="kw">return</span> <span class="ident">req</span>.<span class="ident">error_response</span>(<span class="ident">err</span>);
<span class="kw">return </span>req.error_response(err);
}
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">res</span> <span class="op">=</span> <span class="ident">HttpResponse::Ok</span>();
<span class="kw">let </span><span class="kw-2">mut </span>res = HttpResponse::Ok();
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">origin</span>) <span class="op">=</span> <span class="ident">inner</span>.<span class="ident">access_control_allow_origin</span>(<span class="ident">req</span>.<span class="ident">head</span>()) {
<span class="ident">res</span>.<span class="ident">insert_header</span>((<span class="ident">header::ACCESS_CONTROL_ALLOW_ORIGIN</span>, <span class="ident">origin</span>));
<span class="kw">if let </span><span class="prelude-val">Some</span>(origin) = inner.access_control_allow_origin(req.head()) {
res.insert_header((header::ACCESS_CONTROL_ALLOW_ORIGIN, origin));
}
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="ident">allowed_methods</span>) <span class="op">=</span> <span class="ident">inner</span>.<span class="ident">allowed_methods_baked</span> {
<span class="ident">res</span>.<span class="ident">insert_header</span>((
<span class="ident">header::ACCESS_CONTROL_ALLOW_METHODS</span>,
<span class="ident">allowed_methods</span>.<span class="ident">clone</span>(),
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>allowed_methods) = inner.allowed_methods_baked {
res.insert_header((
header::ACCESS_CONTROL_ALLOW_METHODS,
allowed_methods.clone(),
));
}
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="ident">headers</span>) <span class="op">=</span> <span class="ident">inner</span>.<span class="ident">allowed_headers_baked</span> {
<span class="ident">res</span>.<span class="ident">insert_header</span>((<span class="ident">header::ACCESS_CONTROL_ALLOW_HEADERS</span>, <span class="ident">headers</span>.<span class="ident">clone</span>()));
} <span class="kw">else</span> <span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">headers</span>) <span class="op">=</span> <span class="ident">req</span>.<span class="ident">headers</span>().<span class="ident">get</span>(<span class="ident">header::ACCESS_CONTROL_REQUEST_HEADERS</span>) {
<span class="comment">// all headers allowed, return</span>
<span class="ident">res</span>.<span class="ident">insert_header</span>((<span class="ident">header::ACCESS_CONTROL_ALLOW_HEADERS</span>, <span class="ident">headers</span>.<span class="ident">clone</span>()));
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>headers) = inner.allowed_headers_baked {
res.insert_header((header::ACCESS_CONTROL_ALLOW_HEADERS, headers.clone()));
} <span class="kw">else if let </span><span class="prelude-val">Some</span>(headers) = req.headers().get(header::ACCESS_CONTROL_REQUEST_HEADERS) {
<span class="comment">// all headers allowed, return
</span>res.insert_header((header::ACCESS_CONTROL_ALLOW_HEADERS, headers.clone()));
}
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">supports_credentials</span> {
<span class="ident">res</span>.<span class="ident">insert_header</span>((
<span class="ident">header::ACCESS_CONTROL_ALLOW_CREDENTIALS</span>,
<span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;true&quot;</span>),
<span class="kw">if </span>inner.supports_credentials {
res.insert_header((
header::ACCESS_CONTROL_ALLOW_CREDENTIALS,
HeaderValue::from_static(<span class="string">&quot;true&quot;</span>),
));
}
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">max_age</span>) <span class="op">=</span> <span class="ident">inner</span>.<span class="ident">max_age</span> {
<span class="ident">res</span>.<span class="ident">insert_header</span>((<span class="ident">header::ACCESS_CONTROL_MAX_AGE</span>, <span class="ident">max_age</span>.<span class="ident">to_string</span>()));
<span class="kw">if let </span><span class="prelude-val">Some</span>(max_age) = inner.max_age {
res.insert_header((header::ACCESS_CONTROL_MAX_AGE, max_age.to_string()));
}
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">res</span> <span class="op">=</span> <span class="ident">res</span>.<span class="ident">finish</span>();
<span class="kw">let </span><span class="kw-2">mut </span>res = res.finish();
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">vary_header</span> {
<span class="ident">add_vary_header</span>(<span class="ident">res</span>.<span class="ident">headers_mut</span>());
<span class="kw">if </span>inner.vary_header {
add_vary_header(res.headers_mut());
}
<span class="ident">req</span>.<span class="ident">into_response</span>(<span class="ident">res</span>)
req.into_response(res)
}
<span class="kw">fn</span> <span class="ident">augment_response</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>(<span class="ident">inner</span>: <span class="kw-2">&amp;</span><span class="ident">Inner</span>, <span class="kw-2">mut</span> <span class="ident">res</span>: <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>) -&gt; <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span> {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">origin</span>) <span class="op">=</span> <span class="ident">inner</span>.<span class="ident">access_control_allow_origin</span>(<span class="ident">res</span>.<span class="ident">request</span>().<span class="ident">head</span>()) {
<span class="ident">res</span>.<span class="ident">headers_mut</span>()
.<span class="ident">insert</span>(<span class="ident">header::ACCESS_CONTROL_ALLOW_ORIGIN</span>, <span class="ident">origin</span>);
<span class="kw">fn </span>augment_response&lt;B&gt;(inner: <span class="kw-2">&amp;</span>Inner, <span class="kw-2">mut </span>res: ServiceResponse&lt;B&gt;) -&gt; ServiceResponse&lt;B&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(origin) = inner.access_control_allow_origin(res.request().head()) {
res.headers_mut()
.insert(header::ACCESS_CONTROL_ALLOW_ORIGIN, origin);
};
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="ident">expose</span>) <span class="op">=</span> <span class="ident">inner</span>.<span class="ident">expose_headers_baked</span> {
<span class="macro">log::trace!</span>(<span class="string">&quot;exposing selected headers: {:?}&quot;</span>, <span class="ident">expose</span>);
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>expose) = inner.expose_headers_baked {
<span class="macro">log::trace!</span>(<span class="string">&quot;exposing selected headers: {:?}&quot;</span>, expose);
<span class="ident">res</span>.<span class="ident">headers_mut</span>()
.<span class="ident">insert</span>(<span class="ident">header::ACCESS_CONTROL_EXPOSE_HEADERS</span>, <span class="ident">expose</span>.<span class="ident">clone</span>());
} <span class="kw">else</span> <span class="kw">if</span> <span class="macro">matches!</span>(<span class="ident">inner</span>.<span class="ident">expose_headers</span>, <span class="ident">AllOrSome::All</span>) {
<span class="comment">// intersperse_header_values requires that argument is non-empty</span>
<span class="kw">if</span> <span class="op">!</span><span class="ident">res</span>.<span class="ident">headers</span>().<span class="ident">is_empty</span>() {
<span class="comment">// extract header names from request</span>
<span class="kw">let</span> <span class="ident">expose_all_request_headers</span> <span class="op">=</span> <span class="ident">res</span>
.<span class="ident">headers</span>()
.<span class="ident">keys</span>()
.<span class="ident">into_iter</span>()
.<span class="ident">map</span>(<span class="op">|</span><span class="ident">name</span><span class="op">|</span> <span class="ident">name</span>.<span class="ident">as_str</span>())
.<span class="ident">collect</span>::<span class="op">&lt;</span><span class="ident">HashSet</span><span class="op">&lt;</span><span class="kw">_</span><span class="op">&gt;</span><span class="op">&gt;</span>();
res.headers_mut()
.insert(header::ACCESS_CONTROL_EXPOSE_HEADERS, expose.clone());
} <span class="kw">else if </span><span class="macro">matches!</span>(inner.expose_headers, AllOrSome::All) {
<span class="comment">// intersperse_header_values requires that argument is non-empty
</span><span class="kw">if </span>!res.headers().is_empty() {
<span class="comment">// extract header names from request
</span><span class="kw">let </span>expose_all_request_headers = res
.headers()
.keys()
.into_iter()
.map(|name| name.as_str())
.collect::&lt;HashSet&lt;<span class="kw">_</span>&gt;&gt;();
<span class="comment">// create comma separated string of header names</span>
<span class="kw">let</span> <span class="ident">expose_headers_value</span> <span class="op">=</span> <span class="ident">intersperse_header_values</span>(<span class="kw-2">&amp;</span><span class="ident">expose_all_request_headers</span>);
<span class="comment">// create comma separated string of header names
</span><span class="kw">let </span>expose_headers_value = intersperse_header_values(<span class="kw-2">&amp;</span>expose_all_request_headers);
<span class="macro">log::trace!</span>(
<span class="string">&quot;exposing all headers from request: {:?}&quot;</span>,
<span class="ident">expose_headers_value</span>
expose_headers_value
);
<span class="comment">// add header names to expose response header</span>
<span class="ident">res</span>.<span class="ident">headers_mut</span>()
.<span class="ident">insert</span>(<span class="ident">header::ACCESS_CONTROL_EXPOSE_HEADERS</span>, <span class="ident">expose_headers_value</span>);
<span class="comment">// add header names to expose response header
</span>res.headers_mut()
.insert(header::ACCESS_CONTROL_EXPOSE_HEADERS, expose_headers_value);
}
}
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">supports_credentials</span> {
<span class="ident">res</span>.<span class="ident">headers_mut</span>().<span class="ident">insert</span>(
<span class="ident">header::ACCESS_CONTROL_ALLOW_CREDENTIALS</span>,
<span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;true&quot;</span>),
<span class="kw">if </span>inner.supports_credentials {
res.headers_mut().insert(
header::ACCESS_CONTROL_ALLOW_CREDENTIALS,
HeaderValue::from_static(<span class="string">&quot;true&quot;</span>),
);
}
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">vary_header</span> {
<span class="ident">add_vary_header</span>(<span class="ident">res</span>.<span class="ident">headers_mut</span>());
<span class="kw">if </span>inner.vary_header {
add_vary_header(res.headers_mut());
}
<span class="ident">res</span>
res
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">B</span><span class="op">&gt;</span> <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">CorsMiddleware</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">S</span>: <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>, <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span><span class="op">&gt;</span>,
<span class="ident">S::Future</span>: <span class="lifetime">&#39;static</span>,
<span class="kw">impl</span>&lt;S, B&gt; Service&lt;ServiceRequest&gt; <span class="kw">for </span>CorsMiddleware&lt;S&gt;
<span class="kw">where
</span>S: Service&lt;ServiceRequest, Response = ServiceResponse&lt;B&gt;, Error = Error&gt;,
S::Future: <span class="lifetime">&#39;static</span>,
<span class="ident">B</span>: <span class="ident">MessageBody</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
B: MessageBody + <span class="lifetime">&#39;static</span>,
{
<span class="kw">type</span> <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">EitherBody</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span>;
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">LocalBoxFuture</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">EitherBody</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span><span class="op">&gt;</span>, <span class="ident">Error</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type </span>Response = ServiceResponse&lt;EitherBody&lt;B&gt;&gt;;
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Future = LocalBoxFuture&lt;<span class="lifetime">&#39;static</span>, <span class="prelude-ty">Result</span>&lt;ServiceResponse&lt;EitherBody&lt;B&gt;&gt;, Error&gt;&gt;;
<span class="macro">forward_ready!</span>(<span class="ident">service</span>);
<span class="macro">forward_ready!</span>(service);
<span class="kw">fn</span> <span class="ident">call</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">req</span>: <span class="ident">ServiceRequest</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="kw">let</span> <span class="ident">origin</span> <span class="op">=</span> <span class="ident">req</span>.<span class="ident">headers</span>().<span class="ident">get</span>(<span class="ident">header::ORIGIN</span>);
<span class="kw">fn </span>call(<span class="kw-2">&amp;</span><span class="self">self</span>, req: ServiceRequest) -&gt; <span class="self">Self</span>::Future {
<span class="kw">let </span>origin = req.headers().get(header::ORIGIN);
<span class="comment">// handle preflight requests</span>
<span class="kw">if</span> <span class="self">self</span>.<span class="ident">inner</span>.<span class="ident">preflight</span> <span class="op">&amp;&amp;</span> <span class="ident"><span class="self">Self</span>::is_request_preflight</span>(<span class="kw-2">&amp;</span><span class="ident">req</span>) {
<span class="kw">let</span> <span class="ident">res</span> <span class="op">=</span> <span class="self">self</span>.<span class="ident">handle_preflight</span>(<span class="ident">req</span>);
<span class="kw">return</span> <span class="ident">ok</span>(<span class="ident">res</span>.<span class="ident">map_into_right_body</span>()).<span class="ident">boxed_local</span>();
<span class="comment">// handle preflight requests
</span><span class="kw">if </span><span class="self">self</span>.inner.preflight &amp;&amp; <span class="self">Self</span>::is_request_preflight(<span class="kw-2">&amp;</span>req) {
<span class="kw">let </span>res = <span class="self">self</span>.handle_preflight(req);
<span class="kw">return </span>ok(res.map_into_right_body()).boxed_local();
}
<span class="comment">// only check actual requests with a origin header</span>
<span class="kw">if</span> <span class="ident">origin</span>.<span class="ident">is_some</span>() {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Err</span>(<span class="ident">err</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">inner</span>.<span class="ident">validate_origin</span>(<span class="ident">req</span>.<span class="ident">head</span>()) {
<span class="comment">// only check actual requests with a origin header
</span><span class="kw">if </span>origin.is_some() {
<span class="kw">if let </span><span class="prelude-val">Err</span>(err) = <span class="self">self</span>.inner.validate_origin(req.head()) {
<span class="macro">debug!</span>(<span class="string">&quot;origin validation failed; inner service is not called&quot;</span>);
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">res</span> <span class="op">=</span> <span class="ident">req</span>.<span class="ident">error_response</span>(<span class="ident">err</span>);
<span class="kw">let </span><span class="kw-2">mut </span>res = req.error_response(err);
<span class="kw">if</span> <span class="self">self</span>.<span class="ident">inner</span>.<span class="ident">vary_header</span> {
<span class="ident">add_vary_header</span>(<span class="ident">res</span>.<span class="ident">headers_mut</span>());
<span class="kw">if </span><span class="self">self</span>.inner.vary_header {
add_vary_header(res.headers_mut());
}
<span class="kw">return</span> <span class="ident">ok</span>(<span class="ident">res</span>.<span class="ident">map_into_right_body</span>()).<span class="ident">boxed_local</span>();
<span class="kw">return </span>ok(res.map_into_right_body()).boxed_local();
}
}
<span class="kw">let</span> <span class="ident">inner</span> <span class="op">=</span> <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">inner</span>);
<span class="kw">let</span> <span class="ident">fut</span> <span class="op">=</span> <span class="self">self</span>.<span class="ident">service</span>.<span class="ident">call</span>(<span class="ident">req</span>);
<span class="kw">let </span>inner = Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.inner);
<span class="kw">let </span>fut = <span class="self">self</span>.service.call(req);
<span class="ident">Box::pin</span>(<span class="kw">async</span> <span class="kw">move</span> {
<span class="kw">let</span> <span class="ident">res</span> <span class="op">=</span> <span class="ident">fut</span>.<span class="kw">await</span>;
<span class="prelude-val">Ok</span>(<span class="ident"><span class="self">Self</span>::augment_response</span>(<span class="kw-2">&amp;</span><span class="ident">inner</span>, <span class="ident">res</span><span class="question-mark">?</span>).<span class="ident">map_into_left_body</span>())
Box::pin(<span class="kw">async move </span>{
<span class="kw">let </span>res = fut.<span class="kw">await</span>;
<span class="prelude-val">Ok</span>(<span class="self">Self</span>::augment_response(<span class="kw-2">&amp;</span>inner, res<span class="question-mark">?</span>).map_into_left_body())
})
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">dev::Transform</span>,
<span class="ident">middleware::Compat</span>,
<span class="ident">test</span>::{<span class="self">self</span>, <span class="ident">TestRequest</span>},
<span class="ident">App</span>,
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>actix_web::{
dev::Transform,
middleware::Compat,
test::{<span class="self">self</span>, TestRequest},
App,
};
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::Cors</span>;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use </span><span class="kw">crate</span>::Cors;
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">compat_compat</span>() {
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="ident">App::new</span>().<span class="ident">wrap</span>(<span class="ident">Compat::new</span>(<span class="ident">Cors::default</span>()));
<span class="attribute">#[test]
</span><span class="kw">fn </span>compat_compat() {
<span class="kw">let _ </span>= App::new().wrap(Compat::new(Cors::default()));
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_options_no_origin</span>() {
<span class="comment">// Tests case where allowed_origins is All but there are validate functions to run incase.</span>
<span class="comment">// In this case, origins are only allowed when the DNT header is sent.</span>
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_options_no_origin() {
<span class="comment">// Tests case where allowed_origins is All but there are validate functions to run incase.
// In this case, origins are only allowed when the DNT header is sent.
<span class="kw">let</span> <span class="ident">cors</span> <span class="op">=</span> <span class="ident">Cors::default</span>()
.<span class="ident">allow_any_origin</span>()
.<span class="ident">allowed_origin_fn</span>(<span class="op">|</span><span class="ident">origin</span>, <span class="ident">req_head</span><span class="op">|</span> {
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span><span class="ident">origin</span>, <span class="ident">req_head</span>.<span class="ident">headers</span>.<span class="ident">get</span>(<span class="ident">header::ORIGIN</span>).<span class="ident">unwrap</span>());
<span class="ident">req_head</span>.<span class="ident">headers</span>().<span class="ident">contains_key</span>(<span class="ident">header::DNT</span>)
</span><span class="kw">let </span>cors = Cors::default()
.allow_any_origin()
.allowed_origin_fn(|origin, req_head| {
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>origin, req_head.headers.get(header::ORIGIN).unwrap());
req_head.headers().contains_key(header::DNT)
})
.<span class="ident">new_transform</span>(<span class="ident">test::ok_service</span>())
.<span class="kw">await</span>
.<span class="ident">unwrap</span>();
.new_transform(test::ok_service())
.<span class="kw">await
</span>.unwrap();
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::get</span>()
.<span class="ident">insert_header</span>((<span class="ident">header::ORIGIN</span>, <span class="string">&quot;http://example.com&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let</span> <span class="ident">res</span> <span class="op">=</span> <span class="ident">cors</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let </span>req = TestRequest::get()
.insert_header((header::ORIGIN, <span class="string">&quot;http://example.com&quot;</span>))
.to_srv_request();
<span class="kw">let </span>res = cors.call(req).<span class="kw">await</span>.unwrap();
<span class="macro">assert_eq!</span>(
<span class="prelude-val">None</span>,
<span class="ident">res</span>.<span class="ident">headers</span>()
.<span class="ident">get</span>(<span class="ident">header::ACCESS_CONTROL_ALLOW_ORIGIN</span>)
.<span class="ident">map</span>(<span class="ident">HeaderValue::as_bytes</span>)
res.headers()
.get(header::ACCESS_CONTROL_ALLOW_ORIGIN)
.map(HeaderValue::as_bytes)
);
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::get</span>()
.<span class="ident">insert_header</span>((<span class="ident">header::ORIGIN</span>, <span class="string">&quot;http://example.com&quot;</span>))
.<span class="ident">insert_header</span>((<span class="ident">header::DNT</span>, <span class="string">&quot;1&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let</span> <span class="ident">res</span> <span class="op">=</span> <span class="ident">cors</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="kw">let </span>req = TestRequest::get()
.insert_header((header::ORIGIN, <span class="string">&quot;http://example.com&quot;</span>))
.insert_header((header::DNT, <span class="string">&quot;1&quot;</span>))
.to_srv_request();
<span class="kw">let </span>res = cors.call(req).<span class="kw">await</span>.unwrap();
<span class="macro">assert_eq!</span>(
<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="string">b&quot;http://example.com&quot;</span>[..]),
<span class="ident">res</span>.<span class="ident">headers</span>()
.<span class="ident">get</span>(<span class="ident">header::ACCESS_CONTROL_ALLOW_ORIGIN</span>)
.<span class="ident">map</span>(<span class="ident">HeaderValue::as_bytes</span>)
res.headers()
.get(header::ACCESS_CONTROL_ALLOW_ORIGIN)
.map(HeaderValue::as_bytes)
);
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_cors" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_cors" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -99,106 +99,106 @@
<span id="99">99</span>
<span id="100">100</span>
<span id="101">101</span>
</pre><pre class="rust"><code><span class="doccomment">//! Configuration options to tune the behaviour of [`IdentityMiddleware`].</span>
</pre><pre class="rust"><code><span class="doccomment">//! Configuration options to tune the behaviour of [`IdentityMiddleware`].
<span class="kw">use</span> <span class="ident">std::time::Duration</span>;
</span><span class="kw">use </span>std::time::Duration;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::IdentityMiddleware</span>;
<span class="kw">use </span><span class="kw">crate</span>::IdentityMiddleware;
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct</span> <span class="ident">Configuration</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">on_logout</span>: <span class="ident">LogoutBehaviour</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">login_deadline</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Duration</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">visit_deadline</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Duration</span><span class="op">&gt;</span>,
<span class="attribute">#[derive(Debug, Clone)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>Configuration {
<span class="kw">pub</span>(<span class="kw">crate</span>) on_logout: LogoutBehaviour,
<span class="kw">pub</span>(<span class="kw">crate</span>) login_deadline: <span class="prelude-ty">Option</span>&lt;Duration&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) visit_deadline: <span class="prelude-ty">Option</span>&lt;Duration&gt;,
}
<span class="kw">impl</span> <span class="ident">Default</span> <span class="kw">for</span> <span class="ident">Configuration</span> {
<span class="kw">fn</span> <span class="ident">default</span>() -&gt; <span class="self">Self</span> {
<span class="self">Self</span> {
<span class="ident">on_logout</span>: <span class="ident">LogoutBehaviour::PurgeSession</span>,
<span class="ident">login_deadline</span>: <span class="prelude-val">None</span>,
<span class="ident">visit_deadline</span>: <span class="prelude-val">None</span>,
<span class="kw">impl </span>Default <span class="kw">for </span>Configuration {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{
on_logout: LogoutBehaviour::PurgeSession,
login_deadline: <span class="prelude-val">None</span>,
visit_deadline: <span class="prelude-val">None</span>,
}
}
}
<span class="doccomment">/// `LogoutBehaviour` controls what actions are going to be performed when [`Identity::logout`] is</span>
<span class="doccomment">/// invoked.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`Identity::logout`]: crate::Identity::logout</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="attribute">#[<span class="ident">non_exhaustive</span>]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">LogoutBehaviour</span> {
<span class="doccomment">/// When [`Identity::logout`](crate::Identity::logout) is called, purge the current session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// This behaviour might be desirable when you have stored additional information in the</span>
<span class="doccomment">/// session state that are tied to the user&#39;s identity and should not be retained after logout.</span>
<span class="ident">PurgeSession</span>,
<span class="doccomment">/// `LogoutBehaviour` controls what actions are going to be performed when [`Identity::logout`] is
/// invoked.
///
/// [`Identity::logout`]: crate::Identity::logout
</span><span class="attribute">#[derive(Debug, Clone)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>LogoutBehaviour {
<span class="doccomment">/// When [`Identity::logout`](crate::Identity::logout) is called, purge the current session.
///
/// This behaviour might be desirable when you have stored additional information in the
/// session state that are tied to the user&#39;s identity and should not be retained after logout.
</span>PurgeSession,
<span class="doccomment">/// When [`Identity::logout`](crate::Identity::logout) is called, remove the identity</span>
<span class="doccomment">/// information from the current session state. The session itself is not destroyed.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// This behaviour might be desirable when you have stored information in the session state that</span>
<span class="doccomment">/// is not tied to the user&#39;s identity and should be retained after logout.</span>
<span class="ident">DeleteIdentityKeys</span>,
<span class="doccomment">/// When [`Identity::logout`](crate::Identity::logout) is called, remove the identity
/// information from the current session state. The session itself is not destroyed.
///
/// This behaviour might be desirable when you have stored information in the session state that
/// is not tied to the user&#39;s identity and should be retained after logout.
</span>DeleteIdentityKeys,
}
<span class="doccomment">/// A fluent builder to construct an [`IdentityMiddleware`] instance with custom configuration</span>
<span class="doccomment">/// parameters.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Use [`IdentityMiddleware::builder`] to get started!</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">IdentityMiddlewareBuilder</span> {
<span class="ident">configuration</span>: <span class="ident">Configuration</span>,
<span class="doccomment">/// A fluent builder to construct an [`IdentityMiddleware`] instance with custom configuration
/// parameters.
///
/// Use [`IdentityMiddleware::builder`] to get started!
</span><span class="attribute">#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>IdentityMiddlewareBuilder {
configuration: Configuration,
}
<span class="kw">impl</span> <span class="ident">IdentityMiddlewareBuilder</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">new</span>() -&gt; <span class="self">Self</span> {
<span class="self">Self</span> {
<span class="ident">configuration</span>: <span class="ident">Configuration::default</span>(),
<span class="kw">impl </span>IdentityMiddlewareBuilder {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new() -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{
configuration: Configuration::default(),
}
}
<span class="doccomment">/// Determines how [`Identity::logout`](crate::Identity::logout) affects the current session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// By default, the current session is purged ([`LogoutBehaviour::PurgeSession`]).</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">logout_behaviour</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">logout_behaviour</span>: <span class="ident">LogoutBehaviour</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">on_logout</span> <span class="op">=</span> <span class="ident">logout_behaviour</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Determines how [`Identity::logout`](crate::Identity::logout) affects the current session.
///
/// By default, the current session is purged ([`LogoutBehaviour::PurgeSession`]).
</span><span class="kw">pub fn </span>logout_behaviour(<span class="kw-2">mut </span><span class="self">self</span>, logout_behaviour: LogoutBehaviour) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.configuration.on_logout = logout_behaviour;
<span class="self">self
</span>}
<span class="doccomment">/// Automatically logs out users after a certain amount of time has passed since they logged in,</span>
<span class="doccomment">/// regardless of their activity pattern.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If set to:</span>
<span class="doccomment">/// - `None`: login deadline is disabled.</span>
<span class="doccomment">/// - `Some(duration)`: login deadline is enabled and users will be logged out after `duration`</span>
<span class="doccomment">/// has passed since their login.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// By default, login deadline is disabled.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">login_deadline</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">deadline</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Duration</span><span class="op">&gt;</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">login_deadline</span> <span class="op">=</span> <span class="ident">deadline</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Automatically logs out users after a certain amount of time has passed since they logged in,
/// regardless of their activity pattern.
///
/// If set to:
/// - `None`: login deadline is disabled.
/// - `Some(duration)`: login deadline is enabled and users will be logged out after `duration`
/// has passed since their login.
///
/// By default, login deadline is disabled.
</span><span class="kw">pub fn </span>login_deadline(<span class="kw-2">mut </span><span class="self">self</span>, deadline: <span class="prelude-ty">Option</span>&lt;Duration&gt;) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.configuration.login_deadline = deadline;
<span class="self">self
</span>}
<span class="doccomment">/// Automatically logs out users after a certain amount of time has passed since their last</span>
<span class="doccomment">/// visit.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If set to:</span>
<span class="doccomment">/// - `None`: visit deadline is disabled.</span>
<span class="doccomment">/// - `Some(duration)`: visit deadline is enabled and users will be logged out after `duration`</span>
<span class="doccomment">/// has passed since their last visit.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// By default, visit deadline is disabled.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">visit_deadline</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">deadline</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Duration</span><span class="op">&gt;</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">visit_deadline</span> <span class="op">=</span> <span class="ident">deadline</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Automatically logs out users after a certain amount of time has passed since their last
/// visit.
///
/// If set to:
/// - `None`: visit deadline is disabled.
/// - `Some(duration)`: visit deadline is enabled and users will be logged out after `duration`
/// has passed since their last visit.
///
/// By default, visit deadline is disabled.
</span><span class="kw">pub fn </span>visit_deadline(<span class="kw-2">mut </span><span class="self">self</span>, deadline: <span class="prelude-ty">Option</span>&lt;Duration&gt;) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.configuration.visit_deadline = deadline;
<span class="self">self
</span>}
<span class="doccomment">/// Finalises the builder and returns an [`IdentityMiddleware`] instance.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">build</span>(<span class="self">self</span>) -&gt; <span class="ident">IdentityMiddleware</span> {
<span class="ident">IdentityMiddleware::new</span>(<span class="self">self</span>.<span class="ident">configuration</span>)
<span class="doccomment">/// Finalises the builder and returns an [`IdentityMiddleware`] instance.
</span><span class="kw">pub fn </span>build(<span class="self">self</span>) -&gt; IdentityMiddleware {
IdentityMiddleware::new(<span class="self">self</span>.configuration)
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_identity" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_identity" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -263,92 +263,92 @@
<span id="263">263</span>
<span id="264">264</span>
<span id="265">265</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">actix_session::Session</span>;
<span class="kw">use</span> <span class="ident">actix_utils::future</span>::{<span class="ident">ready</span>, <span class="ident">Ready</span>};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">cookie::time::OffsetDateTime</span>,
<span class="ident">dev</span>::{<span class="ident">Extensions</span>, <span class="ident">Payload</span>},
<span class="ident">http::StatusCode</span>,
<span class="ident">Error</span>, <span class="ident">FromRequest</span>, <span class="ident">HttpMessage</span>, <span class="ident">HttpRequest</span>, <span class="ident">HttpResponse</span>,
</pre><pre class="rust"><code><span class="kw">use </span>actix_session::Session;
<span class="kw">use </span>actix_utils::future::{ready, Ready};
<span class="kw">use </span>actix_web::{
cookie::time::OffsetDateTime,
dev::{Extensions, Payload},
http::StatusCode,
Error, FromRequest, HttpMessage, HttpRequest, HttpResponse,
};
<span class="kw">use</span> <span class="ident">anyhow</span>::{<span class="ident">anyhow</span>, <span class="ident">Context</span>};
<span class="kw">use </span>anyhow::{anyhow, Context};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::config::LogoutBehaviour</span>;
<span class="kw">use </span><span class="kw">crate</span>::config::LogoutBehaviour;
<span class="doccomment">/// A verified user identity. It can be used as a request extractor.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// The lifecycle of a user identity is tied to the lifecycle of the underlying session. If the</span>
<span class="doccomment">/// session is destroyed (e.g. the session expired), the user identity will be forgotten, de-facto</span>
<span class="doccomment">/// forcing a user log out.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_web::{</span>
<span class="doccomment">/// get, post, Responder, HttpRequest, HttpMessage, HttpResponse</span>
<span class="doccomment">/// };</span>
<span class="doccomment">/// use actix_identity::Identity;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[get(&quot;/&quot;)]</span>
<span class="doccomment">/// async fn index(user: Option&lt;Identity&gt;) -&gt; impl Responder {</span>
<span class="doccomment">/// if let Some(user) = user {</span>
<span class="doccomment">/// format!(&quot;Welcome! {}&quot;, user.id().unwrap())</span>
<span class="doccomment">/// } else {</span>
<span class="doccomment">/// &quot;Welcome Anonymous!&quot;.to_owned()</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[post(&quot;/login&quot;)]</span>
<span class="doccomment">/// async fn login(request: HttpRequest) -&gt; impl Responder {</span>
<span class="doccomment">/// Identity::login(&amp;request.extensions(), &quot;User1&quot;.into());</span>
<span class="doccomment">/// HttpResponse::Ok()</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[post(&quot;/logout&quot;)]</span>
<span class="doccomment">/// async fn logout(user: Identity) -&gt; impl Responder {</span>
<span class="doccomment">/// user.logout();</span>
<span class="doccomment">/// HttpResponse::Ok()</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Extractor Behaviour</span>
<span class="doccomment">/// What happens if you try to extract an `Identity` out of a request that does not have a valid</span>
<span class="doccomment">/// identity attached? The API will return a `401 UNAUTHORIZED` to the caller.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If you want to customise this behaviour, consider extracting `Option&lt;Identity&gt;` or</span>
<span class="doccomment">/// `Result&lt;Identity, actix_web::Error&gt;` instead of a bare `Identity`: you will then be fully in</span>
<span class="doccomment">/// control of the error path.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ## Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_web::{http::header::LOCATION, get, HttpResponse, Responder};</span>
<span class="doccomment">/// use actix_identity::Identity;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[get(&quot;/&quot;)]</span>
<span class="doccomment">/// async fn index(user: Option&lt;Identity&gt;) -&gt; impl Responder {</span>
<span class="doccomment">/// if let Some(user) = user {</span>
<span class="doccomment">/// HttpResponse::Ok().finish()</span>
<span class="doccomment">/// } else {</span>
<span class="doccomment">/// // Redirect to login page if unauthenticated</span>
<span class="doccomment">/// HttpResponse::TemporaryRedirect()</span>
<span class="doccomment">/// .insert_header((LOCATION, &quot;/login&quot;))</span>
<span class="doccomment">/// .finish()</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Identity</span>(<span class="ident">IdentityInner</span>);
<span class="doccomment">/// A verified user identity. It can be used as a request extractor.
///
/// The lifecycle of a user identity is tied to the lifecycle of the underlying session. If the
/// session is destroyed (e.g. the session expired), the user identity will be forgotten, de-facto
/// forcing a user log out.
///
/// # Examples
/// ```
/// use actix_web::{
/// get, post, Responder, HttpRequest, HttpMessage, HttpResponse
/// };
/// use actix_identity::Identity;
///
/// #[get(&quot;/&quot;)]
/// async fn index(user: Option&lt;Identity&gt;) -&gt; impl Responder {
/// if let Some(user) = user {
/// format!(&quot;Welcome! {}&quot;, user.id().unwrap())
/// } else {
/// &quot;Welcome Anonymous!&quot;.to_owned()
/// }
/// }
///
/// #[post(&quot;/login&quot;)]
/// async fn login(request: HttpRequest) -&gt; impl Responder {
/// Identity::login(&amp;request.extensions(), &quot;User1&quot;.into());
/// HttpResponse::Ok()
/// }
///
/// #[post(&quot;/logout&quot;)]
/// async fn logout(user: Identity) -&gt; impl Responder {
/// user.logout();
/// HttpResponse::Ok()
/// }
/// ```
///
/// # Extractor Behaviour
/// What happens if you try to extract an `Identity` out of a request that does not have a valid
/// identity attached? The API will return a `401 UNAUTHORIZED` to the caller.
///
/// If you want to customise this behaviour, consider extracting `Option&lt;Identity&gt;` or
/// `Result&lt;Identity, actix_web::Error&gt;` instead of a bare `Identity`: you will then be fully in
/// control of the error path.
///
/// ## Examples
/// ```
/// use actix_web::{http::header::LOCATION, get, HttpResponse, Responder};
/// use actix_identity::Identity;
///
/// #[get(&quot;/&quot;)]
/// async fn index(user: Option&lt;Identity&gt;) -&gt; impl Responder {
/// if let Some(user) = user {
/// HttpResponse::Ok().finish()
/// } else {
/// // Redirect to login page if unauthenticated
/// HttpResponse::TemporaryRedirect()
/// .insert_header((LOCATION, &quot;/login&quot;))
/// .finish()
/// }
/// }
/// ```
</span><span class="kw">pub struct </span>Identity(IdentityInner);
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Clone</span>)]</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct</span> <span class="ident">IdentityInner</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">session</span>: <span class="ident">Session</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">logout_behaviour</span>: <span class="ident">LogoutBehaviour</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">is_login_deadline_enabled</span>: <span class="ident">bool</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">is_visit_deadline_enabled</span>: <span class="ident">bool</span>,
<span class="attribute">#[derive(Clone)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>IdentityInner {
<span class="kw">pub</span>(<span class="kw">crate</span>) session: Session,
<span class="kw">pub</span>(<span class="kw">crate</span>) logout_behaviour: LogoutBehaviour,
<span class="kw">pub</span>(<span class="kw">crate</span>) is_login_deadline_enabled: bool,
<span class="kw">pub</span>(<span class="kw">crate</span>) is_visit_deadline_enabled: bool,
}
<span class="kw">impl</span> <span class="ident">IdentityInner</span> {
<span class="kw">fn</span> <span class="ident">extract</span>(<span class="ident">ext</span>: <span class="kw-2">&amp;</span><span class="ident">Extensions</span>) -&gt; <span class="self">Self</span> {
<span class="ident">ext</span>.<span class="ident">get</span>::<span class="op">&lt;</span><span class="self">Self</span><span class="op">&gt;</span>()
.<span class="ident">expect</span>(
<span class="kw">impl </span>IdentityInner {
<span class="kw">fn </span>extract(ext: <span class="kw-2">&amp;</span>Extensions) -&gt; <span class="self">Self </span>{
ext.get::&lt;<span class="self">Self</span>&gt;()
.expect(
<span class="string">&quot;No `IdentityInner` instance was found in the extensions attached to the \
incoming request. This usually means that `IdentityMiddleware` has not been \
registered as an application middleware via `App::wrap`. `Identity` cannot be used \
@@ -356,177 +356,177 @@
a middleware for your application to fix this panic. If the problem persists, \
please file an issue on GitHub.&quot;</span>,
)
.<span class="ident">to_owned</span>()
.to_owned()
}
<span class="doccomment">/// Retrieve the user id attached to the current session.</span>
<span class="kw">fn</span> <span class="ident">get_identity</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">String</span>, <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="self">self</span>.<span class="ident">session</span>
.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>(<span class="ident">ID_KEY</span>)
.<span class="ident">context</span>(<span class="string">&quot;Failed to deserialize the user identifier attached to the current session&quot;</span>)<span class="question-mark">?</span>
.<span class="ident">ok_or_else</span>(<span class="op">|</span><span class="op">|</span> {
<span class="doccomment">/// Retrieve the user id attached to the current session.
</span><span class="kw">fn </span>get_identity(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;String, anyhow::Error&gt; {
<span class="self">self</span>.session
.get::&lt;String&gt;(ID_KEY)
.context(<span class="string">&quot;Failed to deserialize the user identifier attached to the current session&quot;</span>)<span class="question-mark">?
</span>.ok_or_else(|| {
<span class="macro">anyhow!</span>(<span class="string">&quot;There is no identity information attached to the current session&quot;</span>)
})
}
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const</span> <span class="ident">ID_KEY</span>: <span class="kw-2">&amp;</span><span class="ident">str</span> <span class="op">=</span> <span class="string">&quot;actix_identity.user_id&quot;</span>;
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const</span> <span class="ident">LAST_VISIT_UNIX_TIMESTAMP_KEY</span>: <span class="kw-2">&amp;</span><span class="ident">str</span> <span class="op">=</span> <span class="string">&quot;actix_identity.last_visited_at&quot;</span>;
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const</span> <span class="ident">LOGIN_UNIX_TIMESTAMP_KEY</span>: <span class="kw-2">&amp;</span><span class="ident">str</span> <span class="op">=</span> <span class="string">&quot;actix_identity.logged_in_at&quot;</span>;
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>ID_KEY: <span class="kw-2">&amp;</span>str = <span class="string">&quot;actix_identity.user_id&quot;</span>;
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>LAST_VISIT_UNIX_TIMESTAMP_KEY: <span class="kw-2">&amp;</span>str = <span class="string">&quot;actix_identity.last_visited_at&quot;</span>;
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>LOGIN_UNIX_TIMESTAMP_KEY: <span class="kw-2">&amp;</span>str = <span class="string">&quot;actix_identity.logged_in_at&quot;</span>;
<span class="kw">impl</span> <span class="ident">Identity</span> {
<span class="doccomment">/// Return the user id associated to the current session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_web::{get, Responder};</span>
<span class="doccomment">/// use actix_identity::Identity;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[get(&quot;/&quot;)]</span>
<span class="doccomment">/// async fn index(user: Option&lt;Identity&gt;) -&gt; impl Responder {</span>
<span class="doccomment">/// if let Some(user) = user {</span>
<span class="doccomment">/// format!(&quot;Welcome! {}&quot;, user.id().unwrap())</span>
<span class="doccomment">/// } else {</span>
<span class="doccomment">/// &quot;Welcome Anonymous!&quot;.to_owned()</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">id</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">String</span>, <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">session</span>.<span class="ident">get</span>(<span class="ident">ID_KEY</span>)<span class="question-mark">?</span>.<span class="ident">ok_or_else</span>(<span class="op">|</span><span class="op">|</span> {
<span class="kw">impl </span>Identity {
<span class="doccomment">/// Return the user id associated to the current session.
///
/// # Examples
/// ```
/// use actix_web::{get, Responder};
/// use actix_identity::Identity;
///
/// #[get(&quot;/&quot;)]
/// async fn index(user: Option&lt;Identity&gt;) -&gt; impl Responder {
/// if let Some(user) = user {
/// format!(&quot;Welcome! {}&quot;, user.id().unwrap())
/// } else {
/// &quot;Welcome Anonymous!&quot;.to_owned()
/// }
/// }
/// ```
</span><span class="kw">pub fn </span>id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;String, anyhow::Error&gt; {
<span class="self">self</span>.<span class="number">0</span>.session.get(ID_KEY)<span class="question-mark">?</span>.ok_or_else(|| {
<span class="macro">anyhow!</span>(<span class="string">&quot;Bug: the identity information attached to the current session has disappeared&quot;</span>)
})
}
<span class="doccomment">/// Attach a valid user identity to the current session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// This method should be called after you have successfully authenticated the user. After</span>
<span class="doccomment">/// `login` has been called, the user will be able to access all routes that require a valid</span>
<span class="doccomment">/// [`Identity`].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_web::{post, Responder, HttpRequest, HttpMessage, HttpResponse};</span>
<span class="doccomment">/// use actix_identity::Identity;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[post(&quot;/login&quot;)]</span>
<span class="doccomment">/// async fn login(request: HttpRequest) -&gt; impl Responder {</span>
<span class="doccomment">/// Identity::login(&amp;request.extensions(), &quot;User1&quot;.into());</span>
<span class="doccomment">/// HttpResponse::Ok()</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">login</span>(<span class="ident">ext</span>: <span class="kw-2">&amp;</span><span class="ident">Extensions</span>, <span class="ident">id</span>: <span class="ident">String</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">inner</span> <span class="op">=</span> <span class="ident">IdentityInner::extract</span>(<span class="ident">ext</span>);
<span class="ident">inner</span>.<span class="ident">session</span>.<span class="ident">insert</span>(<span class="ident">ID_KEY</span>, <span class="ident">id</span>)<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">now</span> <span class="op">=</span> <span class="ident">OffsetDateTime::now_utc</span>().<span class="ident">unix_timestamp</span>();
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">is_login_deadline_enabled</span> {
<span class="ident">inner</span>.<span class="ident">session</span>.<span class="ident">insert</span>(<span class="ident">LOGIN_UNIX_TIMESTAMP_KEY</span>, <span class="ident">now</span>)<span class="question-mark">?</span>;
<span class="doccomment">/// Attach a valid user identity to the current session.
///
/// This method should be called after you have successfully authenticated the user. After
/// `login` has been called, the user will be able to access all routes that require a valid
/// [`Identity`].
///
/// # Examples
/// ```
/// use actix_web::{post, Responder, HttpRequest, HttpMessage, HttpResponse};
/// use actix_identity::Identity;
///
/// #[post(&quot;/login&quot;)]
/// async fn login(request: HttpRequest) -&gt; impl Responder {
/// Identity::login(&amp;request.extensions(), &quot;User1&quot;.into());
/// HttpResponse::Ok()
/// }
/// ```
</span><span class="kw">pub fn </span>login(ext: <span class="kw-2">&amp;</span>Extensions, id: String) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, anyhow::Error&gt; {
<span class="kw">let </span>inner = IdentityInner::extract(ext);
inner.session.insert(ID_KEY, id)<span class="question-mark">?</span>;
<span class="kw">let </span>now = OffsetDateTime::now_utc().unix_timestamp();
<span class="kw">if </span>inner.is_login_deadline_enabled {
inner.session.insert(LOGIN_UNIX_TIMESTAMP_KEY, now)<span class="question-mark">?</span>;
}
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">is_visit_deadline_enabled</span> {
<span class="ident">inner</span>.<span class="ident">session</span>.<span class="ident">insert</span>(<span class="ident">LAST_VISIT_UNIX_TIMESTAMP_KEY</span>, <span class="ident">now</span>)<span class="question-mark">?</span>;
<span class="kw">if </span>inner.is_visit_deadline_enabled {
inner.session.insert(LAST_VISIT_UNIX_TIMESTAMP_KEY, now)<span class="question-mark">?</span>;
}
<span class="ident">inner</span>.<span class="ident">session</span>.<span class="ident">renew</span>();
<span class="prelude-val">Ok</span>(<span class="self">Self</span>(<span class="ident">inner</span>))
inner.session.renew();
<span class="prelude-val">Ok</span>(<span class="self">Self</span>(inner))
}
<span class="doccomment">/// Remove the user identity from the current session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// After `logout` has been called, the user will no longer be able to access routes that</span>
<span class="doccomment">/// require a valid [`Identity`].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// The behaviour on logout is determined by [`IdentityMiddlewareBuilder::logout_behaviour`].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_web::{post, Responder, HttpResponse};</span>
<span class="doccomment">/// use actix_identity::Identity;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[post(&quot;/logout&quot;)]</span>
<span class="doccomment">/// async fn logout(user: Identity) -&gt; impl Responder {</span>
<span class="doccomment">/// user.logout();</span>
<span class="doccomment">/// HttpResponse::Ok()</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`IdentityMiddlewareBuilder::logout_behaviour`]: crate::config::IdentityMiddlewareBuilder::logout_behaviour</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">logout</span>(<span class="self">self</span>) {
<span class="kw">match</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">logout_behaviour</span> {
<span class="ident">LogoutBehaviour::PurgeSession</span> =&gt; {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">session</span>.<span class="ident">purge</span>();
<span class="doccomment">/// Remove the user identity from the current session.
///
/// After `logout` has been called, the user will no longer be able to access routes that
/// require a valid [`Identity`].
///
/// The behaviour on logout is determined by [`IdentityMiddlewareBuilder::logout_behaviour`].
///
/// # Examples
/// ```
/// use actix_web::{post, Responder, HttpResponse};
/// use actix_identity::Identity;
///
/// #[post(&quot;/logout&quot;)]
/// async fn logout(user: Identity) -&gt; impl Responder {
/// user.logout();
/// HttpResponse::Ok()
/// }
/// ```
///
/// [`IdentityMiddlewareBuilder::logout_behaviour`]: crate::config::IdentityMiddlewareBuilder::logout_behaviour
</span><span class="kw">pub fn </span>logout(<span class="self">self</span>) {
<span class="kw">match </span><span class="self">self</span>.<span class="number">0</span>.logout_behaviour {
LogoutBehaviour::PurgeSession =&gt; {
<span class="self">self</span>.<span class="number">0</span>.session.purge();
}
<span class="ident">LogoutBehaviour::DeleteIdentityKeys</span> =&gt; {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">session</span>.<span class="ident">remove</span>(<span class="ident">ID_KEY</span>);
<span class="kw">if</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">is_login_deadline_enabled</span> {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">session</span>.<span class="ident">remove</span>(<span class="ident">LOGIN_UNIX_TIMESTAMP_KEY</span>);
LogoutBehaviour::DeleteIdentityKeys =&gt; {
<span class="self">self</span>.<span class="number">0</span>.session.remove(ID_KEY);
<span class="kw">if </span><span class="self">self</span>.<span class="number">0</span>.is_login_deadline_enabled {
<span class="self">self</span>.<span class="number">0</span>.session.remove(LOGIN_UNIX_TIMESTAMP_KEY);
}
<span class="kw">if</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">is_visit_deadline_enabled</span> {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">session</span>.<span class="ident">remove</span>(<span class="ident">LAST_VISIT_UNIX_TIMESTAMP_KEY</span>);
<span class="kw">if </span><span class="self">self</span>.<span class="number">0</span>.is_visit_deadline_enabled {
<span class="self">self</span>.<span class="number">0</span>.session.remove(LAST_VISIT_UNIX_TIMESTAMP_KEY);
}
}
}
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">extract</span>(<span class="ident">ext</span>: <span class="kw-2">&amp;</span><span class="ident">Extensions</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">inner</span> <span class="op">=</span> <span class="ident">IdentityInner::extract</span>(<span class="ident">ext</span>);
<span class="ident">inner</span>.<span class="ident">get_identity</span>()<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(<span class="self">Self</span>(<span class="ident">inner</span>))
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>extract(ext: <span class="kw-2">&amp;</span>Extensions) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, anyhow::Error&gt; {
<span class="kw">let </span>inner = IdentityInner::extract(ext);
inner.get_identity()<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(<span class="self">Self</span>(inner))
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">logged_at</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">OffsetDateTime</span><span class="op">&gt;</span>, <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="self">self</span>.<span class="number">0</span>
.<span class="ident">session</span>
.<span class="ident">get</span>(<span class="ident">LOGIN_UNIX_TIMESTAMP_KEY</span>)<span class="question-mark">?</span>
.<span class="ident">map</span>(<span class="ident">OffsetDateTime::from_unix_timestamp</span>)
.<span class="ident">transpose</span>()
.<span class="ident">map_err</span>(<span class="ident">anyhow::Error::from</span>)
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>logged_at(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;OffsetDateTime&gt;, anyhow::Error&gt; {
<span class="self">self</span>.<span class="number">0
</span>.session
.get(LOGIN_UNIX_TIMESTAMP_KEY)<span class="question-mark">?
</span>.map(OffsetDateTime::from_unix_timestamp)
.transpose()
.map_err(anyhow::Error::from)
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">last_visited_at</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">OffsetDateTime</span><span class="op">&gt;</span>, <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="self">self</span>.<span class="number">0</span>
.<span class="ident">session</span>
.<span class="ident">get</span>(<span class="ident">LAST_VISIT_UNIX_TIMESTAMP_KEY</span>)<span class="question-mark">?</span>
.<span class="ident">map</span>(<span class="ident">OffsetDateTime::from_unix_timestamp</span>)
.<span class="ident">transpose</span>()
.<span class="ident">map_err</span>(<span class="ident">anyhow::Error::from</span>)
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>last_visited_at(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;OffsetDateTime&gt;, anyhow::Error&gt; {
<span class="self">self</span>.<span class="number">0
</span>.session
.get(LAST_VISIT_UNIX_TIMESTAMP_KEY)<span class="question-mark">?
</span>.map(OffsetDateTime::from_unix_timestamp)
.transpose()
.map_err(anyhow::Error::from)
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">set_last_visited_at</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">now</span> <span class="op">=</span> <span class="ident">OffsetDateTime::now_utc</span>().<span class="ident">unix_timestamp</span>();
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">session</span>.<span class="ident">insert</span>(<span class="ident">LAST_VISIT_UNIX_TIMESTAMP_KEY</span>, <span class="ident">now</span>)<span class="question-mark">?</span>;
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>set_last_visited_at(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), anyhow::Error&gt; {
<span class="kw">let </span>now = OffsetDateTime::now_utc().unix_timestamp();
<span class="self">self</span>.<span class="number">0</span>.session.insert(LAST_VISIT_UNIX_TIMESTAMP_KEY, now)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(())
}
}
<span class="doccomment">/// Extractor implementation for [`Identity`].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_web::{get, Responder};</span>
<span class="doccomment">/// use actix_identity::Identity;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[get(&quot;/&quot;)]</span>
<span class="doccomment">/// async fn index(user: Option&lt;Identity&gt;) -&gt; impl Responder {</span>
<span class="doccomment">/// if let Some(user) = user {</span>
<span class="doccomment">/// format!(&quot;Welcome! {}&quot;, user.id().unwrap())</span>
<span class="doccomment">/// } else {</span>
<span class="doccomment">/// &quot;Welcome Anonymous!&quot;.to_owned()</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="kw">impl</span> <span class="ident">FromRequest</span> <span class="kw">for</span> <span class="ident">Identity</span> {
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span>;
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">Ready</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="doccomment">/// Extractor implementation for [`Identity`].
///
/// # Examples
/// ```
/// use actix_web::{get, Responder};
/// use actix_identity::Identity;
///
/// #[get(&quot;/&quot;)]
/// async fn index(user: Option&lt;Identity&gt;) -&gt; impl Responder {
/// if let Some(user) = user {
/// format!(&quot;Welcome! {}&quot;, user.id().unwrap())
/// } else {
/// &quot;Welcome Anonymous!&quot;.to_owned()
/// }
/// }
/// ```
</span><span class="kw">impl </span>FromRequest <span class="kw">for </span>Identity {
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Future = Ready&lt;<span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, <span class="self">Self</span>::Error&gt;&gt;;
<span class="attribute">#[<span class="ident">inline</span>]</span>
<span class="kw">fn</span> <span class="ident">from_request</span>(<span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">HttpRequest</span>, <span class="kw">_</span>: <span class="kw-2">&amp;mut</span> <span class="ident">Payload</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="ident">ready</span>(<span class="ident">Identity::extract</span>(<span class="kw-2">&amp;</span><span class="ident">req</span>.<span class="ident">extensions</span>()).<span class="ident">map_err</span>(<span class="op">|</span><span class="ident">err</span><span class="op">|</span> {
<span class="kw">let</span> <span class="ident">res</span> <span class="op">=</span> <span class="ident">actix_web::error::InternalError::from_response</span>(
<span class="ident">err</span>,
<span class="ident">HttpResponse::new</span>(<span class="ident">StatusCode::UNAUTHORIZED</span>),
<span class="attribute">#[inline]
</span><span class="kw">fn </span>from_request(req: <span class="kw-2">&amp;</span>HttpRequest, <span class="kw">_</span>: <span class="kw-2">&amp;mut </span>Payload) -&gt; <span class="self">Self</span>::Future {
ready(Identity::extract(<span class="kw-2">&amp;</span>req.extensions()).map_err(|err| {
<span class="kw">let </span>res = actix_web::error::InternalError::from_response(
err,
HttpResponse::new(StatusCode::UNAUTHORIZED),
);
<span class="ident">actix_web::Error::from</span>(<span class="ident">res</span>)
actix_web::Error::from(res)
}))
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_identity" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_identity" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -25,32 +25,32 @@
<span id="25">25</span>
<span id="26">26</span>
<span id="27">27</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">actix_web</span>::{<span class="ident">dev::ServiceRequest</span>, <span class="ident">guard::GuardContext</span>, <span class="ident">HttpMessage</span>, <span class="ident">HttpRequest</span>};
</pre><pre class="rust"><code><span class="kw">use </span>actix_web::{dev::ServiceRequest, guard::GuardContext, HttpMessage, HttpRequest};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::Identity</span>;
<span class="kw">use </span><span class="kw">crate</span>::Identity;
<span class="doccomment">/// Helper trait to retrieve an [`Identity`] instance from various `actix-web`&#39;s types.</span>
<span class="kw">pub</span> <span class="kw">trait</span> <span class="ident">IdentityExt</span> {
<span class="doccomment">/// Retrieve the identity attached to the current session, if available.</span>
<span class="kw">fn</span> <span class="ident">get_identity</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">Identity</span>, <span class="ident">anyhow::Error</span><span class="op">&gt;</span>;
<span class="doccomment">/// Helper trait to retrieve an [`Identity`] instance from various `actix-web`&#39;s types.
</span><span class="kw">pub trait </span>IdentityExt {
<span class="doccomment">/// Retrieve the identity attached to the current session, if available.
</span><span class="kw">fn </span>get_identity(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Identity, anyhow::Error&gt;;
}
<span class="kw">impl</span> <span class="ident">IdentityExt</span> <span class="kw">for</span> <span class="ident">HttpRequest</span> {
<span class="kw">fn</span> <span class="ident">get_identity</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">Identity</span>, <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="ident">Identity::extract</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">extensions</span>())
<span class="kw">impl </span>IdentityExt <span class="kw">for </span>HttpRequest {
<span class="kw">fn </span>get_identity(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Identity, anyhow::Error&gt; {
Identity::extract(<span class="kw-2">&amp;</span><span class="self">self</span>.extensions())
}
}
<span class="kw">impl</span> <span class="ident">IdentityExt</span> <span class="kw">for</span> <span class="ident">ServiceRequest</span> {
<span class="kw">fn</span> <span class="ident">get_identity</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">Identity</span>, <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="ident">Identity::extract</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">extensions</span>())
<span class="kw">impl </span>IdentityExt <span class="kw">for </span>ServiceRequest {
<span class="kw">fn </span>get_identity(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Identity, anyhow::Error&gt; {
Identity::extract(<span class="kw-2">&amp;</span><span class="self">self</span>.extensions())
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span> <span class="ident">IdentityExt</span> <span class="kw">for</span> <span class="ident">GuardContext</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">get_identity</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">Identity</span>, <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="ident">Identity::extract</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">req_data</span>())
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;a</span>&gt; IdentityExt <span class="kw">for </span>GuardContext&lt;<span class="lifetime">&#39;a</span>&gt; {
<span class="kw">fn </span>get_identity(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Identity, anyhow::Error&gt; {
Identity::extract(<span class="kw-2">&amp;</span><span class="self">self</span>.req_data())
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_identity" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_identity" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -98,105 +98,105 @@
<span id="98">98</span>
<span id="99">99</span>
<span id="100">100</span>
</pre><pre class="rust"><code><span class="doccomment">//! Identity management for Actix Web.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! `actix-identity` can be used to track identity of a user across multiple requests. It is built</span>
<span class="doccomment">//! on top of HTTP sessions, via [`actix-session`](https://docs.rs/actix-session).</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! # Getting started</span>
<span class="doccomment">//! To start using identity management in your Actix Web application you must register</span>
<span class="doccomment">//! [`IdentityMiddleware`] and `SessionMiddleware` as middleware on your `App`:</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! ```no_run</span>
<span class="doccomment">//! # use actix_web::web;</span>
<span class="doccomment">//! use actix_web::{cookie::Key, App, HttpServer, HttpResponse};</span>
<span class="doccomment">//! use actix_identity::IdentityMiddleware;</span>
<span class="doccomment">//! use actix_session::{storage::RedisSessionStore, SessionMiddleware};</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! #[actix_web::main]</span>
<span class="doccomment">//! async fn main() {</span>
<span class="doccomment">//! let secret_key = Key::generate();</span>
<span class="doccomment">//! let redis_store = RedisSessionStore::new(&quot;redis://127.0.0.1:6379&quot;)</span>
<span class="doccomment">//! .await</span>
<span class="doccomment">//! .unwrap();</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! HttpServer::new(move || {</span>
<span class="doccomment">//! App::new()</span>
<span class="doccomment">//! // Install the identity framework first.</span>
<span class="doccomment">//! .wrap(IdentityMiddleware::default())</span>
<span class="doccomment">//! // The identity system is built on top of sessions. You must install the session</span>
<span class="doccomment">//! // middleware to leverage `actix-identity`. The session middleware must be mounted</span>
<span class="doccomment">//! // AFTER the identity middleware: `actix-web` invokes middleware in the OPPOSITE</span>
<span class="doccomment">//! // order of registration when it receives an incoming request.</span>
<span class="doccomment">//! .wrap(SessionMiddleware::new(</span>
<span class="doccomment">//! redis_store.clone(),</span>
<span class="doccomment">//! secret_key.clone()</span>
<span class="doccomment">//! ))</span>
<span class="doccomment">//! // Your request handlers [...]</span>
<span class="doccomment">//! # .default_service(web::to(|| HttpResponse::Ok()))</span>
<span class="doccomment">//! })</span>
<span class="doccomment">//! # ;</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//! ```</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! User identities can be created, accessed and destroyed using the [`Identity`] extractor in your</span>
<span class="doccomment">//! request handlers:</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! ```no_run</span>
<span class="doccomment">//! use actix_web::{get, post, HttpResponse, Responder, HttpRequest, HttpMessage};</span>
<span class="doccomment">//! use actix_identity::Identity;</span>
<span class="doccomment">//! use actix_session::storage::RedisSessionStore;</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! #[get(&quot;/&quot;)]</span>
<span class="doccomment">//! async fn index(user: Option&lt;Identity&gt;) -&gt; impl Responder {</span>
<span class="doccomment">//! if let Some(user) = user {</span>
<span class="doccomment">//! format!(&quot;Welcome! {}&quot;, user.id().unwrap())</span>
<span class="doccomment">//! } else {</span>
<span class="doccomment">//! &quot;Welcome Anonymous!&quot;.to_owned()</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! #[post(&quot;/login&quot;)]</span>
<span class="doccomment">//! async fn login(request: HttpRequest) -&gt; impl Responder {</span>
<span class="doccomment">//! // Some kind of authentication should happen here</span>
<span class="doccomment">//! // e.g. password-based, biometric, etc.</span>
<span class="doccomment">//! // [...]</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! // attach a verified user identity to the active session</span>
<span class="doccomment">//! Identity::login(&amp;request.extensions(), &quot;User1&quot;.into()).unwrap();</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! HttpResponse::Ok()</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! #[post(&quot;/logout&quot;)]</span>
<span class="doccomment">//! async fn logout(user: Identity) -&gt; impl Responder {</span>
<span class="doccomment">//! user.logout();</span>
<span class="doccomment">//! HttpResponse::Ok()</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//! ```</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! # Advanced configuration</span>
<span class="doccomment">//! By default, `actix-identity` does not automatically log out users. You can change this behaviour</span>
<span class="doccomment">//! by customising the configuration for [`IdentityMiddleware`] via [`IdentityMiddleware::builder`].</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! In particular, you can automatically log out users who:</span>
<span class="doccomment">//! - have been inactive for a while (see [`IdentityMiddlewareBuilder::visit_deadline`];</span>
<span class="doccomment">//! - logged in too long ago (see [`IdentityMiddlewareBuilder::login_deadline`]).</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! [`IdentityMiddlewareBuilder::visit_deadline`]: config::IdentityMiddlewareBuilder::visit_deadline</span>
<span class="doccomment">//! [`IdentityMiddlewareBuilder::login_deadline`]: config::IdentityMiddlewareBuilder::login_deadline</span>
</pre><pre class="rust"><code><span class="doccomment">//! Identity management for Actix Web.
//!
//! `actix-identity` can be used to track identity of a user across multiple requests. It is built
//! on top of HTTP sessions, via [`actix-session`](https://docs.rs/actix-session).
//!
//! # Getting started
//! To start using identity management in your Actix Web application you must register
//! [`IdentityMiddleware`] and `SessionMiddleware` as middleware on your `App`:
//!
//! ```no_run
//! # use actix_web::web;
//! use actix_web::{cookie::Key, App, HttpServer, HttpResponse};
//! use actix_identity::IdentityMiddleware;
//! use actix_session::{storage::RedisSessionStore, SessionMiddleware};
//!
//! #[actix_web::main]
//! async fn main() {
//! let secret_key = Key::generate();
//! let redis_store = RedisSessionStore::new(&quot;redis://127.0.0.1:6379&quot;)
//! .await
//! .unwrap();
//!
//! HttpServer::new(move || {
//! App::new()
//! // Install the identity framework first.
//! .wrap(IdentityMiddleware::default())
//! // The identity system is built on top of sessions. You must install the session
//! // middleware to leverage `actix-identity`. The session middleware must be mounted
//! // AFTER the identity middleware: `actix-web` invokes middleware in the OPPOSITE
//! // order of registration when it receives an incoming request.
//! .wrap(SessionMiddleware::new(
//! redis_store.clone(),
//! secret_key.clone()
//! ))
//! // Your request handlers [...]
//! # .default_service(web::to(|| HttpResponse::Ok()))
//! })
//! # ;
//! }
//! ```
//!
//! User identities can be created, accessed and destroyed using the [`Identity`] extractor in your
//! request handlers:
//!
//! ```no_run
//! use actix_web::{get, post, HttpResponse, Responder, HttpRequest, HttpMessage};
//! use actix_identity::Identity;
//! use actix_session::storage::RedisSessionStore;
//!
//! #[get(&quot;/&quot;)]
//! async fn index(user: Option&lt;Identity&gt;) -&gt; impl Responder {
//! if let Some(user) = user {
//! format!(&quot;Welcome! {}&quot;, user.id().unwrap())
//! } else {
//! &quot;Welcome Anonymous!&quot;.to_owned()
//! }
//! }
//!
//! #[post(&quot;/login&quot;)]
//! async fn login(request: HttpRequest) -&gt; impl Responder {
//! // Some kind of authentication should happen here
//! // e.g. password-based, biometric, etc.
//! // [...]
//!
//! // attach a verified user identity to the active session
//! Identity::login(&amp;request.extensions(), &quot;User1&quot;.into()).unwrap();
//!
//! HttpResponse::Ok()
//! }
//!
//! #[post(&quot;/logout&quot;)]
//! async fn logout(user: Identity) -&gt; impl Responder {
//! user.logout();
//! HttpResponse::Ok()
//! }
//! ```
//!
//! # Advanced configuration
//! By default, `actix-identity` does not automatically log out users. You can change this behaviour
//! by customising the configuration for [`IdentityMiddleware`] via [`IdentityMiddleware::builder`].
//!
//! In particular, you can automatically log out users who:
//! - have been inactive for a while (see [`IdentityMiddlewareBuilder::visit_deadline`];
//! - logged in too long ago (see [`IdentityMiddlewareBuilder::login_deadline`]).
//!
//! [`IdentityMiddlewareBuilder::visit_deadline`]: config::IdentityMiddlewareBuilder::visit_deadline
//! [`IdentityMiddlewareBuilder::login_deadline`]: config::IdentityMiddlewareBuilder::login_deadline
<span class="attribute">#![<span class="ident">forbid</span>(<span class="ident">unsafe_code</span>)]</span>
<span class="attribute">#![<span class="ident">deny</span>(<span class="ident">rust_2018_idioms</span>, <span class="ident">nonstandard_style</span>, <span class="ident">missing_docs</span>)]</span>
<span class="attribute">#![<span class="ident">warn</span>(<span class="ident">future_incompatible</span>)]</span>
</span><span class="attribute">#![forbid(unsafe_code)]
#![deny(rust_2018_idioms, nonstandard_style, missing_docs)]
#![warn(future_incompatible)]
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">config</span>;
<span class="kw">mod</span> <span class="ident">identity</span>;
<span class="kw">mod</span> <span class="ident">identity_ext</span>;
<span class="kw">mod</span> <span class="ident">middleware</span>;
</span><span class="kw">pub mod </span>config;
<span class="kw">mod </span>identity;
<span class="kw">mod </span>identity_ext;
<span class="kw">mod </span>middleware;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::identity::Identity</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::identity_ext::IdentityExt</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::middleware::IdentityMiddleware</span>;
<span class="kw">pub use </span><span class="self">self</span>::identity::Identity;
<span class="kw">pub use </span><span class="self">self</span>::identity_ext::IdentityExt;
<span class="kw">pub use </span><span class="self">self</span>::middleware::IdentityMiddleware;
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_identity" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_identity" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -254,261 +254,261 @@
<span id="254">254</span>
<span id="255">255</span>
<span id="256">256</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::rc::Rc</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::rc::Rc;
<span class="kw">use</span> <span class="ident">actix_session::SessionExt</span>;
<span class="kw">use</span> <span class="ident">actix_utils::future</span>::{<span class="ident">ready</span>, <span class="ident">Ready</span>};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">body::MessageBody</span>,
<span class="ident">cookie::time</span>::{<span class="ident">format_description::well_known::Rfc3339</span>, <span class="ident">OffsetDateTime</span>},
<span class="ident">dev</span>::{<span class="ident">Service</span>, <span class="ident">ServiceRequest</span>, <span class="ident">ServiceResponse</span>, <span class="ident">Transform</span>},
<span class="ident">Error</span>, <span class="ident">HttpMessage</span> <span class="kw">as</span> <span class="kw">_</span>, <span class="prelude-ty">Result</span>,
<span class="kw">use </span>actix_session::SessionExt;
<span class="kw">use </span>actix_utils::future::{ready, Ready};
<span class="kw">use </span>actix_web::{
body::MessageBody,
cookie::time::{format_description::well_known::Rfc3339, OffsetDateTime},
dev::{Service, ServiceRequest, ServiceResponse, Transform},
Error, HttpMessage <span class="kw">as _</span>, <span class="prelude-ty">Result</span>,
};
<span class="kw">use</span> <span class="ident">futures_core::future::LocalBoxFuture</span>;
<span class="kw">use </span>futures_core::future::LocalBoxFuture;
<span class="kw">use</span> <span class="kw">crate</span>::{
<span class="ident">config</span>::{<span class="ident">Configuration</span>, <span class="ident">IdentityMiddlewareBuilder</span>},
<span class="ident">identity::IdentityInner</span>,
<span class="ident">Identity</span>,
<span class="kw">use crate</span>::{
config::{Configuration, IdentityMiddlewareBuilder},
identity::IdentityInner,
Identity,
};
<span class="doccomment">/// Identity management middleware.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ```no_run</span>
<span class="doccomment">/// use actix_web::{cookie::Key, App, HttpServer};</span>
<span class="doccomment">/// use actix_session::storage::RedisSessionStore;</span>
<span class="doccomment">/// use actix_identity::{Identity, IdentityMiddleware};</span>
<span class="doccomment">/// use actix_session::{Session, SessionMiddleware};</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[actix_web::main]</span>
<span class="doccomment">/// async fn main() {</span>
<span class="doccomment">/// let secret_key = Key::generate();</span>
<span class="doccomment">/// let redis_store = RedisSessionStore::new(&quot;redis://127.0.0.1:6379&quot;).await.unwrap();</span>
<span class="doccomment">///</span>
<span class="doccomment">/// HttpServer::new(move || {</span>
<span class="doccomment">/// App::new()</span>
<span class="doccomment">/// // Install the identity framework first.</span>
<span class="doccomment">/// .wrap(IdentityMiddleware::default())</span>
<span class="doccomment">/// // The identity system is built on top of sessions.</span>
<span class="doccomment">/// // You must install the session middleware to leverage `actix-identity`.</span>
<span class="doccomment">/// .wrap(SessionMiddleware::new(redis_store.clone(), secret_key.clone()))</span>
<span class="doccomment">/// })</span>
<span class="doccomment">/// # ;</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Default</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">IdentityMiddleware</span> {
<span class="ident">configuration</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">Configuration</span><span class="op">&gt;</span>,
<span class="doccomment">/// Identity management middleware.
///
/// ```no_run
/// use actix_web::{cookie::Key, App, HttpServer};
/// use actix_session::storage::RedisSessionStore;
/// use actix_identity::{Identity, IdentityMiddleware};
/// use actix_session::{Session, SessionMiddleware};
///
/// #[actix_web::main]
/// async fn main() {
/// let secret_key = Key::generate();
/// let redis_store = RedisSessionStore::new(&quot;redis://127.0.0.1:6379&quot;).await.unwrap();
///
/// HttpServer::new(move || {
/// App::new()
/// // Install the identity framework first.
/// .wrap(IdentityMiddleware::default())
/// // The identity system is built on top of sessions.
/// // You must install the session middleware to leverage `actix-identity`.
/// .wrap(SessionMiddleware::new(redis_store.clone(), secret_key.clone()))
/// })
/// # ;
/// }
/// ```
</span><span class="attribute">#[derive(Default, Clone)]
</span><span class="kw">pub struct </span>IdentityMiddleware {
configuration: Rc&lt;Configuration&gt;,
}
<span class="kw">impl</span> <span class="ident">IdentityMiddleware</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">new</span>(<span class="ident">configuration</span>: <span class="ident">Configuration</span>) -&gt; <span class="self">Self</span> {
<span class="self">Self</span> {
<span class="ident">configuration</span>: <span class="ident">Rc::new</span>(<span class="ident">configuration</span>),
<span class="kw">impl </span>IdentityMiddleware {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new(configuration: Configuration) -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{
configuration: Rc::new(configuration),
}
}
<span class="doccomment">/// A fluent API to configure [`IdentityMiddleware`].</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">builder</span>() -&gt; <span class="ident">IdentityMiddlewareBuilder</span> {
<span class="ident">IdentityMiddlewareBuilder::new</span>()
<span class="doccomment">/// A fluent API to configure [`IdentityMiddleware`].
</span><span class="kw">pub fn </span>builder() -&gt; IdentityMiddlewareBuilder {
IdentityMiddlewareBuilder::new()
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">B</span><span class="op">&gt;</span> <span class="ident">Transform</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">ServiceRequest</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">IdentityMiddleware</span>
<span class="kw">where</span>
<span class="ident">S</span>: <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>, <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span><span class="op">&gt;</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">S::Future</span>: <span class="lifetime">&#39;static</span>,
<span class="ident">B</span>: <span class="ident">MessageBody</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="kw">impl</span>&lt;S, B&gt; Transform&lt;S, ServiceRequest&gt; <span class="kw">for </span>IdentityMiddleware
<span class="kw">where
</span>S: Service&lt;ServiceRequest, Response = ServiceResponse&lt;B&gt;, Error = Error&gt; + <span class="lifetime">&#39;static</span>,
S::Future: <span class="lifetime">&#39;static</span>,
B: MessageBody + <span class="lifetime">&#39;static</span>,
{
<span class="kw">type</span> <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span>;
<span class="kw">type</span> <span class="ident">Transform</span> <span class="op">=</span> <span class="ident">InnerIdentityMiddleware</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">InitError</span> <span class="op">=</span> ();
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">Ready</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Transform</span>, <span class="ident"><span class="self">Self</span>::InitError</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type </span>Response = ServiceResponse&lt;B&gt;;
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Transform = InnerIdentityMiddleware&lt;S&gt;;
<span class="kw">type </span>InitError = ();
<span class="kw">type </span>Future = Ready&lt;<span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Transform, <span class="self">Self</span>::InitError&gt;&gt;;
<span class="kw">fn</span> <span class="ident">new_transform</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">service</span>: <span class="ident">S</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="ident">ready</span>(<span class="prelude-val">Ok</span>(<span class="ident">InnerIdentityMiddleware</span> {
<span class="ident">service</span>: <span class="ident">Rc::new</span>(<span class="ident">service</span>),
<span class="ident">configuration</span>: <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">configuration</span>),
<span class="kw">fn </span>new_transform(<span class="kw-2">&amp;</span><span class="self">self</span>, service: S) -&gt; <span class="self">Self</span>::Future {
ready(<span class="prelude-val">Ok</span>(InnerIdentityMiddleware {
service: Rc::new(service),
configuration: Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.configuration),
}))
}
}
<span class="attribute">#[<span class="ident">doc</span>(<span class="ident">hidden</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">InnerIdentityMiddleware</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="ident">service</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span>,
<span class="ident">configuration</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">Configuration</span><span class="op">&gt;</span>,
<span class="attribute">#[doc(hidden)]
</span><span class="kw">pub struct </span>InnerIdentityMiddleware&lt;S&gt; {
service: Rc&lt;S&gt;,
configuration: Rc&lt;Configuration&gt;,
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> <span class="ident">Clone</span> <span class="kw">for</span> <span class="ident">InnerIdentityMiddleware</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="self">Self</span> {
<span class="self">Self</span> {
<span class="ident">service</span>: <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">service</span>),
<span class="ident">configuration</span>: <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">configuration</span>),
<span class="kw">impl</span>&lt;S&gt; Clone <span class="kw">for </span>InnerIdentityMiddleware&lt;S&gt; {
<span class="kw">fn </span>clone(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{
service: Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.service),
configuration: Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.configuration),
}
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">B</span><span class="op">&gt;</span> <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">InnerIdentityMiddleware</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">S</span>: <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>, <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span><span class="op">&gt;</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">S::Future</span>: <span class="lifetime">&#39;static</span>,
<span class="ident">B</span>: <span class="ident">MessageBody</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="kw">impl</span>&lt;S, B&gt; Service&lt;ServiceRequest&gt; <span class="kw">for </span>InnerIdentityMiddleware&lt;S&gt;
<span class="kw">where
</span>S: Service&lt;ServiceRequest, Response = ServiceResponse&lt;B&gt;, Error = Error&gt; + <span class="lifetime">&#39;static</span>,
S::Future: <span class="lifetime">&#39;static</span>,
B: MessageBody + <span class="lifetime">&#39;static</span>,
{
<span class="kw">type</span> <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span>;
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">LocalBoxFuture</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Response</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type </span>Response = ServiceResponse&lt;B&gt;;
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Future = LocalBoxFuture&lt;<span class="lifetime">&#39;static</span>, <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Response, <span class="self">Self</span>::Error&gt;&gt;;
<span class="macro">actix_service::forward_ready!</span>(<span class="ident">service</span>);
<span class="macro">actix_service::forward_ready!</span>(service);
<span class="kw">fn</span> <span class="ident">call</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">req</span>: <span class="ident">ServiceRequest</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="kw">let</span> <span class="ident">srv</span> <span class="op">=</span> <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">service</span>);
<span class="kw">let</span> <span class="ident">configuration</span> <span class="op">=</span> <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">configuration</span>);
<span class="ident">Box::pin</span>(<span class="kw">async</span> <span class="kw">move</span> {
<span class="kw">let</span> <span class="ident">identity_inner</span> <span class="op">=</span> <span class="ident">IdentityInner</span> {
<span class="ident">session</span>: <span class="ident">req</span>.<span class="ident">get_session</span>(),
<span class="ident">logout_behaviour</span>: <span class="ident">configuration</span>.<span class="ident">on_logout</span>.<span class="ident">clone</span>(),
<span class="ident">is_login_deadline_enabled</span>: <span class="ident">configuration</span>.<span class="ident">login_deadline</span>.<span class="ident">is_some</span>(),
<span class="ident">is_visit_deadline_enabled</span>: <span class="ident">configuration</span>.<span class="ident">visit_deadline</span>.<span class="ident">is_some</span>(),
<span class="kw">fn </span>call(<span class="kw-2">&amp;</span><span class="self">self</span>, req: ServiceRequest) -&gt; <span class="self">Self</span>::Future {
<span class="kw">let </span>srv = Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.service);
<span class="kw">let </span>configuration = Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.configuration);
Box::pin(<span class="kw">async move </span>{
<span class="kw">let </span>identity_inner = IdentityInner {
session: req.get_session(),
logout_behaviour: configuration.on_logout.clone(),
is_login_deadline_enabled: configuration.login_deadline.is_some(),
is_visit_deadline_enabled: configuration.visit_deadline.is_some(),
};
<span class="ident">req</span>.<span class="ident">extensions_mut</span>().<span class="ident">insert</span>(<span class="ident">identity_inner</span>);
<span class="ident">enforce_policies</span>(<span class="kw-2">&amp;</span><span class="ident">req</span>, <span class="kw-2">&amp;</span><span class="ident">configuration</span>);
<span class="ident">srv</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span>
})
req.extensions_mut().insert(identity_inner);
enforce_policies(<span class="kw-2">&amp;</span>req, <span class="kw-2">&amp;</span>configuration);
srv.call(req).<span class="kw">await
</span>})
}
}
<span class="comment">// easier to scan with returns where they are</span>
<span class="comment">// especially if the function body were to evolve in the future</span>
<span class="attribute">#[<span class="ident">allow</span>(<span class="ident">clippy::needless_return</span>)]</span>
<span class="kw">fn</span> <span class="ident">enforce_policies</span>(<span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">ServiceRequest</span>, <span class="ident">configuration</span>: <span class="kw-2">&amp;</span><span class="ident">Configuration</span>) {
<span class="kw">let</span> <span class="ident">must_extract_identity</span> <span class="op">=</span>
<span class="ident">configuration</span>.<span class="ident">login_deadline</span>.<span class="ident">is_some</span>() <span class="op">|</span><span class="op">|</span> <span class="ident">configuration</span>.<span class="ident">visit_deadline</span>.<span class="ident">is_some</span>();
<span class="comment">// easier to scan with returns where they are
// especially if the function body were to evolve in the future
</span><span class="attribute">#[allow(clippy::needless_return)]
</span><span class="kw">fn </span>enforce_policies(req: <span class="kw-2">&amp;</span>ServiceRequest, configuration: <span class="kw-2">&amp;</span>Configuration) {
<span class="kw">let </span>must_extract_identity =
configuration.login_deadline.is_some() || configuration.visit_deadline.is_some();
<span class="kw">if</span> <span class="op">!</span><span class="ident">must_extract_identity</span> {
<span class="kw">if </span>!must_extract_identity {
<span class="kw">return</span>;
}
<span class="kw">let</span> <span class="ident">identity</span> <span class="op">=</span> <span class="kw">match</span> <span class="ident">Identity::extract</span>(<span class="kw-2">&amp;</span><span class="ident">req</span>.<span class="ident">extensions</span>()) {
<span class="prelude-val">Ok</span>(<span class="ident">identity</span>) =&gt; <span class="ident">identity</span>,
<span class="prelude-val">Err</span>(<span class="ident">err</span>) =&gt; {
<span class="kw">let </span>identity = <span class="kw">match </span>Identity::extract(<span class="kw-2">&amp;</span>req.extensions()) {
<span class="prelude-val">Ok</span>(identity) =&gt; identity,
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="macro">tracing::debug!</span>(
<span class="ident">error</span>.<span class="ident">display</span> <span class="op">=</span> <span class="op">%</span><span class="ident">err</span>,
<span class="ident">error</span>.<span class="ident">debug</span> <span class="op">=</span> <span class="question-mark">?</span><span class="ident">err</span>,
<span class="string">&quot;Failed to extract an `Identity` from the incoming request.&quot;</span>
);
error.display = %err,
error.debug = <span class="question-mark">?</span>err,
<span class="string">&quot;Failed to extract an `Identity` from the incoming request.&quot;
</span>);
<span class="kw">return</span>;
}
};
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">login_deadline</span>) <span class="op">=</span> <span class="ident">configuration</span>.<span class="ident">login_deadline</span> {
<span class="kw">if</span> <span class="macro">matches!</span>(
<span class="ident">enforce_login_deadline</span>(<span class="kw-2">&amp;</span><span class="ident">identity</span>, <span class="ident">login_deadline</span>),
<span class="ident">PolicyDecision::LogOut</span>
<span class="kw">if let </span><span class="prelude-val">Some</span>(login_deadline) = configuration.login_deadline {
<span class="kw">if </span><span class="macro">matches!</span>(
enforce_login_deadline(<span class="kw-2">&amp;</span>identity, login_deadline),
PolicyDecision::LogOut
) {
<span class="ident">identity</span>.<span class="ident">logout</span>();
identity.logout();
<span class="kw">return</span>;
}
}
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">visit_deadline</span>) <span class="op">=</span> <span class="ident">configuration</span>.<span class="ident">visit_deadline</span> {
<span class="kw">if</span> <span class="macro">matches!</span>(
<span class="ident">enforce_visit_deadline</span>(<span class="kw-2">&amp;</span><span class="ident">identity</span>, <span class="ident">visit_deadline</span>),
<span class="ident">PolicyDecision::LogOut</span>
<span class="kw">if let </span><span class="prelude-val">Some</span>(visit_deadline) = configuration.visit_deadline {
<span class="kw">if </span><span class="macro">matches!</span>(
enforce_visit_deadline(<span class="kw-2">&amp;</span>identity, visit_deadline),
PolicyDecision::LogOut
) {
<span class="ident">identity</span>.<span class="ident">logout</span>();
identity.logout();
<span class="kw">return</span>;
} <span class="kw">else</span> <span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Err</span>(<span class="ident">err</span>) <span class="op">=</span> <span class="ident">identity</span>.<span class="ident">set_last_visited_at</span>() {
} <span class="kw">else if let </span><span class="prelude-val">Err</span>(err) = identity.set_last_visited_at() {
<span class="macro">tracing::warn!</span>(
<span class="ident">error</span>.<span class="ident">display</span> <span class="op">=</span> <span class="op">%</span><span class="ident">err</span>,
<span class="ident">error</span>.<span class="ident">debug</span> <span class="op">=</span> <span class="question-mark">?</span><span class="ident">err</span>,
<span class="string">&quot;Failed to set the last visited timestamp on `Identity` for an incoming request.&quot;</span>
);
error.display = %err,
error.debug = <span class="question-mark">?</span>err,
<span class="string">&quot;Failed to set the last visited timestamp on `Identity` for an incoming request.&quot;
</span>);
}
}
}
<span class="kw">fn</span> <span class="ident">enforce_login_deadline</span>(
<span class="ident">identity</span>: <span class="kw-2">&amp;</span><span class="ident">Identity</span>,
<span class="ident">login_deadline</span>: <span class="ident">std::time::Duration</span>,
) -&gt; <span class="ident">PolicyDecision</span> {
<span class="kw">match</span> <span class="ident">identity</span>.<span class="ident">logged_at</span>() {
<span class="kw">fn </span>enforce_login_deadline(
identity: <span class="kw-2">&amp;</span>Identity,
login_deadline: std::time::Duration,
) -&gt; PolicyDecision {
<span class="kw">match </span>identity.logged_at() {
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>) =&gt; {
<span class="macro">tracing::info!</span>(
<span class="string">&quot;Login deadline is enabled, but there is no login timestamp in the session \
state attached to the incoming request. Logging the user out.&quot;</span>
);
<span class="ident">PolicyDecision::LogOut</span>
state attached to the incoming request. Logging the user out.&quot;
</span>);
PolicyDecision::LogOut
}
<span class="prelude-val">Err</span>(<span class="ident">err</span>) =&gt; {
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="macro">tracing::info!</span>(
<span class="ident">error</span>.<span class="ident">display</span> <span class="op">=</span> <span class="op">%</span><span class="ident">err</span>,
<span class="ident">error</span>.<span class="ident">debug</span> <span class="op">=</span> <span class="question-mark">?</span><span class="ident">err</span>,
error.display = %err,
error.debug = <span class="question-mark">?</span>err,
<span class="string">&quot;Login deadline is enabled but we failed to extract the login timestamp from the \
session state attached to the incoming request. Logging the user out.&quot;</span>
);
<span class="ident">PolicyDecision::LogOut</span>
session state attached to the incoming request. Logging the user out.&quot;
</span>);
PolicyDecision::LogOut
}
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(<span class="ident">logged_in_at</span>)) =&gt; {
<span class="kw">let</span> <span class="ident">elapsed</span> <span class="op">=</span> <span class="ident">OffsetDateTime::now_utc</span>() <span class="op">-</span> <span class="ident">logged_in_at</span>;
<span class="kw">if</span> <span class="ident">elapsed</span> <span class="op">&gt;</span> <span class="ident">login_deadline</span> {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(logged_in_at)) =&gt; {
<span class="kw">let </span>elapsed = OffsetDateTime::now_utc() - logged_in_at;
<span class="kw">if </span>elapsed &gt; login_deadline {
<span class="macro">tracing::info!</span>(
<span class="ident">user</span>.<span class="ident">logged_in_at</span> <span class="op">=</span> <span class="op">%</span><span class="ident">logged_in_at</span>.<span class="ident">format</span>(<span class="kw-2">&amp;</span><span class="ident">Rfc3339</span>).<span class="ident">unwrap_or_default</span>(),
<span class="ident">identity</span>.<span class="ident">login_deadline_seconds</span> <span class="op">=</span> <span class="ident">login_deadline</span>.<span class="ident">as_secs</span>(),
<span class="ident">identity</span>.<span class="ident">elapsed_since_login_seconds</span> <span class="op">=</span> <span class="ident">elapsed</span>.<span class="ident">whole_seconds</span>(),
user.logged_in_at = %logged_in_at.format(<span class="kw-2">&amp;</span>Rfc3339).unwrap_or_default(),
identity.login_deadline_seconds = login_deadline.as_secs(),
identity.elapsed_since_login_seconds = elapsed.whole_seconds(),
<span class="string">&quot;Login deadline is enabled and too much time has passed since the user logged \
in. Logging the user out.&quot;</span>
);
<span class="ident">PolicyDecision::LogOut</span>
} <span class="kw">else</span> {
<span class="ident">PolicyDecision::StayLoggedIn</span>
in. Logging the user out.&quot;
</span>);
PolicyDecision::LogOut
} <span class="kw">else </span>{
PolicyDecision::StayLoggedIn
}
}
}
}
<span class="kw">fn</span> <span class="ident">enforce_visit_deadline</span>(
<span class="ident">identity</span>: <span class="kw-2">&amp;</span><span class="ident">Identity</span>,
<span class="ident">visit_deadline</span>: <span class="ident">std::time::Duration</span>,
) -&gt; <span class="ident">PolicyDecision</span> {
<span class="kw">match</span> <span class="ident">identity</span>.<span class="ident">last_visited_at</span>() {
<span class="kw">fn </span>enforce_visit_deadline(
identity: <span class="kw-2">&amp;</span>Identity,
visit_deadline: std::time::Duration,
) -&gt; PolicyDecision {
<span class="kw">match </span>identity.last_visited_at() {
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>) =&gt; {
<span class="macro">tracing::info!</span>(
<span class="string">&quot;Last visit deadline is enabled, but there is no last visit timestamp in the \
session state attached to the incoming request. Logging the user out.&quot;</span>
);
<span class="ident">PolicyDecision::LogOut</span>
session state attached to the incoming request. Logging the user out.&quot;
</span>);
PolicyDecision::LogOut
}
<span class="prelude-val">Err</span>(<span class="ident">err</span>) =&gt; {
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="macro">tracing::info!</span>(
<span class="ident">error</span>.<span class="ident">display</span> <span class="op">=</span> <span class="op">%</span><span class="ident">err</span>,
<span class="ident">error</span>.<span class="ident">debug</span> <span class="op">=</span> <span class="question-mark">?</span><span class="ident">err</span>,
error.display = %err,
error.debug = <span class="question-mark">?</span>err,
<span class="string">&quot;Last visit deadline is enabled but we failed to extract the last visit timestamp \
from the session state attached to the incoming request. Logging the user out.&quot;</span>
);
<span class="ident">PolicyDecision::LogOut</span>
from the session state attached to the incoming request. Logging the user out.&quot;
</span>);
PolicyDecision::LogOut
}
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(<span class="ident">last_visited_at</span>)) =&gt; {
<span class="kw">let</span> <span class="ident">elapsed</span> <span class="op">=</span> <span class="ident">OffsetDateTime::now_utc</span>() <span class="op">-</span> <span class="ident">last_visited_at</span>;
<span class="kw">if</span> <span class="ident">elapsed</span> <span class="op">&gt;</span> <span class="ident">visit_deadline</span> {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(last_visited_at)) =&gt; {
<span class="kw">let </span>elapsed = OffsetDateTime::now_utc() - last_visited_at;
<span class="kw">if </span>elapsed &gt; visit_deadline {
<span class="macro">tracing::info!</span>(
<span class="ident">user</span>.<span class="ident">last_visited_at</span> <span class="op">=</span> <span class="op">%</span><span class="ident">last_visited_at</span>.<span class="ident">format</span>(<span class="kw-2">&amp;</span><span class="ident">Rfc3339</span>).<span class="ident">unwrap_or_default</span>(),
<span class="ident">identity</span>.<span class="ident">visit_deadline_seconds</span> <span class="op">=</span> <span class="ident">visit_deadline</span>.<span class="ident">as_secs</span>(),
<span class="ident">identity</span>.<span class="ident">elapsed_since_last_visit_seconds</span> <span class="op">=</span> <span class="ident">elapsed</span>.<span class="ident">whole_seconds</span>(),
user.last_visited_at = %last_visited_at.format(<span class="kw-2">&amp;</span>Rfc3339).unwrap_or_default(),
identity.visit_deadline_seconds = visit_deadline.as_secs(),
identity.elapsed_since_last_visit_seconds = elapsed.whole_seconds(),
<span class="string">&quot;Last visit deadline is enabled and too much time has passed since the last \
time the user visited. Logging the user out.&quot;</span>
);
<span class="ident">PolicyDecision::LogOut</span>
} <span class="kw">else</span> {
<span class="ident">PolicyDecision::StayLoggedIn</span>
time the user visited. Logging the user out.&quot;
</span>);
PolicyDecision::LogOut
} <span class="kw">else </span>{
PolicyDecision::StayLoggedIn
}
}
}
}
<span class="kw">enum</span> <span class="ident">PolicyDecision</span> {
<span class="ident">StayLoggedIn</span>,
<span class="ident">LogOut</span>,
<span class="kw">enum </span>PolicyDecision {
StayLoggedIn,
LogOut,
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_identity" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_identity" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -121,126 +121,126 @@
<span id="119">119</span>
<span id="120">120</span>
<span id="121">121</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">borrow::Cow</span>, <span class="ident">time::Duration</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{borrow::Cow, time::Duration};
<span class="kw">use</span> <span class="ident">redis::Client</span>;
<span class="kw">use </span>redis::Client;
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">errors::Error</span>, <span class="ident">Limiter</span>};
<span class="kw">use crate</span>::{errors::Error, Limiter};
<span class="doccomment">/// Rate limiter builder.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Builder</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">redis_url</span>: <span class="ident">String</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">limit</span>: <span class="ident">usize</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">period</span>: <span class="ident">Duration</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">cookie_name</span>: <span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">session_key</span>: <span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span>,
<span class="doccomment">/// Rate limiter builder.
</span><span class="attribute">#[derive(Debug)]
</span><span class="kw">pub struct </span>Builder {
<span class="kw">pub</span>(<span class="kw">crate</span>) redis_url: String,
<span class="kw">pub</span>(<span class="kw">crate</span>) limit: usize,
<span class="kw">pub</span>(<span class="kw">crate</span>) period: Duration,
<span class="kw">pub</span>(<span class="kw">crate</span>) cookie_name: Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) session_key: Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;,
}
<span class="kw">impl</span> <span class="ident">Builder</span> {
<span class="doccomment">/// Set upper limit.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">limit</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>, <span class="ident">limit</span>: <span class="ident">usize</span>) -&gt; <span class="kw-2">&amp;mut</span> <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">limit</span> <span class="op">=</span> <span class="ident">limit</span>;
<span class="self">self</span>
}
<span class="kw">impl </span>Builder {
<span class="doccomment">/// Set upper limit.
</span><span class="kw">pub fn </span>limit(<span class="kw-2">&amp;mut </span><span class="self">self</span>, limit: usize) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="self">self</span>.limit = limit;
<span class="self">self
</span>}
<span class="doccomment">/// Set limit window/period.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">period</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>, <span class="ident">period</span>: <span class="ident">Duration</span>) -&gt; <span class="kw-2">&amp;mut</span> <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">period</span> <span class="op">=</span> <span class="ident">period</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Set limit window/period.
</span><span class="kw">pub fn </span>period(<span class="kw-2">&amp;mut </span><span class="self">self</span>, period: Duration) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="self">self</span>.period = period;
<span class="self">self
</span>}
<span class="doccomment">/// Set name of cookie to be sent.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">cookie_name</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>, <span class="ident">cookie_name</span>: <span class="kw">impl</span> <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>) -&gt; <span class="kw-2">&amp;mut</span> <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">cookie_name</span> <span class="op">=</span> <span class="ident">cookie_name</span>.<span class="ident">into</span>();
<span class="self">self</span>
}
<span class="doccomment">/// Set name of cookie to be sent.
</span><span class="kw">pub fn </span>cookie_name(<span class="kw-2">&amp;mut </span><span class="self">self</span>, cookie_name: <span class="kw">impl </span>Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="self">self</span>.cookie_name = cookie_name.into();
<span class="self">self
</span>}
<span class="doccomment">/// Set session key to be used in backend.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">session_key</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>, <span class="ident">session_key</span>: <span class="kw">impl</span> <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>) -&gt; <span class="kw-2">&amp;mut</span> <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">session_key</span> <span class="op">=</span> <span class="ident">session_key</span>.<span class="ident">into</span>();
<span class="self">self</span>
}
<span class="doccomment">/// Set session key to be used in backend.
</span><span class="kw">pub fn </span>session_key(<span class="kw-2">&amp;mut </span><span class="self">self</span>, session_key: <span class="kw">impl </span>Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="self">self</span>.session_key = session_key.into();
<span class="self">self
</span>}
<span class="doccomment">/// Finalizes and returns a `Limiter`.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Note that this method will connect to the Redis server to test its connection which is a</span>
<span class="doccomment">/// **synchronous** operation.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">build</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">Limiter</span>, <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="prelude-val">Ok</span>(<span class="ident">Limiter</span> {
<span class="ident">client</span>: <span class="ident">Client::open</span>(<span class="self">self</span>.<span class="ident">redis_url</span>.<span class="ident">as_str</span>())<span class="question-mark">?</span>,
<span class="ident">limit</span>: <span class="self">self</span>.<span class="ident">limit</span>,
<span class="ident">period</span>: <span class="self">self</span>.<span class="ident">period</span>,
<span class="ident">cookie_name</span>: <span class="self">self</span>.<span class="ident">cookie_name</span>.<span class="ident">clone</span>(),
<span class="ident">session_key</span>: <span class="self">self</span>.<span class="ident">session_key</span>.<span class="ident">clone</span>(),
<span class="doccomment">/// Finalizes and returns a `Limiter`.
///
/// Note that this method will connect to the Redis server to test its connection which is a
/// **synchronous** operation.
</span><span class="kw">pub fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Limiter, Error&gt; {
<span class="prelude-val">Ok</span>(Limiter {
client: Client::open(<span class="self">self</span>.redis_url.as_str())<span class="question-mark">?</span>,
limit: <span class="self">self</span>.limit,
period: <span class="self">self</span>.period,
cookie_name: <span class="self">self</span>.cookie_name.clone(),
session_key: <span class="self">self</span>.session_key.clone(),
})
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_create_builder</span>() {
<span class="kw">let</span> <span class="ident">redis_url</span> <span class="op">=</span> <span class="string">&quot;redis://127.0.0.1&quot;</span>;
<span class="kw">let</span> <span class="ident">period</span> <span class="op">=</span> <span class="ident">Duration::from_secs</span>(<span class="number">10</span>);
<span class="kw">let</span> <span class="ident">builder</span> <span class="op">=</span> <span class="ident">Builder</span> {
<span class="ident">redis_url</span>: <span class="ident">redis_url</span>.<span class="ident">to_owned</span>(),
<span class="ident">limit</span>: <span class="number">100</span>,
<span class="ident">period</span>,
<span class="ident">cookie_name</span>: <span class="ident">Cow::Owned</span>(<span class="string">&quot;session&quot;</span>.<span class="ident">to_string</span>()),
<span class="ident">session_key</span>: <span class="ident">Cow::Owned</span>(<span class="string">&quot;rate-api&quot;</span>.<span class="ident">to_string</span>()),
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_create_builder() {
<span class="kw">let </span>redis_url = <span class="string">&quot;redis://127.0.0.1&quot;</span>;
<span class="kw">let </span>period = Duration::from_secs(<span class="number">10</span>);
<span class="kw">let </span>builder = Builder {
redis_url: redis_url.to_owned(),
limit: <span class="number">100</span>,
period,
cookie_name: Cow::Owned(<span class="string">&quot;session&quot;</span>.to_string()),
session_key: Cow::Owned(<span class="string">&quot;rate-api&quot;</span>.to_string()),
};
<span class="macro">assert_eq!</span>(<span class="ident">builder</span>.<span class="ident">redis_url</span>, <span class="ident">redis_url</span>);
<span class="macro">assert_eq!</span>(<span class="ident">builder</span>.<span class="ident">limit</span>, <span class="number">100</span>);
<span class="macro">assert_eq!</span>(<span class="ident">builder</span>.<span class="ident">period</span>, <span class="ident">period</span>);
<span class="macro">assert_eq!</span>(<span class="ident">builder</span>.<span class="ident">session_key</span>, <span class="string">&quot;rate-api&quot;</span>);
<span class="macro">assert_eq!</span>(<span class="ident">builder</span>.<span class="ident">cookie_name</span>, <span class="string">&quot;session&quot;</span>);
<span class="macro">assert_eq!</span>(builder.redis_url, redis_url);
<span class="macro">assert_eq!</span>(builder.limit, <span class="number">100</span>);
<span class="macro">assert_eq!</span>(builder.period, period);
<span class="macro">assert_eq!</span>(builder.session_key, <span class="string">&quot;rate-api&quot;</span>);
<span class="macro">assert_eq!</span>(builder.cookie_name, <span class="string">&quot;session&quot;</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_create_limiter</span>() {
<span class="kw">let</span> <span class="ident">redis_url</span> <span class="op">=</span> <span class="string">&quot;redis://127.0.0.1&quot;</span>;
<span class="kw">let</span> <span class="ident">period</span> <span class="op">=</span> <span class="ident">Duration::from_secs</span>(<span class="number">20</span>);
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">builder</span> <span class="op">=</span> <span class="ident">Builder</span> {
<span class="ident">redis_url</span>: <span class="ident">redis_url</span>.<span class="ident">to_owned</span>(),
<span class="ident">limit</span>: <span class="number">100</span>,
<span class="ident">period</span>: <span class="ident">Duration::from_secs</span>(<span class="number">10</span>),
<span class="ident">session_key</span>: <span class="ident">Cow::Borrowed</span>(<span class="string">&quot;key&quot;</span>),
<span class="ident">cookie_name</span>: <span class="ident">Cow::Borrowed</span>(<span class="string">&quot;sid&quot;</span>),
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_create_limiter() {
<span class="kw">let </span>redis_url = <span class="string">&quot;redis://127.0.0.1&quot;</span>;
<span class="kw">let </span>period = Duration::from_secs(<span class="number">20</span>);
<span class="kw">let </span><span class="kw-2">mut </span>builder = Builder {
redis_url: redis_url.to_owned(),
limit: <span class="number">100</span>,
period: Duration::from_secs(<span class="number">10</span>),
session_key: Cow::Borrowed(<span class="string">&quot;key&quot;</span>),
cookie_name: Cow::Borrowed(<span class="string">&quot;sid&quot;</span>),
};
<span class="kw">let</span> <span class="ident">limiter</span> <span class="op">=</span> <span class="ident">builder</span>
.<span class="ident">limit</span>(<span class="number">200</span>)
.<span class="ident">period</span>(<span class="ident">period</span>)
.<span class="ident">cookie_name</span>(<span class="string">&quot;session&quot;</span>.<span class="ident">to_string</span>())
.<span class="ident">session_key</span>(<span class="string">&quot;rate-api&quot;</span>.<span class="ident">to_string</span>())
.<span class="ident">build</span>()
.<span class="ident">unwrap</span>();
<span class="kw">let </span>limiter = builder
.limit(<span class="number">200</span>)
.period(period)
.cookie_name(<span class="string">&quot;session&quot;</span>.to_string())
.session_key(<span class="string">&quot;rate-api&quot;</span>.to_string())
.build()
.unwrap();
<span class="macro">assert_eq!</span>(<span class="ident">limiter</span>.<span class="ident">limit</span>, <span class="number">200</span>);
<span class="macro">assert_eq!</span>(<span class="ident">limiter</span>.<span class="ident">period</span>, <span class="ident">period</span>);
<span class="macro">assert_eq!</span>(<span class="ident">limiter</span>.<span class="ident">session_key</span>, <span class="string">&quot;rate-api&quot;</span>);
<span class="macro">assert_eq!</span>(<span class="ident">limiter</span>.<span class="ident">cookie_name</span>, <span class="string">&quot;session&quot;</span>);
<span class="macro">assert_eq!</span>(limiter.limit, <span class="number">200</span>);
<span class="macro">assert_eq!</span>(limiter.period, period);
<span class="macro">assert_eq!</span>(limiter.session_key, <span class="string">&quot;rate-api&quot;</span>);
<span class="macro">assert_eq!</span>(limiter.cookie_name, <span class="string">&quot;session&quot;</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="attribute">#[<span class="ident">should_panic</span> <span class="op">=</span> <span class="string">&quot;Redis URL did not parse&quot;</span>]</span>
<span class="kw">fn</span> <span class="ident">test_create_limiter_error</span>() {
<span class="kw">let</span> <span class="ident">redis_url</span> <span class="op">=</span> <span class="string">&quot;127.0.0.1&quot;</span>;
<span class="kw">let</span> <span class="ident">period</span> <span class="op">=</span> <span class="ident">Duration::from_secs</span>(<span class="number">20</span>);
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">builder</span> <span class="op">=</span> <span class="ident">Builder</span> {
<span class="ident">redis_url</span>: <span class="ident">redis_url</span>.<span class="ident">to_owned</span>(),
<span class="ident">limit</span>: <span class="number">100</span>,
<span class="ident">period</span>: <span class="ident">Duration::from_secs</span>(<span class="number">10</span>),
<span class="ident">session_key</span>: <span class="ident">Cow::Borrowed</span>(<span class="string">&quot;key&quot;</span>),
<span class="ident">cookie_name</span>: <span class="ident">Cow::Borrowed</span>(<span class="string">&quot;sid&quot;</span>),
<span class="attribute">#[test]
#[should_panic = <span class="string">&quot;Redis URL did not parse&quot;</span>]
</span><span class="kw">fn </span>test_create_limiter_error() {
<span class="kw">let </span>redis_url = <span class="string">&quot;127.0.0.1&quot;</span>;
<span class="kw">let </span>period = Duration::from_secs(<span class="number">20</span>);
<span class="kw">let </span><span class="kw-2">mut </span>builder = Builder {
redis_url: redis_url.to_owned(),
limit: <span class="number">100</span>,
period: Duration::from_secs(<span class="number">10</span>),
session_key: Cow::Borrowed(<span class="string">&quot;key&quot;</span>),
cookie_name: Cow::Borrowed(<span class="string">&quot;sid&quot;</span>),
};
<span class="ident">builder</span>.<span class="ident">limit</span>(<span class="number">200</span>).<span class="ident">period</span>(<span class="ident">period</span>).<span class="ident">build</span>().<span class="ident">unwrap</span>();
builder.limit(<span class="number">200</span>).period(period).build().unwrap();
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_limitation" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_limitation" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -42,47 +42,47 @@
<span id="40">40</span>
<span id="41">41</span>
<span id="42">42</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">derive_more</span>::{<span class="ident">Display</span>, <span class="ident">Error</span>, <span class="ident">From</span>};
</pre><pre class="rust"><code><span class="kw">use </span>derive_more::{Display, Error, From};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::status::Status</span>;
<span class="kw">use </span><span class="kw">crate</span>::status::Status;
<span class="doccomment">/// Failure modes of the rate limiter.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Display</span>, <span class="ident">Error</span>, <span class="ident">From</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">Error</span> {
<span class="doccomment">/// Redis client failed to connect or run a query.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Redis client failed to connect or run a query&quot;</span>)]</span>
<span class="ident">Client</span>(<span class="ident">redis::RedisError</span>),
<span class="doccomment">/// Failure modes of the rate limiter.
</span><span class="attribute">#[derive(Debug, Display, Error, From)]
</span><span class="kw">pub enum </span>Error {
<span class="doccomment">/// Redis client failed to connect or run a query.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Redis client failed to connect or run a query&quot;</span>)]
</span>Client(redis::RedisError),
<span class="doccomment">/// Limit is exceeded for a key.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Limit is exceeded for a key&quot;</span>)]</span>
<span class="attribute">#[<span class="ident">from</span>(<span class="ident">ignore</span>)]</span>
<span class="ident">LimitExceeded</span>(<span class="attribute">#[<span class="ident">error</span>(<span class="ident">not</span>(<span class="ident">source</span>))]</span> <span class="ident">Status</span>),
<span class="doccomment">/// Limit is exceeded for a key.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Limit is exceeded for a key&quot;</span>)]
#[from(ignore)]
</span>LimitExceeded(<span class="attribute">#[error(not(source))] </span>Status),
<span class="doccomment">/// Time conversion failed.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Time conversion failed&quot;</span>)]</span>
<span class="ident">Time</span>(<span class="ident">time::error::ComponentRange</span>),
<span class="doccomment">/// Time conversion failed.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Time conversion failed&quot;</span>)]
</span>Time(time::error::ComponentRange),
<span class="doccomment">/// Generic error.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Generic error&quot;</span>)]</span>
<span class="attribute">#[<span class="ident">from</span>(<span class="ident">ignore</span>)]</span>
<span class="ident">Other</span>(<span class="attribute">#[<span class="ident">error</span>(<span class="ident">not</span>(<span class="ident">source</span>))]</span> <span class="ident">String</span>),
<span class="doccomment">/// Generic error.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Generic error&quot;</span>)]
#[from(ignore)]
</span>Other(<span class="attribute">#[error(not(source))] </span>String),
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="macro">static_assertions::assert_impl_all!</span> {
<span class="ident">Error</span>:
<span class="ident">From</span><span class="op">&lt;</span><span class="ident">redis::RedisError</span><span class="op">&gt;</span>,
<span class="ident">From</span><span class="op">&lt;</span><span class="ident">time::error::ComponentRange</span><span class="op">&gt;</span>,
<span class="macro">static_assertions::assert_impl_all! </span>{
Error:
From&lt;redis::RedisError&gt;,
From&lt;time::error::ComponentRange&gt;,
}
<span class="macro">static_assertions::assert_not_impl_any!</span> {
<span class="ident">Error</span>:
<span class="ident">From</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>,
<span class="ident">From</span><span class="op">&lt;</span><span class="ident">Status</span><span class="op">&gt;</span>,
<span class="macro">static_assertions::assert_not_impl_any! </span>{
Error:
From&lt;String&gt;,
From&lt;Status&gt;,
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_limitation" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_limitation" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -159,164 +159,164 @@
<span id="157">157</span>
<span id="158">158</span>
<span id="159">159</span>
</pre><pre class="rust"><code><span class="doccomment">//! Rate limiter using a fixed window counter for arbitrary keys, backed by Redis for Actix Web.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! ```toml</span>
<span class="doccomment">//! [dependencies]</span>
<span class="doccomment">//! actix-web = &quot;4&quot;</span>
<span class="attribute">#![<span class="ident">doc</span> <span class="op">=</span> <span class="macro">concat!</span>(<span class="string">&quot;actix-limitation = \&quot;&quot;</span>, <span class="macro">env!</span>(<span class="string">&quot;CARGO_PKG_VERSION_MAJOR&quot;</span>), <span class="string">&quot;.&quot;</span>, <span class="macro">env!</span>(<span class="string">&quot;CARGO_PKG_VERSION_MINOR&quot;</span>),<span class="string">&quot;\&quot;&quot;</span>)]</span>
<span class="doccomment">//! ```</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! ```no_run</span>
<span class="doccomment">//! use std::time::Duration;</span>
<span class="doccomment">//! use actix_web::{get, web, App, HttpServer, Responder};</span>
<span class="doccomment">//! use actix_limitation::{Limiter, RateLimiter};</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! #[get(&quot;/{id}/{name}&quot;)]</span>
<span class="doccomment">//! async fn index(info: web::Path&lt;(u32, String)&gt;) -&gt; impl Responder {</span>
<span class="doccomment">//! format!(&quot;Hello {}! id:{}&quot;, info.1, info.0)</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! #[actix_web::main]</span>
<span class="doccomment">//! async fn main() -&gt; std::io::Result&lt;()&gt; {</span>
<span class="doccomment">//! let limiter = web::Data::new(</span>
<span class="doccomment">//! Limiter::builder(&quot;redis://127.0.0.1&quot;)</span>
<span class="doccomment">//! .cookie_name(&quot;session-id&quot;.to_owned())</span>
<span class="doccomment">//! .session_key(&quot;rate-api-id&quot;.to_owned())</span>
<span class="doccomment">//! .limit(5000)</span>
<span class="doccomment">//! .period(Duration::from_secs(3600)) // 60 minutes</span>
<span class="doccomment">//! .build()</span>
<span class="doccomment">//! .unwrap(),</span>
<span class="doccomment">//! );</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! HttpServer::new(move || {</span>
<span class="doccomment">//! App::new()</span>
<span class="doccomment">//! .wrap(RateLimiter::default())</span>
<span class="doccomment">//! .app_data(limiter.clone())</span>
<span class="doccomment">//! .service(index)</span>
<span class="doccomment">//! })</span>
<span class="doccomment">//! .bind((&quot;127.0.0.1&quot;, 8080))?</span>
<span class="doccomment">//! .run()</span>
<span class="doccomment">//! .await</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//! ```</span>
</pre><pre class="rust"><code><span class="doccomment">//! Rate limiter using a fixed window counter for arbitrary keys, backed by Redis for Actix Web.
//!
//! ```toml
//! [dependencies]
//! actix-web = &quot;4&quot;
</span><span class="attribute">#![doc = <span class="macro">concat!</span>(<span class="string">&quot;actix-limitation = \&quot;&quot;</span>, <span class="macro">env!</span>(<span class="string">&quot;CARGO_PKG_VERSION_MAJOR&quot;</span>), <span class="string">&quot;.&quot;</span>, <span class="macro">env!</span>(<span class="string">&quot;CARGO_PKG_VERSION_MINOR&quot;</span>),<span class="string">&quot;\&quot;&quot;</span>)]
</span><span class="doccomment">//! ```
//!
//! ```no_run
//! use std::time::Duration;
//! use actix_web::{get, web, App, HttpServer, Responder};
//! use actix_limitation::{Limiter, RateLimiter};
//!
//! #[get(&quot;/{id}/{name}&quot;)]
//! async fn index(info: web::Path&lt;(u32, String)&gt;) -&gt; impl Responder {
//! format!(&quot;Hello {}! id:{}&quot;, info.1, info.0)
//! }
//!
//! #[actix_web::main]
//! async fn main() -&gt; std::io::Result&lt;()&gt; {
//! let limiter = web::Data::new(
//! Limiter::builder(&quot;redis://127.0.0.1&quot;)
//! .cookie_name(&quot;session-id&quot;.to_owned())
//! .session_key(&quot;rate-api-id&quot;.to_owned())
//! .limit(5000)
//! .period(Duration::from_secs(3600)) // 60 minutes
//! .build()
//! .unwrap(),
//! );
//!
//! HttpServer::new(move || {
//! App::new()
//! .wrap(RateLimiter::default())
//! .app_data(limiter.clone())
//! .service(index)
//! })
//! .bind((&quot;127.0.0.1&quot;, 8080))?
//! .run()
//! .await
//! }
//! ```
<span class="attribute">#![<span class="ident">forbid</span>(<span class="ident">unsafe_code</span>)]</span>
<span class="attribute">#![<span class="ident">deny</span>(<span class="ident">rust_2018_idioms</span>, <span class="ident">nonstandard_style</span>)]</span>
<span class="attribute">#![<span class="ident">warn</span>(<span class="ident">future_incompatible</span>, <span class="ident">missing_docs</span>, <span class="ident">missing_debug_implementations</span>)]</span>
<span class="attribute">#![<span class="ident">doc</span>(<span class="ident">html_logo_url</span> <span class="op">=</span> <span class="string">&quot;https://actix.rs/img/logo.png&quot;</span>)]</span>
<span class="attribute">#![<span class="ident">doc</span>(<span class="ident">html_favicon_url</span> <span class="op">=</span> <span class="string">&quot;https://actix.rs/favicon.ico&quot;</span>)]</span>
</span><span class="attribute">#![forbid(unsafe_code)]
#![deny(rust_2018_idioms, nonstandard_style)]
#![warn(future_incompatible, missing_docs, missing_debug_implementations)]
#![doc(html_logo_url = <span class="string">&quot;https://actix.rs/img/logo.png&quot;</span>)]
#![doc(html_favicon_url = <span class="string">&quot;https://actix.rs/favicon.ico&quot;</span>)]
<span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">borrow::Cow</span>, <span class="ident">time::Duration</span>};
</span><span class="kw">use </span>std::{borrow::Cow, time::Duration};
<span class="kw">use</span> <span class="ident">redis::Client</span>;
<span class="kw">use </span>redis::Client;
<span class="kw">mod</span> <span class="ident">builder</span>;
<span class="kw">mod</span> <span class="ident">errors</span>;
<span class="kw">mod</span> <span class="ident">middleware</span>;
<span class="kw">mod</span> <span class="ident">status</span>;
<span class="kw">mod </span>builder;
<span class="kw">mod </span>errors;
<span class="kw">mod </span>middleware;
<span class="kw">mod </span>status;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::builder::Builder</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::errors::Error</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::middleware::RateLimiter</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::status::Status</span>;
<span class="kw">pub use </span><span class="self">self</span>::builder::Builder;
<span class="kw">pub use </span><span class="self">self</span>::errors::Error;
<span class="kw">pub use </span><span class="self">self</span>::middleware::RateLimiter;
<span class="kw">pub use </span><span class="self">self</span>::status::Status;
<span class="doccomment">/// Default request limit.</span>
<span class="kw">pub</span> <span class="kw">const</span> <span class="ident">DEFAULT_REQUEST_LIMIT</span>: <span class="ident">usize</span> <span class="op">=</span> <span class="number">5000</span>;
<span class="doccomment">/// Default request limit.
</span><span class="kw">pub const </span>DEFAULT_REQUEST_LIMIT: usize = <span class="number">5000</span>;
<span class="doccomment">/// Default period (in seconds).</span>
<span class="kw">pub</span> <span class="kw">const</span> <span class="ident">DEFAULT_PERIOD_SECS</span>: <span class="ident">u64</span> <span class="op">=</span> <span class="number">3600</span>;
<span class="doccomment">/// Default period (in seconds).
</span><span class="kw">pub const </span>DEFAULT_PERIOD_SECS: u64 = <span class="number">3600</span>;
<span class="doccomment">/// Default cookie name.</span>
<span class="kw">pub</span> <span class="kw">const</span> <span class="ident">DEFAULT_COOKIE_NAME</span>: <span class="kw-2">&amp;</span><span class="ident">str</span> <span class="op">=</span> <span class="string">&quot;sid&quot;</span>;
<span class="doccomment">/// Default cookie name.
</span><span class="kw">pub const </span>DEFAULT_COOKIE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">&quot;sid&quot;</span>;
<span class="doccomment">/// Default session key.</span>
<span class="kw">pub</span> <span class="kw">const</span> <span class="ident">DEFAULT_SESSION_KEY</span>: <span class="kw-2">&amp;</span><span class="ident">str</span> <span class="op">=</span> <span class="string">&quot;rate-api-id&quot;</span>;
<span class="doccomment">/// Default session key.
</span><span class="kw">pub const </span>DEFAULT_SESSION_KEY: <span class="kw-2">&amp;</span>str = <span class="string">&quot;rate-api-id&quot;</span>;
<span class="doccomment">/// Rate limiter.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Limiter</span> {
<span class="ident">client</span>: <span class="ident">Client</span>,
<span class="ident">limit</span>: <span class="ident">usize</span>,
<span class="ident">period</span>: <span class="ident">Duration</span>,
<span class="ident">cookie_name</span>: <span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span>,
<span class="ident">session_key</span>: <span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span>,
<span class="doccomment">/// Rate limiter.
</span><span class="attribute">#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>Limiter {
client: Client,
limit: usize,
period: Duration,
cookie_name: Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;,
session_key: Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;,
}
<span class="kw">impl</span> <span class="ident">Limiter</span> {
<span class="doccomment">/// Construct rate limiter builder with defaults.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// See [`redis-rs` docs](https://docs.rs/redis/0.21/redis/#connection-parameters) on connection</span>
<span class="doccomment">/// parameters for how to set the Redis URL.</span>
<span class="attribute">#[<span class="ident">must_use</span>]</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">builder</span>(<span class="ident">redis_url</span>: <span class="kw">impl</span> <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>) -&gt; <span class="ident">Builder</span> {
<span class="ident">Builder</span> {
<span class="ident">redis_url</span>: <span class="ident">redis_url</span>.<span class="ident">into</span>(),
<span class="ident">limit</span>: <span class="ident">DEFAULT_REQUEST_LIMIT</span>,
<span class="ident">period</span>: <span class="ident">Duration::from_secs</span>(<span class="ident">DEFAULT_PERIOD_SECS</span>),
<span class="ident">cookie_name</span>: <span class="ident">Cow::Borrowed</span>(<span class="ident">DEFAULT_COOKIE_NAME</span>),
<span class="ident">session_key</span>: <span class="ident">Cow::Borrowed</span>(<span class="ident">DEFAULT_SESSION_KEY</span>),
<span class="kw">impl </span>Limiter {
<span class="doccomment">/// Construct rate limiter builder with defaults.
///
/// See [`redis-rs` docs](https://docs.rs/redis/0.21/redis/#connection-parameters) on connection
/// parameters for how to set the Redis URL.
</span><span class="attribute">#[must_use]
</span><span class="kw">pub fn </span>builder(redis_url: <span class="kw">impl </span>Into&lt;String&gt;) -&gt; Builder {
Builder {
redis_url: redis_url.into(),
limit: DEFAULT_REQUEST_LIMIT,
period: Duration::from_secs(DEFAULT_PERIOD_SECS),
cookie_name: Cow::Borrowed(DEFAULT_COOKIE_NAME),
session_key: Cow::Borrowed(DEFAULT_SESSION_KEY),
}
}
<span class="doccomment">/// Consumes one rate limit unit, returning the status.</span>
<span class="kw">pub</span> <span class="kw">async</span> <span class="kw">fn</span> <span class="ident">count</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">key</span>: <span class="kw">impl</span> <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">Status</span>, <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> (<span class="ident">count</span>, <span class="ident">reset</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">track</span>(<span class="ident">key</span>).<span class="kw">await</span><span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">status</span> <span class="op">=</span> <span class="ident">Status::new</span>(<span class="ident">count</span>, <span class="self">self</span>.<span class="ident">limit</span>, <span class="ident">reset</span>);
<span class="doccomment">/// Consumes one rate limit unit, returning the status.
</span><span class="kw">pub async fn </span>count(<span class="kw-2">&amp;</span><span class="self">self</span>, key: <span class="kw">impl </span>Into&lt;String&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;Status, Error&gt; {
<span class="kw">let </span>(count, reset) = <span class="self">self</span>.track(key).<span class="kw">await</span><span class="question-mark">?</span>;
<span class="kw">let </span>status = Status::new(count, <span class="self">self</span>.limit, reset);
<span class="kw">if</span> <span class="ident">count</span> <span class="op">&gt;</span> <span class="self">self</span>.<span class="ident">limit</span> {
<span class="prelude-val">Err</span>(<span class="ident">Error::LimitExceeded</span>(<span class="ident">status</span>))
} <span class="kw">else</span> {
<span class="prelude-val">Ok</span>(<span class="ident">status</span>)
<span class="kw">if </span>count &gt; <span class="self">self</span>.limit {
<span class="prelude-val">Err</span>(Error::LimitExceeded(status))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(status)
}
}
<span class="doccomment">/// Tracks the given key in a period and returns the count and TTL for the key in seconds.</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">track</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">key</span>: <span class="kw">impl</span> <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(<span class="ident">usize</span>, <span class="ident">usize</span>), <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">key</span> <span class="op">=</span> <span class="ident">key</span>.<span class="ident">into</span>();
<span class="kw">let</span> <span class="ident">expires</span> <span class="op">=</span> <span class="self">self</span>.<span class="ident">period</span>.<span class="ident">as_secs</span>();
<span class="doccomment">/// Tracks the given key in a period and returns the count and TTL for the key in seconds.
</span><span class="kw">async fn </span>track(<span class="kw-2">&amp;</span><span class="self">self</span>, key: <span class="kw">impl </span>Into&lt;String&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;(usize, usize), Error&gt; {
<span class="kw">let </span>key = key.into();
<span class="kw">let </span>expires = <span class="self">self</span>.period.as_secs();
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">connection</span> <span class="op">=</span> <span class="self">self</span>.<span class="ident">client</span>.<span class="ident">get_tokio_connection</span>().<span class="kw">await</span><span class="question-mark">?</span>;
<span class="kw">let </span><span class="kw-2">mut </span>connection = <span class="self">self</span>.client.get_tokio_connection().<span class="kw">await</span><span class="question-mark">?</span>;
<span class="comment">// The seed of this approach is outlined Atul R in a blog post about rate limiting using</span>
<span class="comment">// NodeJS and Redis. For more details, see https://blog.atulr.com/rate-limiter</span>
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">pipe</span> <span class="op">=</span> <span class="ident">redis::pipe</span>();
<span class="ident">pipe</span>.<span class="ident">atomic</span>()
.<span class="ident">cmd</span>(<span class="string">&quot;SET&quot;</span>) <span class="comment">// Set key and value</span>
.<span class="ident">arg</span>(<span class="kw-2">&amp;</span><span class="ident">key</span>)
.<span class="ident">arg</span>(<span class="number">0</span>)
.<span class="ident">arg</span>(<span class="string">&quot;EX&quot;</span>) <span class="comment">// Set the specified expire time, in seconds.</span>
.<span class="ident">arg</span>(<span class="ident">expires</span>)
.<span class="ident">arg</span>(<span class="string">&quot;NX&quot;</span>) <span class="comment">// Only set the key if it does not already exist.</span>
.<span class="ident">ignore</span>() <span class="comment">// --- ignore returned value of SET command ---</span>
.<span class="ident">cmd</span>(<span class="string">&quot;INCR&quot;</span>) <span class="comment">// Increment key</span>
.<span class="ident">arg</span>(<span class="kw-2">&amp;</span><span class="ident">key</span>)
.<span class="ident">cmd</span>(<span class="string">&quot;TTL&quot;</span>) <span class="comment">// Return time-to-live of key</span>
.<span class="ident">arg</span>(<span class="kw-2">&amp;</span><span class="ident">key</span>);
<span class="comment">// The seed of this approach is outlined Atul R in a blog post about rate limiting using
// NodeJS and Redis. For more details, see https://blog.atulr.com/rate-limiter
</span><span class="kw">let </span><span class="kw-2">mut </span>pipe = redis::pipe();
pipe.atomic()
.cmd(<span class="string">&quot;SET&quot;</span>) <span class="comment">// Set key and value
</span>.arg(<span class="kw-2">&amp;</span>key)
.arg(<span class="number">0</span>)
.arg(<span class="string">&quot;EX&quot;</span>) <span class="comment">// Set the specified expire time, in seconds.
</span>.arg(expires)
.arg(<span class="string">&quot;NX&quot;</span>) <span class="comment">// Only set the key if it does not already exist.
</span>.ignore() <span class="comment">// --- ignore returned value of SET command ---
</span>.cmd(<span class="string">&quot;INCR&quot;</span>) <span class="comment">// Increment key
</span>.arg(<span class="kw-2">&amp;</span>key)
.cmd(<span class="string">&quot;TTL&quot;</span>) <span class="comment">// Return time-to-live of key
</span>.arg(<span class="kw-2">&amp;</span>key);
<span class="kw">let</span> (<span class="ident">count</span>, <span class="ident">ttl</span>) <span class="op">=</span> <span class="ident">pipe</span>.<span class="ident">query_async</span>(<span class="kw-2">&amp;mut</span> <span class="ident">connection</span>).<span class="kw">await</span><span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">reset</span> <span class="op">=</span> <span class="ident">Status::epoch_utc_plus</span>(<span class="ident">Duration::from_secs</span>(<span class="ident">ttl</span>))<span class="question-mark">?</span>;
<span class="kw">let </span>(count, ttl) = pipe.query_async(<span class="kw-2">&amp;mut </span>connection).<span class="kw">await</span><span class="question-mark">?</span>;
<span class="kw">let </span>reset = Status::epoch_utc_plus(Duration::from_secs(ttl))<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>((<span class="ident">count</span>, <span class="ident">reset</span>))
<span class="prelude-val">Ok</span>((count, reset))
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_create_limiter</span>() {
<span class="kw">let</span> <span class="ident">builder</span> <span class="op">=</span> <span class="ident">Limiter::builder</span>(<span class="string">&quot;redis://127.0.0.1:6379/1&quot;</span>);
<span class="kw">let</span> <span class="ident">limiter</span> <span class="op">=</span> <span class="ident">builder</span>.<span class="ident">build</span>();
<span class="macro">assert!</span>(<span class="ident">limiter</span>.<span class="ident">is_ok</span>());
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_create_limiter() {
<span class="kw">let </span>builder = Limiter::builder(<span class="string">&quot;redis://127.0.0.1:6379/1&quot;</span>);
<span class="kw">let </span>limiter = builder.build();
<span class="macro">assert!</span>(limiter.is_ok());
<span class="kw">let</span> <span class="ident">limiter</span> <span class="op">=</span> <span class="ident">limiter</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">limiter</span>.<span class="ident">limit</span>, <span class="number">5000</span>);
<span class="macro">assert_eq!</span>(<span class="ident">limiter</span>.<span class="ident">period</span>, <span class="ident">Duration::from_secs</span>(<span class="number">3600</span>));
<span class="macro">assert_eq!</span>(<span class="ident">limiter</span>.<span class="ident">cookie_name</span>, <span class="ident">DEFAULT_COOKIE_NAME</span>);
<span class="macro">assert_eq!</span>(<span class="ident">limiter</span>.<span class="ident">session_key</span>, <span class="ident">DEFAULT_SESSION_KEY</span>);
<span class="kw">let </span>limiter = limiter.unwrap();
<span class="macro">assert_eq!</span>(limiter.limit, <span class="number">5000</span>);
<span class="macro">assert_eq!</span>(limiter.period, Duration::from_secs(<span class="number">3600</span>));
<span class="macro">assert_eq!</span>(limiter.cookie_name, DEFAULT_COOKIE_NAME);
<span class="macro">assert_eq!</span>(limiter.session_key, DEFAULT_SESSION_KEY);
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_limitation" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_limitation" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -103,108 +103,108 @@
<span id="101">101</span>
<span id="102">102</span>
<span id="103">103</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">future::Future</span>, <span class="ident">pin::Pin</span>, <span class="ident">rc::Rc</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{future::Future, pin::Pin, rc::Rc};
<span class="kw">use</span> <span class="ident">actix_session::SessionExt</span> <span class="kw">as</span> <span class="kw">_</span>;
<span class="kw">use</span> <span class="ident">actix_utils::future</span>::{<span class="ident">ok</span>, <span class="ident">Ready</span>};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">body::EitherBody</span>,
<span class="ident">dev</span>::{<span class="ident">forward_ready</span>, <span class="ident">Service</span>, <span class="ident">ServiceRequest</span>, <span class="ident">ServiceResponse</span>, <span class="ident">Transform</span>},
<span class="ident">http::StatusCode</span>,
<span class="ident">web</span>, <span class="ident">Error</span>, <span class="ident">HttpResponse</span>,
<span class="kw">use </span>actix_session::SessionExt <span class="kw">as _</span>;
<span class="kw">use </span>actix_utils::future::{ok, Ready};
<span class="kw">use </span>actix_web::{
body::EitherBody,
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
http::StatusCode,
web, Error, HttpResponse,
};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::Limiter</span>;
<span class="kw">use </span><span class="kw">crate</span>::Limiter;
<span class="doccomment">/// Rate limit middleware.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Default</span>)]</span>
<span class="attribute">#[<span class="ident">non_exhaustive</span>]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">RateLimiter</span>;
<span class="doccomment">/// Rate limit middleware.
</span><span class="attribute">#[derive(Debug, Default)]
#[non_exhaustive]
</span><span class="kw">pub struct </span>RateLimiter;
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">B</span><span class="op">&gt;</span> <span class="ident">Transform</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">ServiceRequest</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">RateLimiter</span>
<span class="kw">where</span>
<span class="ident">S</span>: <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>, <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span><span class="op">&gt;</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">S::Future</span>: <span class="lifetime">&#39;static</span>,
<span class="ident">B</span>: <span class="lifetime">&#39;static</span>,
<span class="kw">impl</span>&lt;S, B&gt; Transform&lt;S, ServiceRequest&gt; <span class="kw">for </span>RateLimiter
<span class="kw">where
</span>S: Service&lt;ServiceRequest, Response = ServiceResponse&lt;B&gt;, Error = Error&gt; + <span class="lifetime">&#39;static</span>,
S::Future: <span class="lifetime">&#39;static</span>,
B: <span class="lifetime">&#39;static</span>,
{
<span class="kw">type</span> <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">EitherBody</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span>;
<span class="kw">type</span> <span class="ident">Transform</span> <span class="op">=</span> <span class="ident">RateLimiterMiddleware</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">InitError</span> <span class="op">=</span> ();
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">Ready</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Transform</span>, <span class="ident"><span class="self">Self</span>::InitError</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type </span>Response = ServiceResponse&lt;EitherBody&lt;B&gt;&gt;;
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Transform = RateLimiterMiddleware&lt;S&gt;;
<span class="kw">type </span>InitError = ();
<span class="kw">type </span>Future = Ready&lt;<span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Transform, <span class="self">Self</span>::InitError&gt;&gt;;
<span class="kw">fn</span> <span class="ident">new_transform</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">service</span>: <span class="ident">S</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="ident">ok</span>(<span class="ident">RateLimiterMiddleware</span> {
<span class="ident">service</span>: <span class="ident">Rc::new</span>(<span class="ident">service</span>),
<span class="kw">fn </span>new_transform(<span class="kw-2">&amp;</span><span class="self">self</span>, service: S) -&gt; <span class="self">Self</span>::Future {
ok(RateLimiterMiddleware {
service: Rc::new(service),
})
}
}
<span class="doccomment">/// Rate limit middleware service.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">RateLimiterMiddleware</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="ident">service</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span>,
<span class="doccomment">/// Rate limit middleware service.
</span><span class="attribute">#[derive(Debug)]
</span><span class="kw">pub struct </span>RateLimiterMiddleware&lt;S&gt; {
service: Rc&lt;S&gt;,
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">B</span><span class="op">&gt;</span> <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">RateLimiterMiddleware</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">S</span>: <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>, <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span><span class="op">&gt;</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">S::Future</span>: <span class="lifetime">&#39;static</span>,
<span class="ident">B</span>: <span class="lifetime">&#39;static</span>,
<span class="kw">impl</span>&lt;S, B&gt; Service&lt;ServiceRequest&gt; <span class="kw">for </span>RateLimiterMiddleware&lt;S&gt;
<span class="kw">where
</span>S: Service&lt;ServiceRequest, Response = ServiceResponse&lt;B&gt;, Error = Error&gt; + <span class="lifetime">&#39;static</span>,
S::Future: <span class="lifetime">&#39;static</span>,
B: <span class="lifetime">&#39;static</span>,
{
<span class="kw">type</span> <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">EitherBody</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span>;
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">Pin</span><span class="op">&lt;</span><span class="ident">Box</span><span class="op">&lt;</span><span class="kw">dyn</span> <span class="ident">Future</span><span class="op">&lt;</span><span class="ident">Output</span> <span class="op">=</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Response</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type </span>Response = ServiceResponse&lt;EitherBody&lt;B&gt;&gt;;
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Future = Pin&lt;Box&lt;<span class="kw">dyn </span>Future&lt;Output = <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Response, <span class="self">Self</span>::Error&gt;&gt;&gt;&gt;;
<span class="macro">forward_ready!</span>(<span class="ident">service</span>);
<span class="macro">forward_ready!</span>(service);
<span class="kw">fn</span> <span class="ident">call</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">req</span>: <span class="ident">ServiceRequest</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="comment">// A mis-configuration of the Actix App will result in a **runtime** failure, so the expect</span>
<span class="comment">// method description is important context for the developer.</span>
<span class="kw">let</span> <span class="ident">limiter</span> <span class="op">=</span> <span class="ident">req</span>
.<span class="ident">app_data</span>::<span class="op">&lt;</span><span class="ident">web::Data</span><span class="op">&lt;</span><span class="ident">Limiter</span><span class="op">&gt;</span><span class="op">&gt;</span>()
.<span class="ident">expect</span>(<span class="string">&quot;web::Data&lt;Limiter&gt; should be set in app data for RateLimiter middleware&quot;</span>)
.<span class="ident">clone</span>();
<span class="kw">fn </span>call(<span class="kw-2">&amp;</span><span class="self">self</span>, req: ServiceRequest) -&gt; <span class="self">Self</span>::Future {
<span class="comment">// A mis-configuration of the Actix App will result in a **runtime** failure, so the expect
// method description is important context for the developer.
</span><span class="kw">let </span>limiter = req
.app_data::&lt;web::Data&lt;Limiter&gt;&gt;()
.expect(<span class="string">&quot;web::Data&lt;Limiter&gt; should be set in app data for RateLimiter middleware&quot;</span>)
.clone();
<span class="kw">let</span> <span class="ident">key</span> <span class="op">=</span> <span class="ident">req</span>.<span class="ident">get_session</span>().<span class="ident">get</span>(<span class="kw-2">&amp;</span><span class="ident">limiter</span>.<span class="ident">session_key</span>).<span class="ident">unwrap_or</span>(<span class="prelude-val">None</span>);
<span class="kw">let</span> <span class="ident">service</span> <span class="op">=</span> <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">service</span>);
<span class="kw">let </span>key = req.get_session().get(<span class="kw-2">&amp;</span>limiter.session_key).unwrap_or(<span class="prelude-val">None</span>);
<span class="kw">let </span>service = Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.service);
<span class="kw">let</span> <span class="ident">key</span> <span class="op">=</span> <span class="kw">match</span> <span class="ident">key</span> {
<span class="prelude-val">Some</span>(<span class="ident">key</span>) =&gt; <span class="ident">key</span>,
<span class="prelude-val">None</span> =&gt; {
<span class="kw">let</span> <span class="ident">fallback</span> <span class="op">=</span> <span class="ident">req</span>.<span class="ident">cookie</span>(<span class="kw-2">&amp;</span><span class="ident">limiter</span>.<span class="ident">cookie_name</span>).<span class="ident">map</span>(<span class="op">|</span><span class="ident">c</span><span class="op">|</span> <span class="ident">c</span>.<span class="ident">to_string</span>());
<span class="kw">let </span>key = <span class="kw">match </span>key {
<span class="prelude-val">Some</span>(key) =&gt; key,
<span class="prelude-val">None </span>=&gt; {
<span class="kw">let </span>fallback = req.cookie(<span class="kw-2">&amp;</span>limiter.cookie_name).map(|c| c.to_string());
<span class="kw">match</span> <span class="ident">fallback</span> {
<span class="prelude-val">Some</span>(<span class="ident">key</span>) =&gt; <span class="ident">key</span>,
<span class="prelude-val">None</span> =&gt; {
<span class="kw">return</span> <span class="ident">Box::pin</span>(<span class="kw">async</span> <span class="kw">move</span> {
<span class="ident">service</span>
.<span class="ident">call</span>(<span class="ident">req</span>)
.<span class="kw">await</span>
.<span class="ident">map</span>(<span class="ident">ServiceResponse::map_into_left_body</span>)
<span class="kw">match </span>fallback {
<span class="prelude-val">Some</span>(key) =&gt; key,
<span class="prelude-val">None </span>=&gt; {
<span class="kw">return </span>Box::pin(<span class="kw">async move </span>{
service
.call(req)
.<span class="kw">await
</span>.map(ServiceResponse::map_into_left_body)
});
}
}
}
};
<span class="ident">Box::pin</span>(<span class="kw">async</span> <span class="kw">move</span> {
<span class="kw">let</span> <span class="ident">status</span> <span class="op">=</span> <span class="ident">limiter</span>.<span class="ident">count</span>(<span class="ident">key</span>.<span class="ident">to_string</span>()).<span class="kw">await</span>;
Box::pin(<span class="kw">async move </span>{
<span class="kw">let </span>status = limiter.count(key.to_string()).<span class="kw">await</span>;
<span class="kw">if</span> <span class="ident">status</span>.<span class="ident">is_err</span>() {
<span class="macro">log::warn!</span>(<span class="string">&quot;Rate limit exceed error for {}&quot;</span>, <span class="ident">key</span>);
<span class="kw">if </span>status.is_err() {
<span class="macro">log::warn!</span>(<span class="string">&quot;Rate limit exceed error for {}&quot;</span>, key);
<span class="prelude-val">Ok</span>(<span class="ident">req</span>.<span class="ident">into_response</span>(
<span class="ident">HttpResponse::new</span>(<span class="ident">StatusCode::TOO_MANY_REQUESTS</span>).<span class="ident">map_into_right_body</span>(),
<span class="prelude-val">Ok</span>(req.into_response(
HttpResponse::new(StatusCode::TOO_MANY_REQUESTS).map_into_right_body(),
))
} <span class="kw">else</span> {
<span class="ident">service</span>
.<span class="ident">call</span>(<span class="ident">req</span>)
.<span class="kw">await</span>
.<span class="ident">map</span>(<span class="ident">ServiceResponse::map_into_left_body</span>)
} <span class="kw">else </span>{
service
.call(req)
.<span class="kw">await
</span>.map(ServiceResponse::map_into_left_body)
}
})
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_limitation" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_limitation" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -118,123 +118,123 @@
<span id="116">116</span>
<span id="117">117</span>
<span id="118">118</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">convert::TryInto</span>, <span class="ident">ops::Add</span>, <span class="ident">time::Duration</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{convert::TryInto, ops::Add, time::Duration};
<span class="kw">use</span> <span class="ident">chrono::SubsecRound</span> <span class="kw">as</span> <span class="kw">_</span>;
<span class="kw">use </span>chrono::SubsecRound <span class="kw">as _</span>;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::Error</span> <span class="kw">as</span> <span class="ident">LimitationError</span>;
<span class="kw">use </span><span class="kw">crate</span>::Error <span class="kw">as </span>LimitationError;
<span class="doccomment">/// A report for a given key containing the limit status.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Status</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">limit</span>: <span class="ident">usize</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">remaining</span>: <span class="ident">usize</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">reset_epoch_utc</span>: <span class="ident">usize</span>,
<span class="doccomment">/// A report for a given key containing the limit status.
</span><span class="attribute">#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>Status {
<span class="kw">pub</span>(<span class="kw">crate</span>) limit: usize,
<span class="kw">pub</span>(<span class="kw">crate</span>) remaining: usize,
<span class="kw">pub</span>(<span class="kw">crate</span>) reset_epoch_utc: usize,
}
<span class="kw">impl</span> <span class="ident">Status</span> {
<span class="doccomment">/// Constructs status limit status from parts.</span>
<span class="attribute">#[<span class="ident">must_use</span>]</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">new</span>(<span class="ident">count</span>: <span class="ident">usize</span>, <span class="ident">limit</span>: <span class="ident">usize</span>, <span class="ident">reset_epoch_utc</span>: <span class="ident">usize</span>) -&gt; <span class="self">Self</span> {
<span class="kw">let</span> <span class="ident">remaining</span> <span class="op">=</span> <span class="kw">if</span> <span class="ident">count</span> <span class="op">&gt;</span><span class="op">=</span> <span class="ident">limit</span> { <span class="number">0</span> } <span class="kw">else</span> { <span class="ident">limit</span> <span class="op">-</span> <span class="ident">count</span> };
<span class="kw">impl </span>Status {
<span class="doccomment">/// Constructs status limit status from parts.
</span><span class="attribute">#[must_use]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new(count: usize, limit: usize, reset_epoch_utc: usize) -&gt; <span class="self">Self </span>{
<span class="kw">let </span>remaining = <span class="kw">if </span>count &gt;= limit { <span class="number">0 </span>} <span class="kw">else </span>{ limit - count };
<span class="ident">Status</span> {
<span class="ident">limit</span>,
<span class="ident">remaining</span>,
<span class="ident">reset_epoch_utc</span>,
Status {
limit,
remaining,
reset_epoch_utc,
}
}
<span class="doccomment">/// Returns the maximum number of requests allowed in the current period.</span>
<span class="attribute">#[<span class="ident">must_use</span>]</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">limit</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">usize</span> {
<span class="self">self</span>.<span class="ident">limit</span>
<span class="doccomment">/// Returns the maximum number of requests allowed in the current period.
</span><span class="attribute">#[must_use]
</span><span class="kw">pub fn </span>limit(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<span class="self">self</span>.limit
}
<span class="doccomment">/// Returns how many requests are left in the current period.</span>
<span class="attribute">#[<span class="ident">must_use</span>]</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">remaining</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">usize</span> {
<span class="self">self</span>.<span class="ident">remaining</span>
<span class="doccomment">/// Returns how many requests are left in the current period.
</span><span class="attribute">#[must_use]
</span><span class="kw">pub fn </span>remaining(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<span class="self">self</span>.remaining
}
<span class="doccomment">/// Returns a UNIX timestamp in UTC approximately when the next period will begin.</span>
<span class="attribute">#[<span class="ident">must_use</span>]</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">reset_epoch_utc</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">usize</span> {
<span class="self">self</span>.<span class="ident">reset_epoch_utc</span>
<span class="doccomment">/// Returns a UNIX timestamp in UTC approximately when the next period will begin.
</span><span class="attribute">#[must_use]
</span><span class="kw">pub fn </span>reset_epoch_utc(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<span class="self">self</span>.reset_epoch_utc
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">epoch_utc_plus</span>(<span class="ident">duration</span>: <span class="ident">Duration</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">usize</span>, <span class="ident">LimitationError</span><span class="op">&gt;</span> {
<span class="kw">match</span> <span class="ident">chrono::Duration::from_std</span>(<span class="ident">duration</span>) {
<span class="prelude-val">Ok</span>(<span class="ident">value</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">chrono::Utc::now</span>()
.<span class="ident">add</span>(<span class="ident">value</span>)
.<span class="ident">round_subsecs</span>(<span class="number">0</span>)
.<span class="ident">timestamp</span>()
.<span class="ident">try_into</span>()
.<span class="ident">unwrap_or</span>(<span class="number">0</span>)),
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>epoch_utc_plus(duration: Duration) -&gt; <span class="prelude-ty">Result</span>&lt;usize, LimitationError&gt; {
<span class="kw">match </span>chrono::Duration::from_std(duration) {
<span class="prelude-val">Ok</span>(value) =&gt; <span class="prelude-val">Ok</span>(chrono::Utc::now()
.add(value)
.round_subsecs(<span class="number">0</span>)
.timestamp()
.try_into()
.unwrap_or(<span class="number">0</span>)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(<span class="ident">LimitationError::Other</span>(
<span class="string">&quot;Source duration value is out of range for the target type&quot;</span>.<span class="ident">to_string</span>(),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(LimitationError::Other(
<span class="string">&quot;Source duration value is out of range for the target type&quot;</span>.to_string(),
)),
}
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_create_status</span>() {
<span class="kw">let</span> <span class="ident">status</span> <span class="op">=</span> <span class="ident">Status</span> {
<span class="ident">limit</span>: <span class="number">100</span>,
<span class="ident">remaining</span>: <span class="number">0</span>,
<span class="ident">reset_epoch_utc</span>: <span class="number">1000</span>,
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_create_status() {
<span class="kw">let </span>status = Status {
limit: <span class="number">100</span>,
remaining: <span class="number">0</span>,
reset_epoch_utc: <span class="number">1000</span>,
};
<span class="macro">assert_eq!</span>(<span class="ident">status</span>.<span class="ident">limit</span>(), <span class="number">100</span>);
<span class="macro">assert_eq!</span>(<span class="ident">status</span>.<span class="ident">remaining</span>(), <span class="number">0</span>);
<span class="macro">assert_eq!</span>(<span class="ident">status</span>.<span class="ident">reset_epoch_utc</span>(), <span class="number">1000</span>);
<span class="macro">assert_eq!</span>(status.limit(), <span class="number">100</span>);
<span class="macro">assert_eq!</span>(status.remaining(), <span class="number">0</span>);
<span class="macro">assert_eq!</span>(status.reset_epoch_utc(), <span class="number">1000</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_build_status</span>() {
<span class="kw">let</span> <span class="ident">count</span> <span class="op">=</span> <span class="number">200</span>;
<span class="kw">let</span> <span class="ident">limit</span> <span class="op">=</span> <span class="number">100</span>;
<span class="kw">let</span> <span class="ident">status</span> <span class="op">=</span> <span class="ident">Status::new</span>(<span class="ident">count</span>, <span class="ident">limit</span>, <span class="number">2000</span>);
<span class="macro">assert_eq!</span>(<span class="ident">status</span>.<span class="ident">limit</span>(), <span class="ident">limit</span>);
<span class="macro">assert_eq!</span>(<span class="ident">status</span>.<span class="ident">remaining</span>(), <span class="number">0</span>);
<span class="macro">assert_eq!</span>(<span class="ident">status</span>.<span class="ident">reset_epoch_utc</span>(), <span class="number">2000</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_build_status() {
<span class="kw">let </span>count = <span class="number">200</span>;
<span class="kw">let </span>limit = <span class="number">100</span>;
<span class="kw">let </span>status = Status::new(count, limit, <span class="number">2000</span>);
<span class="macro">assert_eq!</span>(status.limit(), limit);
<span class="macro">assert_eq!</span>(status.remaining(), <span class="number">0</span>);
<span class="macro">assert_eq!</span>(status.reset_epoch_utc(), <span class="number">2000</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_build_status_limit</span>() {
<span class="kw">let</span> <span class="ident">limit</span> <span class="op">=</span> <span class="number">100</span>;
<span class="kw">let</span> <span class="ident">status</span> <span class="op">=</span> <span class="ident">Status::new</span>(<span class="number">0</span>, <span class="ident">limit</span>, <span class="number">2000</span>);
<span class="macro">assert_eq!</span>(<span class="ident">status</span>.<span class="ident">limit</span>(), <span class="ident">limit</span>);
<span class="macro">assert_eq!</span>(<span class="ident">status</span>.<span class="ident">remaining</span>(), <span class="ident">limit</span>);
<span class="macro">assert_eq!</span>(<span class="ident">status</span>.<span class="ident">reset_epoch_utc</span>(), <span class="number">2000</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_build_status_limit() {
<span class="kw">let </span>limit = <span class="number">100</span>;
<span class="kw">let </span>status = Status::new(<span class="number">0</span>, limit, <span class="number">2000</span>);
<span class="macro">assert_eq!</span>(status.limit(), limit);
<span class="macro">assert_eq!</span>(status.remaining(), limit);
<span class="macro">assert_eq!</span>(status.reset_epoch_utc(), <span class="number">2000</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_epoch_utc_plus_zero</span>() {
<span class="kw">let</span> <span class="ident">duration</span> <span class="op">=</span> <span class="ident">Duration::from_secs</span>(<span class="number">0</span>);
<span class="kw">let</span> <span class="ident">seconds</span> <span class="op">=</span> <span class="ident">Status::epoch_utc_plus</span>(<span class="ident">duration</span>).<span class="ident">unwrap</span>();
<span class="macro">assert!</span>(<span class="ident">seconds</span> <span class="kw">as</span> <span class="ident">u64</span> <span class="op">&gt;</span><span class="op">=</span> <span class="ident">duration</span>.<span class="ident">as_secs</span>());
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_epoch_utc_plus_zero() {
<span class="kw">let </span>duration = Duration::from_secs(<span class="number">0</span>);
<span class="kw">let </span>seconds = Status::epoch_utc_plus(duration).unwrap();
<span class="macro">assert!</span>(seconds <span class="kw">as </span>u64 &gt;= duration.as_secs());
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_epoch_utc_plus</span>() {
<span class="kw">let</span> <span class="ident">duration</span> <span class="op">=</span> <span class="ident">Duration::from_secs</span>(<span class="number">10</span>);
<span class="kw">let</span> <span class="ident">seconds</span> <span class="op">=</span> <span class="ident">Status::epoch_utc_plus</span>(<span class="ident">duration</span>).<span class="ident">unwrap</span>();
<span class="macro">assert!</span>(<span class="ident">seconds</span> <span class="kw">as</span> <span class="ident">u64</span> <span class="op">&gt;</span><span class="op">=</span> <span class="ident">duration</span>.<span class="ident">as_secs</span>() <span class="op">+</span> <span class="number">10</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_epoch_utc_plus() {
<span class="kw">let </span>duration = Duration::from_secs(<span class="number">10</span>);
<span class="kw">let </span>seconds = Status::epoch_utc_plus(duration).unwrap();
<span class="macro">assert!</span>(seconds <span class="kw">as </span>u64 &gt;= duration.as_secs() + <span class="number">10</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="attribute">#[<span class="ident">should_panic</span> <span class="op">=</span> <span class="string">&quot;Source duration value is out of range for the target type&quot;</span>]</span>
<span class="kw">fn</span> <span class="ident">test_epoch_utc_plus_overflow</span>() {
<span class="kw">let</span> <span class="ident">duration</span> <span class="op">=</span> <span class="ident">Duration::from_secs</span>(<span class="number">10000000000000000000</span>);
<span class="ident">Status::epoch_utc_plus</span>(<span class="ident">duration</span>).<span class="ident">unwrap</span>();
<span class="attribute">#[test]
#[should_panic = <span class="string">&quot;Source duration value is out of range for the target type&quot;</span>]
</span><span class="kw">fn </span>test_epoch_utc_plus_overflow() {
<span class="kw">let </span>duration = Duration::from_secs(<span class="number">10000000000000000000</span>);
Status::epoch_utc_plus(duration).unwrap();
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_limitation" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_limitation" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -331,338 +331,342 @@
<span id="331">331</span>
<span id="332">332</span>
<span id="333">333</span>
</pre><pre class="rust"><code><span class="doccomment">//! Protobuf payload extractor for Actix Web.</span>
<span id="334">334</span>
<span id="335">335</span>
</pre><pre class="rust"><code><span class="doccomment">//! Protobuf payload extractor for Actix Web.
<span class="attribute">#![<span class="ident">forbid</span>(<span class="ident">unsafe_code</span>)]</span>
<span class="attribute">#![<span class="ident">deny</span>(<span class="ident">rust_2018_idioms</span>, <span class="ident">nonstandard_style</span>)]</span>
<span class="attribute">#![<span class="ident">warn</span>(<span class="ident">future_incompatible</span>)]</span>
</span><span class="attribute">#![forbid(unsafe_code)]
#![deny(rust_2018_idioms, nonstandard_style)]
#![warn(future_incompatible)]
<span class="kw">use</span> <span class="ident">std</span>::{
<span class="ident">fmt</span>,
<span class="ident">future::Future</span>,
<span class="ident">ops</span>::{<span class="ident">Deref</span>, <span class="ident">DerefMut</span>},
<span class="ident">pin::Pin</span>,
<span class="ident">task</span>::{<span class="self">self</span>, <span class="ident">Poll</span>},
</span><span class="kw">use </span>std::{
fmt,
future::Future,
ops::{Deref, DerefMut},
pin::Pin,
task::{<span class="self">self</span>, Poll},
};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">body::BoxBody</span>,
<span class="ident">dev::Payload</span>,
<span class="ident">error::PayloadError</span>,
<span class="ident">http::header</span>::{<span class="ident">CONTENT_LENGTH</span>, <span class="ident">CONTENT_TYPE</span>},
<span class="ident">web::BytesMut</span>,
<span class="ident">Error</span>, <span class="ident">FromRequest</span>, <span class="ident">HttpMessage</span>, <span class="ident">HttpRequest</span>, <span class="ident">HttpResponse</span>, <span class="ident">HttpResponseBuilder</span>, <span class="ident">Responder</span>,
<span class="ident">ResponseError</span>,
<span class="kw">use </span>actix_web::{
body::BoxBody,
dev::Payload,
error::PayloadError,
http::header::{CONTENT_LENGTH, CONTENT_TYPE},
web::BytesMut,
Error, FromRequest, HttpMessage, HttpRequest, HttpResponse, HttpResponseBuilder, Responder,
ResponseError,
};
<span class="kw">use</span> <span class="ident">derive_more::Display</span>;
<span class="kw">use</span> <span class="ident">futures_util</span>::{
<span class="ident">future</span>::{<span class="ident">FutureExt</span> <span class="kw">as</span> <span class="kw">_</span>, <span class="ident">LocalBoxFuture</span>},
<span class="ident">stream::StreamExt</span> <span class="kw">as</span> <span class="kw">_</span>,
<span class="kw">use </span>derive_more::Display;
<span class="kw">use </span>futures_util::{
future::{FutureExt <span class="kw">as _</span>, LocalBoxFuture},
stream::StreamExt <span class="kw">as _</span>,
};
<span class="kw">use</span> <span class="ident">prost</span>::{<span class="ident">DecodeError</span> <span class="kw">as</span> <span class="ident">ProtoBufDecodeError</span>, <span class="ident">EncodeError</span> <span class="kw">as</span> <span class="ident">ProtoBufEncodeError</span>, <span class="ident">Message</span>};
<span class="kw">use </span>prost::{DecodeError <span class="kw">as </span>ProtoBufDecodeError, EncodeError <span class="kw">as </span>ProtoBufEncodeError, Message};
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Display</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">ProtoBufPayloadError</span> {
<span class="doccomment">/// Payload size is bigger than 256k</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Payload size is bigger than 256k&quot;</span>)]</span>
<span class="ident">Overflow</span>,
<span class="attribute">#[derive(Debug, Display)]
</span><span class="kw">pub enum </span>ProtoBufPayloadError {
<span class="doccomment">/// Payload size is bigger than 256k
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Payload size is bigger than 256k&quot;</span>)]
</span>Overflow,
<span class="doccomment">/// Content type error</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Content type error&quot;</span>)]</span>
<span class="ident">ContentType</span>,
<span class="doccomment">/// Content type error
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Content type error&quot;</span>)]
</span>ContentType,
<span class="doccomment">/// Serialize error</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;ProtoBuf serialize error: {}&quot;</span>, <span class="ident">_0</span>)]</span>
<span class="ident">Serialize</span>(<span class="ident">ProtoBufEncodeError</span>),
<span class="doccomment">/// Serialize error
</span><span class="attribute">#[display(fmt = <span class="string">&quot;ProtoBuf serialize error: {}&quot;</span>, _0)]
</span>Serialize(ProtoBufEncodeError),
<span class="doccomment">/// Deserialize error</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;ProtoBuf deserialize error: {}&quot;</span>, <span class="ident">_0</span>)]</span>
<span class="ident">Deserialize</span>(<span class="ident">ProtoBufDecodeError</span>),
<span class="doccomment">/// Deserialize error
</span><span class="attribute">#[display(fmt = <span class="string">&quot;ProtoBuf deserialize error: {}&quot;</span>, _0)]
</span>Deserialize(ProtoBufDecodeError),
<span class="doccomment">/// Payload error</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Error that occur during reading payload: {}&quot;</span>, <span class="ident">_0</span>)]</span>
<span class="ident">Payload</span>(<span class="ident">PayloadError</span>),
<span class="doccomment">/// Payload error
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Error that occur during reading payload: {}&quot;</span>, _0)]
</span>Payload(PayloadError),
}
<span class="kw">impl</span> <span class="ident">ResponseError</span> <span class="kw">for</span> <span class="ident">ProtoBufPayloadError</span> {
<span class="kw">fn</span> <span class="ident">error_response</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">HttpResponse</span> {
<span class="kw">match</span> <span class="kw-2">*</span><span class="self">self</span> {
<span class="ident">ProtoBufPayloadError::Overflow</span> =&gt; <span class="ident">HttpResponse::PayloadTooLarge</span>().<span class="ident">into</span>(),
<span class="kw">_</span> =&gt; <span class="ident">HttpResponse::BadRequest</span>().<span class="ident">into</span>(),
<span class="kw">impl </span>ResponseError <span class="kw">for </span>ProtoBufPayloadError {
<span class="kw">fn </span>error_response(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; HttpResponse {
<span class="kw">match </span><span class="kw-2">*</span><span class="self">self </span>{
ProtoBufPayloadError::Overflow =&gt; HttpResponse::PayloadTooLarge().into(),
<span class="kw">_ </span>=&gt; HttpResponse::BadRequest().into(),
}
}
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">PayloadError</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">ProtoBufPayloadError</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">err</span>: <span class="ident">PayloadError</span>) -&gt; <span class="ident">ProtoBufPayloadError</span> {
<span class="ident">ProtoBufPayloadError::Payload</span>(<span class="ident">err</span>)
<span class="kw">impl </span>From&lt;PayloadError&gt; <span class="kw">for </span>ProtoBufPayloadError {
<span class="kw">fn </span>from(err: PayloadError) -&gt; ProtoBufPayloadError {
ProtoBufPayloadError::Payload(err)
}
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">ProtoBufDecodeError</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">ProtoBufPayloadError</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">err</span>: <span class="ident">ProtoBufDecodeError</span>) -&gt; <span class="ident">ProtoBufPayloadError</span> {
<span class="ident">ProtoBufPayloadError::Deserialize</span>(<span class="ident">err</span>)
<span class="kw">impl </span>From&lt;ProtoBufDecodeError&gt; <span class="kw">for </span>ProtoBufPayloadError {
<span class="kw">fn </span>from(err: ProtoBufDecodeError) -&gt; ProtoBufPayloadError {
ProtoBufPayloadError::Deserialize(err)
}
}
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">ProtoBuf</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Message</span><span class="op">&gt;</span>(<span class="kw">pub</span> <span class="ident">T</span>);
<span class="kw">pub struct </span>ProtoBuf&lt;T: Message&gt;(<span class="kw">pub </span>T);
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Message</span><span class="op">&gt;</span> <span class="ident">Deref</span> <span class="kw">for</span> <span class="ident">ProtoBuf</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> {
<span class="kw">type</span> <span class="ident">Target</span> <span class="op">=</span> <span class="ident">T</span>;
<span class="kw">impl</span>&lt;T: Message&gt; Deref <span class="kw">for </span>ProtoBuf&lt;T&gt; {
<span class="kw">type </span>Target = T;
<span class="kw">fn</span> <span class="ident">deref</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="ident">T</span> {
<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0</span>
}
<span class="kw">fn </span>deref(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>T {
<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0
</span>}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Message</span><span class="op">&gt;</span> <span class="ident">DerefMut</span> <span class="kw">for</span> <span class="ident">ProtoBuf</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">deref_mut</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut</span> <span class="ident">T</span> {
<span class="kw-2">&amp;mut</span> <span class="self">self</span>.<span class="number">0</span>
}
<span class="kw">impl</span>&lt;T: Message&gt; DerefMut <span class="kw">for </span>ProtoBuf&lt;T&gt; {
<span class="kw">fn </span>deref_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>T {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.<span class="number">0
</span>}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Message</span><span class="op">&gt;</span> <span class="ident">fmt::Debug</span> <span class="kw">for</span> <span class="ident">ProtoBuf</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">fmt::Debug</span>,
<span class="kw">impl</span>&lt;T: Message&gt; fmt::Debug <span class="kw">for </span>ProtoBuf&lt;T&gt;
<span class="kw">where
</span>T: fmt::Debug,
{
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="macro">write!</span>(<span class="ident">f</span>, <span class="string">&quot;ProtoBuf: {:?}&quot;</span>, <span class="self">self</span>.<span class="number">0</span>)
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
<span class="macro">write!</span>(f, <span class="string">&quot;ProtoBuf: {:?}&quot;</span>, <span class="self">self</span>.<span class="number">0</span>)
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Message</span><span class="op">&gt;</span> <span class="ident">fmt::Display</span> <span class="kw">for</span> <span class="ident">ProtoBuf</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">fmt::Display</span>,
<span class="kw">impl</span>&lt;T: Message&gt; fmt::Display <span class="kw">for </span>ProtoBuf&lt;T&gt;
<span class="kw">where
</span>T: fmt::Display,
{
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="ident">fmt::Display::fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0</span>, <span class="ident">f</span>)
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
fmt::Display::fmt(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0</span>, f)
}
}
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">ProtoBufConfig</span> {
<span class="ident">limit</span>: <span class="ident">usize</span>,
<span class="kw">pub struct </span>ProtoBufConfig {
limit: usize,
}
<span class="kw">impl</span> <span class="ident">ProtoBufConfig</span> {
<span class="doccomment">/// Change max size of payload. By default max size is 256Kb</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">limit</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>, <span class="ident">limit</span>: <span class="ident">usize</span>) -&gt; <span class="kw-2">&amp;mut</span> <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">limit</span> <span class="op">=</span> <span class="ident">limit</span>;
<span class="self">self</span>
<span class="kw">impl </span>ProtoBufConfig {
<span class="doccomment">/// Change max size of payload. By default max size is 256Kb
</span><span class="kw">pub fn </span>limit(<span class="kw-2">&amp;mut </span><span class="self">self</span>, limit: usize) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="self">self</span>.limit = limit;
<span class="self">self
</span>}
}
<span class="kw">impl </span>Default <span class="kw">for </span>ProtoBufConfig {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
ProtoBufConfig { limit: <span class="number">262_144 </span>}
}
}
<span class="kw">impl</span> <span class="ident">Default</span> <span class="kw">for</span> <span class="ident">ProtoBufConfig</span> {
<span class="kw">fn</span> <span class="ident">default</span>() -&gt; <span class="self">Self</span> {
<span class="ident">ProtoBufConfig</span> { <span class="ident">limit</span>: <span class="number">262_144</span> }
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> <span class="ident">FromRequest</span> <span class="kw">for</span> <span class="ident">ProtoBuf</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">Message</span> <span class="op">+</span> <span class="ident">Default</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="kw">impl</span>&lt;T&gt; FromRequest <span class="kw">for </span>ProtoBuf&lt;T&gt;
<span class="kw">where
</span>T: Message + Default + <span class="lifetime">&#39;static</span>,
{
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span>;
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">LocalBoxFuture</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">Error</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Future = LocalBoxFuture&lt;<span class="lifetime">&#39;static</span>, <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, Error&gt;&gt;;
<span class="attribute">#[<span class="ident">inline</span>]</span>
<span class="kw">fn</span> <span class="ident">from_request</span>(<span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">HttpRequest</span>, <span class="ident">payload</span>: <span class="kw-2">&amp;mut</span> <span class="ident">Payload</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="kw">let</span> <span class="ident">limit</span> <span class="op">=</span> <span class="ident">req</span>
.<span class="ident">app_data</span>::<span class="op">&lt;</span><span class="ident">ProtoBufConfig</span><span class="op">&gt;</span>()
.<span class="ident">map</span>(<span class="op">|</span><span class="ident">c</span><span class="op">|</span> <span class="ident">c</span>.<span class="ident">limit</span>)
.<span class="ident">unwrap_or</span>(<span class="number">262_144</span>);
<span class="ident">ProtoBufMessage::new</span>(<span class="ident">req</span>, <span class="ident">payload</span>)
.<span class="ident">limit</span>(<span class="ident">limit</span>)
.<span class="ident">map</span>(<span class="kw">move</span> <span class="op">|</span><span class="ident">res</span><span class="op">|</span> <span class="kw">match</span> <span class="ident">res</span> {
<span class="prelude-val">Err</span>(<span class="ident">e</span>) =&gt; <span class="prelude-val">Err</span>(<span class="ident">e</span>.<span class="ident">into</span>()),
<span class="prelude-val">Ok</span>(<span class="ident">item</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">ProtoBuf</span>(<span class="ident">item</span>)),
<span class="attribute">#[inline]
</span><span class="kw">fn </span>from_request(req: <span class="kw-2">&amp;</span>HttpRequest, payload: <span class="kw-2">&amp;mut </span>Payload) -&gt; <span class="self">Self</span>::Future {
<span class="kw">let </span>limit = req
.app_data::&lt;ProtoBufConfig&gt;()
.map(|c| c.limit)
.unwrap_or(<span class="number">262_144</span>);
ProtoBufMessage::new(req, payload)
.limit(limit)
.map(<span class="kw">move </span>|res| <span class="kw">match </span>res {
<span class="prelude-val">Err</span>(e) =&gt; <span class="prelude-val">Err</span>(e.into()),
<span class="prelude-val">Ok</span>(item) =&gt; <span class="prelude-val">Ok</span>(ProtoBuf(item)),
})
.<span class="ident">boxed_local</span>()
.boxed_local()
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Message</span> <span class="op">+</span> <span class="ident">Default</span><span class="op">&gt;</span> <span class="ident">Responder</span> <span class="kw">for</span> <span class="ident">ProtoBuf</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> {
<span class="kw">type</span> <span class="ident">Body</span> <span class="op">=</span> <span class="ident">BoxBody</span>;
<span class="kw">impl</span>&lt;T: Message + Default&gt; Responder <span class="kw">for </span>ProtoBuf&lt;T&gt; {
<span class="kw">type </span>Body = BoxBody;
<span class="kw">fn</span> <span class="ident">respond_to</span>(<span class="self">self</span>, <span class="kw">_</span>: <span class="kw-2">&amp;</span><span class="ident">HttpRequest</span>) -&gt; <span class="ident">HttpResponse</span> {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">buf</span> <span class="op">=</span> <span class="ident">Vec::new</span>();
<span class="kw">match</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">encode</span>(<span class="kw-2">&amp;mut</span> <span class="ident">buf</span>) {
<span class="prelude-val">Ok</span>(()) =&gt; <span class="ident">HttpResponse::Ok</span>()
.<span class="ident">content_type</span>(<span class="string">&quot;application/protobuf&quot;</span>)
.<span class="ident">body</span>(<span class="ident">buf</span>),
<span class="prelude-val">Err</span>(<span class="ident">err</span>) =&gt; <span class="ident">HttpResponse::from_error</span>(<span class="ident">Error::from</span>(<span class="ident">ProtoBufPayloadError::Serialize</span>(<span class="ident">err</span>))),
<span class="kw">fn </span>respond_to(<span class="self">self</span>, <span class="kw">_</span>: <span class="kw-2">&amp;</span>HttpRequest) -&gt; HttpResponse {
<span class="kw">let </span><span class="kw-2">mut </span>buf = Vec::new();
<span class="kw">match </span><span class="self">self</span>.<span class="number">0</span>.encode(<span class="kw-2">&amp;mut </span>buf) {
<span class="prelude-val">Ok</span>(()) =&gt; HttpResponse::Ok()
.content_type(<span class="string">&quot;application/protobuf&quot;</span>)
.body(buf),
<span class="prelude-val">Err</span>(err) =&gt; HttpResponse::from_error(Error::from(ProtoBufPayloadError::Serialize(err))),
}
}
}
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">ProtoBufMessage</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Message</span> <span class="op">+</span> <span class="ident">Default</span><span class="op">&gt;</span> {
<span class="ident">limit</span>: <span class="ident">usize</span>,
<span class="ident">length</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">usize</span><span class="op">&gt;</span>,
<span class="ident">stream</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Payload</span><span class="op">&gt;</span>,
<span class="ident">err</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">ProtoBufPayloadError</span><span class="op">&gt;</span>,
<span class="ident">fut</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">LocalBoxFuture</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">T</span>, <span class="ident">ProtoBufPayloadError</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">pub struct </span>ProtoBufMessage&lt;T: Message + Default&gt; {
limit: usize,
length: <span class="prelude-ty">Option</span>&lt;usize&gt;,
stream: <span class="prelude-ty">Option</span>&lt;Payload&gt;,
err: <span class="prelude-ty">Option</span>&lt;ProtoBufPayloadError&gt;,
fut: <span class="prelude-ty">Option</span>&lt;LocalBoxFuture&lt;<span class="lifetime">&#39;static</span>, <span class="prelude-ty">Result</span>&lt;T, ProtoBufPayloadError&gt;&gt;&gt;,
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Message</span> <span class="op">+</span> <span class="ident">Default</span><span class="op">&gt;</span> <span class="ident">ProtoBufMessage</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> {
<span class="doccomment">/// Create `ProtoBufMessage` for request.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">new</span>(<span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">HttpRequest</span>, <span class="ident">payload</span>: <span class="kw-2">&amp;mut</span> <span class="ident">Payload</span>) -&gt; <span class="self">Self</span> {
<span class="kw">if</span> <span class="ident">req</span>.<span class="ident">content_type</span>() <span class="op">!</span><span class="op">=</span> <span class="string">&quot;application/protobuf&quot;</span> {
<span class="kw">return</span> <span class="ident">ProtoBufMessage</span> {
<span class="ident">limit</span>: <span class="number">262_144</span>,
<span class="ident">length</span>: <span class="prelude-val">None</span>,
<span class="ident">stream</span>: <span class="prelude-val">None</span>,
<span class="ident">fut</span>: <span class="prelude-val">None</span>,
<span class="ident">err</span>: <span class="prelude-val">Some</span>(<span class="ident">ProtoBufPayloadError::ContentType</span>),
<span class="kw">impl</span>&lt;T: Message + Default&gt; ProtoBufMessage&lt;T&gt; {
<span class="doccomment">/// Create `ProtoBufMessage` for request.
</span><span class="kw">pub fn </span>new(req: <span class="kw-2">&amp;</span>HttpRequest, payload: <span class="kw-2">&amp;mut </span>Payload) -&gt; <span class="self">Self </span>{
<span class="kw">if </span>req.content_type() != <span class="string">&quot;application/protobuf&quot;
</span>&amp;&amp; req.content_type() != <span class="string">&quot;application/x-protobuf&quot;
</span>{
<span class="kw">return </span>ProtoBufMessage {
limit: <span class="number">262_144</span>,
length: <span class="prelude-val">None</span>,
stream: <span class="prelude-val">None</span>,
fut: <span class="prelude-val">None</span>,
err: <span class="prelude-val">Some</span>(ProtoBufPayloadError::ContentType),
};
}
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">len</span> <span class="op">=</span> <span class="prelude-val">None</span>;
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">l</span>) <span class="op">=</span> <span class="ident">req</span>.<span class="ident">headers</span>().<span class="ident">get</span>(<span class="ident">CONTENT_LENGTH</span>) {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Ok</span>(<span class="ident">s</span>) <span class="op">=</span> <span class="ident">l</span>.<span class="ident">to_str</span>() {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Ok</span>(<span class="ident">l</span>) <span class="op">=</span> <span class="ident">s</span>.<span class="ident">parse</span>::<span class="op">&lt;</span><span class="ident">usize</span><span class="op">&gt;</span>() {
<span class="ident">len</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">l</span>)
<span class="kw">let </span><span class="kw-2">mut </span>len = <span class="prelude-val">None</span>;
<span class="kw">if let </span><span class="prelude-val">Some</span>(l) = req.headers().get(CONTENT_LENGTH) {
<span class="kw">if let </span><span class="prelude-val">Ok</span>(s) = l.to_str() {
<span class="kw">if let </span><span class="prelude-val">Ok</span>(l) = s.parse::&lt;usize&gt;() {
len = <span class="prelude-val">Some</span>(l)
}
}
}
<span class="ident">ProtoBufMessage</span> {
<span class="ident">limit</span>: <span class="number">262_144</span>,
<span class="ident">length</span>: <span class="ident">len</span>,
<span class="ident">stream</span>: <span class="prelude-val">Some</span>(<span class="ident">payload</span>.<span class="ident">take</span>()),
<span class="ident">fut</span>: <span class="prelude-val">None</span>,
<span class="ident">err</span>: <span class="prelude-val">None</span>,
ProtoBufMessage {
limit: <span class="number">262_144</span>,
length: len,
stream: <span class="prelude-val">Some</span>(payload.take()),
fut: <span class="prelude-val">None</span>,
err: <span class="prelude-val">None</span>,
}
}
<span class="doccomment">/// Change max size of payload. By default max size is 256Kb</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">limit</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">limit</span>: <span class="ident">usize</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">limit</span> <span class="op">=</span> <span class="ident">limit</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Change max size of payload. By default max size is 256Kb
</span><span class="kw">pub fn </span>limit(<span class="kw-2">mut </span><span class="self">self</span>, limit: usize) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.limit = limit;
<span class="self">self
</span>}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Message</span> <span class="op">+</span> <span class="ident">Default</span> <span class="op">+</span> <span class="lifetime">&#39;static</span><span class="op">&gt;</span> <span class="ident">Future</span> <span class="kw">for</span> <span class="ident">ProtoBufMessage</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> {
<span class="kw">type</span> <span class="ident">Output</span> <span class="op">=</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">T</span>, <span class="ident">ProtoBufPayloadError</span><span class="op">&gt;</span>;
<span class="kw">impl</span>&lt;T: Message + Default + <span class="lifetime">&#39;static</span>&gt; Future <span class="kw">for </span>ProtoBufMessage&lt;T&gt; {
<span class="kw">type </span>Output = <span class="prelude-ty">Result</span>&lt;T, ProtoBufPayloadError&gt;;
<span class="kw">fn</span> <span class="ident">poll</span>(<span class="kw-2">mut</span> <span class="self">self</span>: <span class="ident">Pin</span><span class="op">&lt;</span><span class="kw-2">&amp;mut</span> <span class="self">Self</span><span class="op">&gt;</span>, <span class="ident">task</span>: <span class="kw-2">&amp;mut</span> <span class="ident">task::Context</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">Poll</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Output</span><span class="op">&gt;</span> {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="kw-2">mut</span> <span class="ident">fut</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">fut</span> {
<span class="kw">return</span> <span class="ident">Pin::new</span>(<span class="ident">fut</span>).<span class="ident">poll</span>(<span class="ident">task</span>);
<span class="kw">fn </span>poll(<span class="kw-2">mut </span><span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, task: <span class="kw-2">&amp;mut </span>task::Context&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; Poll&lt;<span class="self">Self</span>::Output&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref mut </span>fut) = <span class="self">self</span>.fut {
<span class="kw">return </span>Pin::new(fut).poll(task);
}
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">err</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">err</span>.<span class="ident">take</span>() {
<span class="kw">return</span> <span class="ident">Poll::Ready</span>(<span class="prelude-val">Err</span>(<span class="ident">err</span>));
<span class="kw">if let </span><span class="prelude-val">Some</span>(err) = <span class="self">self</span>.err.take() {
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">Err</span>(err));
}
<span class="kw">let</span> <span class="ident">limit</span> <span class="op">=</span> <span class="self">self</span>.<span class="ident">limit</span>;
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">len</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>.<span class="ident">take</span>() {
<span class="kw">if</span> <span class="ident">len</span> <span class="op">&gt;</span> <span class="ident">limit</span> {
<span class="kw">return</span> <span class="ident">Poll::Ready</span>(<span class="prelude-val">Err</span>(<span class="ident">ProtoBufPayloadError::Overflow</span>));
<span class="kw">let </span>limit = <span class="self">self</span>.limit;
<span class="kw">if let </span><span class="prelude-val">Some</span>(len) = <span class="self">self</span>.length.take() {
<span class="kw">if </span>len &gt; limit {
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">Err</span>(ProtoBufPayloadError::Overflow));
}
}
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">stream</span> <span class="op">=</span> <span class="self">self</span>
.<span class="ident">stream</span>
.<span class="ident">take</span>()
.<span class="ident">expect</span>(<span class="string">&quot;ProtoBufMessage could not be used second time&quot;</span>);
<span class="kw">let </span><span class="kw-2">mut </span>stream = <span class="self">self
</span>.stream
.take()
.expect(<span class="string">&quot;ProtoBufMessage could not be used second time&quot;</span>);
<span class="self">self</span>.<span class="ident">fut</span> <span class="op">=</span> <span class="prelude-val">Some</span>(
<span class="kw">async</span> <span class="kw">move</span> {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">body</span> <span class="op">=</span> <span class="ident">BytesMut::with_capacity</span>(<span class="number">8192</span>);
<span class="self">self</span>.fut = <span class="prelude-val">Some</span>(
<span class="kw">async move </span>{
<span class="kw">let </span><span class="kw-2">mut </span>body = BytesMut::with_capacity(<span class="number">8192</span>);
<span class="kw">while</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">item</span>) <span class="op">=</span> <span class="ident">stream</span>.<span class="ident">next</span>().<span class="kw">await</span> {
<span class="kw">let</span> <span class="ident">chunk</span> <span class="op">=</span> <span class="ident">item</span><span class="question-mark">?</span>;
<span class="kw">if</span> (<span class="ident">body</span>.<span class="ident">len</span>() <span class="op">+</span> <span class="ident">chunk</span>.<span class="ident">len</span>()) <span class="op">&gt;</span> <span class="ident">limit</span> {
<span class="kw">return</span> <span class="prelude-val">Err</span>(<span class="ident">ProtoBufPayloadError::Overflow</span>);
} <span class="kw">else</span> {
<span class="ident">body</span>.<span class="ident">extend_from_slice</span>(<span class="kw-2">&amp;</span><span class="ident">chunk</span>);
<span class="kw">while let </span><span class="prelude-val">Some</span>(item) = stream.next().<span class="kw">await </span>{
<span class="kw">let </span>chunk = item<span class="question-mark">?</span>;
<span class="kw">if </span>(body.len() + chunk.len()) &gt; limit {
<span class="kw">return </span><span class="prelude-val">Err</span>(ProtoBufPayloadError::Overflow);
} <span class="kw">else </span>{
body.extend_from_slice(<span class="kw-2">&amp;</span>chunk);
}
}
<span class="prelude-val">Ok</span>(<span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span><span class="ident">::decode</span>(<span class="kw-2">&amp;mut</span> <span class="ident">body</span>)<span class="question-mark">?</span>)
<span class="prelude-val">Ok</span>(&lt;T&gt;::decode(<span class="kw-2">&amp;mut </span>body)<span class="question-mark">?</span>)
}
.<span class="ident">boxed_local</span>(),
.boxed_local(),
);
<span class="self">self</span>.<span class="ident">poll</span>(<span class="ident">task</span>)
<span class="self">self</span>.poll(task)
}
}
<span class="kw">pub</span> <span class="kw">trait</span> <span class="ident">ProtoBufResponseBuilder</span> {
<span class="kw">fn</span> <span class="ident">protobuf</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Message</span><span class="op">&gt;</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>, <span class="ident">value</span>: <span class="ident">T</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HttpResponse</span>, <span class="ident">Error</span><span class="op">&gt;</span>;
<span class="kw">pub trait </span>ProtoBufResponseBuilder {
<span class="kw">fn </span>protobuf&lt;T: Message&gt;(<span class="kw-2">&amp;mut </span><span class="self">self</span>, value: T) -&gt; <span class="prelude-ty">Result</span>&lt;HttpResponse, Error&gt;;
}
<span class="kw">impl</span> <span class="ident">ProtoBufResponseBuilder</span> <span class="kw">for</span> <span class="ident">HttpResponseBuilder</span> {
<span class="kw">fn</span> <span class="ident">protobuf</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Message</span><span class="op">&gt;</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>, <span class="ident">value</span>: <span class="ident">T</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HttpResponse</span>, <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="self">self</span>.<span class="ident">insert_header</span>((<span class="ident">CONTENT_TYPE</span>, <span class="string">&quot;application/protobuf&quot;</span>));
<span class="kw">impl </span>ProtoBufResponseBuilder <span class="kw">for </span>HttpResponseBuilder {
<span class="kw">fn </span>protobuf&lt;T: Message&gt;(<span class="kw-2">&amp;mut </span><span class="self">self</span>, value: T) -&gt; <span class="prelude-ty">Result</span>&lt;HttpResponse, Error&gt; {
<span class="self">self</span>.insert_header((CONTENT_TYPE, <span class="string">&quot;application/protobuf&quot;</span>));
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">body</span> <span class="op">=</span> <span class="ident">Vec::new</span>();
<span class="ident">value</span>
.<span class="ident">encode</span>(<span class="kw-2">&amp;mut</span> <span class="ident">body</span>)
.<span class="ident">map_err</span>(<span class="ident">ProtoBufPayloadError::Serialize</span>)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(<span class="self">self</span>.<span class="ident">body</span>(<span class="ident">body</span>))
<span class="kw">let </span><span class="kw-2">mut </span>body = Vec::new();
value
.encode(<span class="kw-2">&amp;mut </span>body)
.map_err(ProtoBufPayloadError::Serialize)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(<span class="self">self</span>.body(body))
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="ident">actix_web::http::header</span>;
<span class="kw">use</span> <span class="ident">actix_web::test::TestRequest</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>actix_web::http::header;
<span class="kw">use </span>actix_web::test::TestRequest;
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">impl</span> <span class="ident">PartialEq</span> <span class="kw">for</span> <span class="ident">ProtoBufPayloadError</span> {
<span class="kw">fn</span> <span class="ident">eq</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">other</span>: <span class="kw-2">&amp;</span><span class="ident">ProtoBufPayloadError</span>) -&gt; <span class="ident">bool</span> {
<span class="kw">match</span> <span class="kw-2">*</span><span class="self">self</span> {
<span class="ident">ProtoBufPayloadError::Overflow</span> =&gt; {
<span class="macro">matches!</span>(<span class="kw-2">*</span><span class="ident">other</span>, <span class="ident">ProtoBufPayloadError::Overflow</span>)
<span class="kw">impl </span>PartialEq <span class="kw">for </span>ProtoBufPayloadError {
<span class="kw">fn </span>eq(<span class="kw-2">&amp;</span><span class="self">self</span>, other: <span class="kw-2">&amp;</span>ProtoBufPayloadError) -&gt; bool {
<span class="kw">match </span><span class="kw-2">*</span><span class="self">self </span>{
ProtoBufPayloadError::Overflow =&gt; {
<span class="macro">matches!</span>(<span class="kw-2">*</span>other, ProtoBufPayloadError::Overflow)
}
<span class="ident">ProtoBufPayloadError::ContentType</span> =&gt; {
<span class="macro">matches!</span>(<span class="kw-2">*</span><span class="ident">other</span>, <span class="ident">ProtoBufPayloadError::ContentType</span>)
ProtoBufPayloadError::ContentType =&gt; {
<span class="macro">matches!</span>(<span class="kw-2">*</span>other, ProtoBufPayloadError::ContentType)
}
<span class="kw">_</span> =&gt; <span class="bool-val">false</span>,
<span class="kw">_ </span>=&gt; <span class="bool-val">false</span>,
}
}
}
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">Message</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">MyObject</span> {
<span class="attribute">#[<span class="ident">prost</span>(<span class="ident">int32</span>, <span class="ident">tag</span> <span class="op">=</span> <span class="string">&quot;1&quot;</span>)]</span>
<span class="kw">pub</span> <span class="ident">number</span>: <span class="ident">i32</span>,
<span class="attribute">#[<span class="ident">prost</span>(<span class="ident">string</span>, <span class="ident">tag</span> <span class="op">=</span> <span class="string">&quot;2&quot;</span>)]</span>
<span class="kw">pub</span> <span class="ident">name</span>: <span class="ident">String</span>,
<span class="attribute">#[derive(Clone, PartialEq, Eq, Message)]
</span><span class="kw">pub struct </span>MyObject {
<span class="attribute">#[prost(int32, tag = <span class="string">&quot;1&quot;</span>)]
</span><span class="kw">pub </span>number: i32,
<span class="attribute">#[prost(string, tag = <span class="string">&quot;2&quot;</span>)]
</span><span class="kw">pub </span>name: String,
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_protobuf</span>() {
<span class="kw">let</span> <span class="ident">protobuf</span> <span class="op">=</span> <span class="ident">ProtoBuf</span>(<span class="ident">MyObject</span> {
<span class="ident">number</span>: <span class="number">9</span>,
<span class="ident">name</span>: <span class="string">&quot;test&quot;</span>.<span class="ident">to_owned</span>(),
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_protobuf() {
<span class="kw">let </span>protobuf = ProtoBuf(MyObject {
number: <span class="number">9</span>,
name: <span class="string">&quot;test&quot;</span>.to_owned(),
});
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::default</span>().<span class="ident">to_http_request</span>();
<span class="kw">let</span> <span class="ident">resp</span> <span class="op">=</span> <span class="ident">protobuf</span>.<span class="ident">respond_to</span>(<span class="kw-2">&amp;</span><span class="ident">req</span>);
<span class="kw">let</span> <span class="ident">ct</span> <span class="op">=</span> <span class="ident">resp</span>.<span class="ident">headers</span>().<span class="ident">get</span>(<span class="ident">header::CONTENT_TYPE</span>).<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">ct</span>, <span class="string">&quot;application/protobuf&quot;</span>);
<span class="kw">let </span>req = TestRequest::default().to_http_request();
<span class="kw">let </span>resp = protobuf.respond_to(<span class="kw-2">&amp;</span>req);
<span class="kw">let </span>ct = resp.headers().get(header::CONTENT_TYPE).unwrap();
<span class="macro">assert_eq!</span>(ct, <span class="string">&quot;application/protobuf&quot;</span>);
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_protobuf_message</span>() {
<span class="kw">let</span> (<span class="ident">req</span>, <span class="kw-2">mut</span> <span class="ident">pl</span>) <span class="op">=</span> <span class="ident">TestRequest::default</span>().<span class="ident">to_http_parts</span>();
<span class="kw">let</span> <span class="ident">protobuf</span> <span class="op">=</span> <span class="ident">ProtoBufMessage</span>::<span class="op">&lt;</span><span class="ident">MyObject</span><span class="op">&gt;</span><span class="ident">::new</span>(<span class="kw-2">&amp;</span><span class="ident">req</span>, <span class="kw-2">&amp;mut</span> <span class="ident">pl</span>).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(<span class="ident">protobuf</span>.<span class="ident">err</span>().<span class="ident">unwrap</span>(), <span class="ident">ProtoBufPayloadError::ContentType</span>);
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_protobuf_message() {
<span class="kw">let </span>(req, <span class="kw-2">mut </span>pl) = TestRequest::default().to_http_parts();
<span class="kw">let </span>protobuf = ProtoBufMessage::&lt;MyObject&gt;::new(<span class="kw-2">&amp;</span>req, <span class="kw-2">&amp;mut </span>pl).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(protobuf.err().unwrap(), ProtoBufPayloadError::ContentType);
<span class="kw">let</span> (<span class="ident">req</span>, <span class="kw-2">mut</span> <span class="ident">pl</span>) <span class="op">=</span> <span class="ident">TestRequest::get</span>()
.<span class="ident">insert_header</span>((<span class="ident">header::CONTENT_TYPE</span>, <span class="string">&quot;application/text&quot;</span>))
.<span class="ident">to_http_parts</span>();
<span class="kw">let</span> <span class="ident">protobuf</span> <span class="op">=</span> <span class="ident">ProtoBufMessage</span>::<span class="op">&lt;</span><span class="ident">MyObject</span><span class="op">&gt;</span><span class="ident">::new</span>(<span class="kw-2">&amp;</span><span class="ident">req</span>, <span class="kw-2">&amp;mut</span> <span class="ident">pl</span>).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(<span class="ident">protobuf</span>.<span class="ident">err</span>().<span class="ident">unwrap</span>(), <span class="ident">ProtoBufPayloadError::ContentType</span>);
<span class="kw">let </span>(req, <span class="kw-2">mut </span>pl) = TestRequest::get()
.insert_header((header::CONTENT_TYPE, <span class="string">&quot;application/text&quot;</span>))
.to_http_parts();
<span class="kw">let </span>protobuf = ProtoBufMessage::&lt;MyObject&gt;::new(<span class="kw-2">&amp;</span>req, <span class="kw-2">&amp;mut </span>pl).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(protobuf.err().unwrap(), ProtoBufPayloadError::ContentType);
<span class="kw">let</span> (<span class="ident">req</span>, <span class="kw-2">mut</span> <span class="ident">pl</span>) <span class="op">=</span> <span class="ident">TestRequest::get</span>()
.<span class="ident">insert_header</span>((<span class="ident">header::CONTENT_TYPE</span>, <span class="string">&quot;application/protobuf&quot;</span>))
.<span class="ident">insert_header</span>((<span class="ident">header::CONTENT_LENGTH</span>, <span class="string">&quot;10000&quot;</span>))
.<span class="ident">to_http_parts</span>();
<span class="kw">let</span> <span class="ident">protobuf</span> <span class="op">=</span> <span class="ident">ProtoBufMessage</span>::<span class="op">&lt;</span><span class="ident">MyObject</span><span class="op">&gt;</span><span class="ident">::new</span>(<span class="kw-2">&amp;</span><span class="ident">req</span>, <span class="kw-2">&amp;mut</span> <span class="ident">pl</span>)
.<span class="ident">limit</span>(<span class="number">100</span>)
<span class="kw">let </span>(req, <span class="kw-2">mut </span>pl) = TestRequest::get()
.insert_header((header::CONTENT_TYPE, <span class="string">&quot;application/protobuf&quot;</span>))
.insert_header((header::CONTENT_LENGTH, <span class="string">&quot;10000&quot;</span>))
.to_http_parts();
<span class="kw">let </span>protobuf = ProtoBufMessage::&lt;MyObject&gt;::new(<span class="kw-2">&amp;</span>req, <span class="kw-2">&amp;mut </span>pl)
.limit(<span class="number">100</span>)
.<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(<span class="ident">protobuf</span>.<span class="ident">err</span>().<span class="ident">unwrap</span>(), <span class="ident">ProtoBufPayloadError::Overflow</span>);
<span class="macro">assert_eq!</span>(protobuf.err().unwrap(), ProtoBufPayloadError::Overflow);
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_protobuf" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_protobuf" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -27,34 +27,34 @@
<span id="27">27</span>
<span id="28">28</span>
<span id="29">29</span>
</pre><pre class="rust"><code><span class="doccomment">//! Redis integration for `actix`.</span>
</pre><pre class="rust"><code><span class="doccomment">//! Redis integration for `actix`.
<span class="attribute">#![<span class="ident">forbid</span>(<span class="ident">unsafe_code</span>)]</span>
<span class="attribute">#![<span class="ident">deny</span>(<span class="ident">rust_2018_idioms</span>, <span class="ident">nonstandard_style</span>)]</span>
<span class="attribute">#![<span class="ident">warn</span>(<span class="ident">future_incompatible</span>)]</span>
</span><span class="attribute">#![forbid(unsafe_code)]
#![deny(rust_2018_idioms, nonstandard_style)]
#![warn(future_incompatible)]
<span class="kw">use</span> <span class="ident">derive_more</span>::{<span class="ident">Display</span>, <span class="ident">Error</span>, <span class="ident">From</span>};
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident">redis_async</span>::{<span class="ident">error::Error</span> <span class="kw">as</span> <span class="ident">RespError</span>, <span class="ident">resp::RespValue</span>, <span class="ident">resp_array</span>};
</span><span class="kw">use </span>derive_more::{Display, Error, From};
<span class="kw">pub use </span>redis_async::{error::Error <span class="kw">as </span>RespError, resp::RespValue, resp_array};
<span class="kw">mod</span> <span class="ident">redis</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::redis</span>::{<span class="ident">Command</span>, <span class="ident">RedisActor</span>};
<span class="kw">mod </span>redis;
<span class="kw">pub use </span><span class="self">self</span>::redis::{Command, RedisActor};
<span class="doccomment">/// General purpose `actix-redis` error.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Display</span>, <span class="ident">Error</span>, <span class="ident">From</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">Error</span> {
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Redis error: {}&quot;</span>, <span class="ident">_0</span>)]</span>
<span class="ident">Redis</span>(<span class="ident">redis_async::error::Error</span>),
<span class="doccomment">/// General purpose `actix-redis` error.
</span><span class="attribute">#[derive(Debug, Display, Error, From)]
</span><span class="kw">pub enum </span>Error {
<span class="attribute">#[display(fmt = <span class="string">&quot;Redis error: {}&quot;</span>, _0)]
</span>Redis(redis_async::error::Error),
<span class="doccomment">/// Receiving message during reconnecting.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Redis: Not connected&quot;</span>)]</span>
<span class="ident">NotConnected</span>,
<span class="doccomment">/// Receiving message during reconnecting.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Redis: Not connected&quot;</span>)]
</span>NotConnected,
<span class="doccomment">/// Cancel all waiters when connection is dropped.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Redis: Disconnected&quot;</span>)]</span>
<span class="ident">Disconnected</span>,
<span class="doccomment">/// Cancel all waiters when connection is dropped.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Redis: Disconnected&quot;</span>)]
</span>Disconnected,
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;web&quot;</span>)]</span>
<span class="kw">impl</span> <span class="ident">actix_web::ResponseError</span> <span class="kw">for</span> <span class="ident">Error</span> {}
<span class="attribute">#[cfg(feature = <span class="string">&quot;web&quot;</span>)]
</span><span class="kw">impl </span>actix_web::ResponseError <span class="kw">for </span>Error {}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_redis" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_redis" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -141,148 +141,148 @@
<span id="141">141</span>
<span id="142">142</span>
<span id="143">143</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">collections::VecDeque</span>, <span class="ident">io</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{collections::VecDeque, io};
<span class="kw">use</span> <span class="ident">actix::prelude</span>::<span class="kw-2">*</span>;
<span class="kw">use</span> <span class="ident">actix_rt::net::TcpStream</span>;
<span class="kw">use</span> <span class="ident">actix_service::boxed</span>::{<span class="self">self</span>, <span class="ident">BoxService</span>};
<span class="kw">use</span> <span class="ident">actix_tls::connect</span>::{<span class="ident">ConnectError</span>, <span class="ident">ConnectInfo</span>, <span class="ident">Connection</span>, <span class="ident">ConnectorService</span>};
<span class="kw">use</span> <span class="ident">backoff</span>::{<span class="ident">backoff::Backoff</span>, <span class="ident">ExponentialBackoff</span>};
<span class="kw">use</span> <span class="ident">log</span>::{<span class="ident">error</span>, <span class="ident">info</span>, <span class="ident">warn</span>};
<span class="kw">use</span> <span class="ident">redis_async</span>::{
<span class="ident">error::Error</span> <span class="kw">as</span> <span class="ident">RespError</span>,
<span class="ident">resp</span>::{<span class="ident">RespCodec</span>, <span class="ident">RespValue</span>},
<span class="kw">use </span>actix::prelude::<span class="kw-2">*</span>;
<span class="kw">use </span>actix_rt::net::TcpStream;
<span class="kw">use </span>actix_service::boxed::{<span class="self">self</span>, BoxService};
<span class="kw">use </span>actix_tls::connect::{ConnectError, ConnectInfo, Connection, ConnectorService};
<span class="kw">use </span>backoff::{backoff::Backoff, ExponentialBackoff};
<span class="kw">use </span>log::{error, info, warn};
<span class="kw">use </span>redis_async::{
error::Error <span class="kw">as </span>RespError,
resp::{RespCodec, RespValue},
};
<span class="kw">use</span> <span class="ident">tokio</span>::{
<span class="ident">io</span>::{<span class="ident">split</span>, <span class="ident">WriteHalf</span>},
<span class="ident">sync::oneshot</span>,
<span class="kw">use </span>tokio::{
io::{split, WriteHalf},
sync::oneshot,
};
<span class="kw">use</span> <span class="ident">tokio_util::codec::FramedRead</span>;
<span class="kw">use </span>tokio_util::codec::FramedRead;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::Error</span>;
<span class="kw">use </span><span class="kw">crate</span>::Error;
<span class="doccomment">/// Command for sending data to Redis.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Command</span>(<span class="kw">pub</span> <span class="ident">RespValue</span>);
<span class="doccomment">/// Command for sending data to Redis.
</span><span class="attribute">#[derive(Debug)]
</span><span class="kw">pub struct </span>Command(<span class="kw">pub </span>RespValue);
<span class="kw">impl</span> <span class="ident">Message</span> <span class="kw">for</span> <span class="ident">Command</span> {
<span class="kw">type</span> <span class="prelude-ty">Result</span> <span class="op">=</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">RespValue</span>, <span class="ident">Error</span><span class="op">&gt;</span>;
<span class="kw">impl </span>Message <span class="kw">for </span>Command {
<span class="kw">type </span><span class="prelude-ty">Result </span>= <span class="prelude-ty">Result</span>&lt;RespValue, Error&gt;;
}
<span class="doccomment">/// Redis communication actor.</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">RedisActor</span> {
<span class="ident">addr</span>: <span class="ident">String</span>,
<span class="ident">connector</span>: <span class="ident">BoxService</span><span class="op">&lt;</span><span class="ident">ConnectInfo</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>, <span class="ident">Connection</span><span class="op">&lt;</span><span class="ident">String</span>, <span class="ident">TcpStream</span><span class="op">&gt;</span>, <span class="ident">ConnectError</span><span class="op">&gt;</span>,
<span class="ident">backoff</span>: <span class="ident">ExponentialBackoff</span>,
<span class="ident">cell</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">actix::io::FramedWrite</span><span class="op">&lt;</span><span class="ident">RespValue</span>, <span class="ident">WriteHalf</span><span class="op">&lt;</span><span class="ident">TcpStream</span><span class="op">&gt;</span>, <span class="ident">RespCodec</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="ident">queue</span>: <span class="ident">VecDeque</span><span class="op">&lt;</span><span class="ident">oneshot::Sender</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">RespValue</span>, <span class="ident">Error</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="doccomment">/// Redis communication actor.
</span><span class="kw">pub struct </span>RedisActor {
addr: String,
connector: BoxService&lt;ConnectInfo&lt;String&gt;, Connection&lt;String, TcpStream&gt;, ConnectError&gt;,
backoff: ExponentialBackoff,
cell: <span class="prelude-ty">Option</span>&lt;actix::io::FramedWrite&lt;RespValue, WriteHalf&lt;TcpStream&gt;, RespCodec&gt;&gt;,
queue: VecDeque&lt;oneshot::Sender&lt;<span class="prelude-ty">Result</span>&lt;RespValue, Error&gt;&gt;&gt;,
}
<span class="kw">impl</span> <span class="ident">RedisActor</span> {
<span class="doccomment">/// Start new `Supervisor` with `RedisActor`.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">start</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span><span class="op">&gt;</span>(<span class="ident">addr</span>: <span class="ident">S</span>) -&gt; <span class="ident">Addr</span><span class="op">&lt;</span><span class="ident">RedisActor</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">addr</span> <span class="op">=</span> <span class="ident">addr</span>.<span class="ident">into</span>();
<span class="kw">impl </span>RedisActor {
<span class="doccomment">/// Start new `Supervisor` with `RedisActor`.
</span><span class="kw">pub fn </span>start&lt;S: Into&lt;String&gt;&gt;(addr: S) -&gt; Addr&lt;RedisActor&gt; {
<span class="kw">let </span>addr = addr.into();
<span class="kw">let</span> <span class="ident">backoff</span> <span class="op">=</span> <span class="ident">ExponentialBackoff</span> {
<span class="ident">max_elapsed_time</span>: <span class="prelude-val">None</span>,
..<span class="ident">Default::default</span>()
<span class="kw">let </span>backoff = ExponentialBackoff {
max_elapsed_time: <span class="prelude-val">None</span>,
..Default::default()
};
<span class="ident">Supervisor::start</span>(<span class="op">|</span><span class="kw">_</span><span class="op">|</span> <span class="ident">RedisActor</span> {
<span class="ident">addr</span>,
<span class="ident">connector</span>: <span class="ident">boxed::service</span>(<span class="ident">ConnectorService::default</span>()),
<span class="ident">cell</span>: <span class="prelude-val">None</span>,
<span class="ident">backoff</span>,
<span class="ident">queue</span>: <span class="ident">VecDeque::new</span>(),
Supervisor::start(|<span class="kw">_</span>| RedisActor {
addr,
connector: boxed::service(ConnectorService::default()),
cell: <span class="prelude-val">None</span>,
backoff,
queue: VecDeque::new(),
})
}
}
<span class="kw">impl</span> <span class="ident">Actor</span> <span class="kw">for</span> <span class="ident">RedisActor</span> {
<span class="kw">type</span> <span class="ident">Context</span> <span class="op">=</span> <span class="ident">Context</span><span class="op">&lt;</span><span class="self">Self</span><span class="op">&gt;</span>;
<span class="kw">impl </span>Actor <span class="kw">for </span>RedisActor {
<span class="kw">type </span>Context = Context&lt;<span class="self">Self</span>&gt;;
<span class="kw">fn</span> <span class="ident">started</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>, <span class="ident">ctx</span>: <span class="kw-2">&amp;mut</span> <span class="ident">Context</span><span class="op">&lt;</span><span class="self">Self</span><span class="op">&gt;</span>) {
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">ConnectInfo::new</span>(<span class="self">self</span>.<span class="ident">addr</span>.<span class="ident">to_owned</span>());
<span class="self">self</span>.<span class="ident">connector</span>
.<span class="ident">call</span>(<span class="ident">req</span>)
.<span class="ident">into_actor</span>(<span class="self">self</span>)
.<span class="ident">map</span>(<span class="op">|</span><span class="ident">res</span>, <span class="ident">act</span>, <span class="ident">ctx</span><span class="op">|</span> <span class="kw">match</span> <span class="ident">res</span> {
<span class="prelude-val">Ok</span>(<span class="ident">conn</span>) =&gt; {
<span class="kw">let</span> <span class="ident">stream</span> <span class="op">=</span> <span class="ident">conn</span>.<span class="ident">into_parts</span>().<span class="number">0</span>;
<span class="macro">info!</span>(<span class="string">&quot;Connected to redis server: {}&quot;</span>, <span class="ident">act</span>.<span class="ident">addr</span>);
<span class="kw">fn </span>started(<span class="kw-2">&amp;mut </span><span class="self">self</span>, ctx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="self">Self</span>&gt;) {
<span class="kw">let </span>req = ConnectInfo::new(<span class="self">self</span>.addr.to_owned());
<span class="self">self</span>.connector
.call(req)
.into_actor(<span class="self">self</span>)
.map(|res, act, ctx| <span class="kw">match </span>res {
<span class="prelude-val">Ok</span>(conn) =&gt; {
<span class="kw">let </span>stream = conn.into_parts().<span class="number">0</span>;
<span class="macro">info!</span>(<span class="string">&quot;Connected to redis server: {}&quot;</span>, act.addr);
<span class="kw">let</span> (<span class="ident">r</span>, <span class="ident">w</span>) <span class="op">=</span> <span class="ident">split</span>(<span class="ident">stream</span>);
<span class="kw">let </span>(r, w) = split(stream);
<span class="comment">// configure write side of the connection</span>
<span class="kw">let</span> <span class="ident">framed</span> <span class="op">=</span> <span class="ident">actix::io::FramedWrite::new</span>(<span class="ident">w</span>, <span class="ident">RespCodec</span>, <span class="ident">ctx</span>);
<span class="ident">act</span>.<span class="ident">cell</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">framed</span>);
<span class="comment">// configure write side of the connection
</span><span class="kw">let </span>framed = actix::io::FramedWrite::new(w, RespCodec, ctx);
act.cell = <span class="prelude-val">Some</span>(framed);
<span class="comment">// read side of the connection</span>
<span class="ident">ctx</span>.<span class="ident">add_stream</span>(<span class="ident">FramedRead::new</span>(<span class="ident">r</span>, <span class="ident">RespCodec</span>));
<span class="comment">// read side of the connection
</span>ctx.add_stream(FramedRead::new(r, RespCodec));
<span class="ident">act</span>.<span class="ident">backoff</span>.<span class="ident">reset</span>();
act.backoff.reset();
}
<span class="prelude-val">Err</span>(<span class="ident">err</span>) =&gt; {
<span class="macro">error!</span>(<span class="string">&quot;Can not connect to redis server: {}&quot;</span>, <span class="ident">err</span>);
<span class="comment">// re-connect with backoff time.</span>
<span class="comment">// we stop current context, supervisor will restart it.</span>
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">timeout</span>) <span class="op">=</span> <span class="ident">act</span>.<span class="ident">backoff</span>.<span class="ident">next_backoff</span>() {
<span class="ident">ctx</span>.<span class="ident">run_later</span>(<span class="ident">timeout</span>, <span class="op">|</span><span class="kw">_</span>, <span class="ident">ctx</span><span class="op">|</span> <span class="ident">ctx</span>.<span class="ident">stop</span>());
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="macro">error!</span>(<span class="string">&quot;Can not connect to redis server: {}&quot;</span>, err);
<span class="comment">// re-connect with backoff time.
// we stop current context, supervisor will restart it.
</span><span class="kw">if let </span><span class="prelude-val">Some</span>(timeout) = act.backoff.next_backoff() {
ctx.run_later(timeout, |<span class="kw">_</span>, ctx| ctx.stop());
}
}
})
.<span class="ident">wait</span>(<span class="ident">ctx</span>);
.wait(ctx);
}
}
<span class="kw">impl</span> <span class="ident">Supervised</span> <span class="kw">for</span> <span class="ident">RedisActor</span> {
<span class="kw">fn</span> <span class="ident">restarting</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>, <span class="kw">_</span>: <span class="kw-2">&amp;mut</span> <span class="ident"><span class="self">Self</span>::Context</span>) {
<span class="self">self</span>.<span class="ident">cell</span>.<span class="ident">take</span>();
<span class="kw">for</span> <span class="ident">tx</span> <span class="kw">in</span> <span class="self">self</span>.<span class="ident">queue</span>.<span class="ident">drain</span>(..) {
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="ident">tx</span>.<span class="ident">send</span>(<span class="prelude-val">Err</span>(<span class="ident">Error::Disconnected</span>));
<span class="kw">impl </span>Supervised <span class="kw">for </span>RedisActor {
<span class="kw">fn </span>restarting(<span class="kw-2">&amp;mut </span><span class="self">self</span>, <span class="kw">_</span>: <span class="kw-2">&amp;mut </span><span class="self">Self</span>::Context) {
<span class="self">self</span>.cell.take();
<span class="kw">for </span>tx <span class="kw">in </span><span class="self">self</span>.queue.drain(..) {
<span class="kw">let _ </span>= tx.send(<span class="prelude-val">Err</span>(Error::Disconnected));
}
}
}
<span class="kw">impl</span> <span class="ident">actix::io::WriteHandler</span><span class="op">&lt;</span><span class="ident">io::Error</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">RedisActor</span> {
<span class="kw">fn</span> <span class="ident">error</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>, <span class="ident">err</span>: <span class="ident">io::Error</span>, <span class="kw">_</span>: <span class="kw-2">&amp;mut</span> <span class="ident"><span class="self">Self</span>::Context</span>) -&gt; <span class="ident">Running</span> {
<span class="macro">warn!</span>(<span class="string">&quot;Redis connection dropped: {} error: {}&quot;</span>, <span class="self">self</span>.<span class="ident">addr</span>, <span class="ident">err</span>);
<span class="ident">Running::Stop</span>
<span class="kw">impl </span>actix::io::WriteHandler&lt;io::Error&gt; <span class="kw">for </span>RedisActor {
<span class="kw">fn </span>error(<span class="kw-2">&amp;mut </span><span class="self">self</span>, err: io::Error, <span class="kw">_</span>: <span class="kw-2">&amp;mut </span><span class="self">Self</span>::Context) -&gt; Running {
<span class="macro">warn!</span>(<span class="string">&quot;Redis connection dropped: {} error: {}&quot;</span>, <span class="self">self</span>.addr, err);
Running::Stop
}
}
<span class="kw">impl</span> <span class="ident">StreamHandler</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">RespValue</span>, <span class="ident">RespError</span><span class="op">&gt;</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">RedisActor</span> {
<span class="kw">fn</span> <span class="ident">handle</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>, <span class="ident">msg</span>: <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">RespValue</span>, <span class="ident">RespError</span><span class="op">&gt;</span>, <span class="ident">ctx</span>: <span class="kw-2">&amp;mut</span> <span class="ident"><span class="self">Self</span>::Context</span>) {
<span class="kw">match</span> <span class="ident">msg</span> {
<span class="prelude-val">Err</span>(<span class="ident">e</span>) =&gt; {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">tx</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">queue</span>.<span class="ident">pop_front</span>() {
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="ident">tx</span>.<span class="ident">send</span>(<span class="prelude-val">Err</span>(<span class="ident">e</span>.<span class="ident">into</span>()));
<span class="kw">impl </span>StreamHandler&lt;<span class="prelude-ty">Result</span>&lt;RespValue, RespError&gt;&gt; <span class="kw">for </span>RedisActor {
<span class="kw">fn </span>handle(<span class="kw-2">&amp;mut </span><span class="self">self</span>, msg: <span class="prelude-ty">Result</span>&lt;RespValue, RespError&gt;, ctx: <span class="kw-2">&amp;mut </span><span class="self">Self</span>::Context) {
<span class="kw">match </span>msg {
<span class="prelude-val">Err</span>(e) =&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(tx) = <span class="self">self</span>.queue.pop_front() {
<span class="kw">let _ </span>= tx.send(<span class="prelude-val">Err</span>(e.into()));
}
<span class="ident">ctx</span>.<span class="ident">stop</span>();
ctx.stop();
}
<span class="prelude-val">Ok</span>(<span class="ident">val</span>) =&gt; {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">tx</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">queue</span>.<span class="ident">pop_front</span>() {
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="ident">tx</span>.<span class="ident">send</span>(<span class="prelude-val">Ok</span>(<span class="ident">val</span>));
<span class="prelude-val">Ok</span>(val) =&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(tx) = <span class="self">self</span>.queue.pop_front() {
<span class="kw">let _ </span>= tx.send(<span class="prelude-val">Ok</span>(val));
}
}
}
}
}
<span class="kw">impl</span> <span class="ident">Handler</span><span class="op">&lt;</span><span class="ident">Command</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">RedisActor</span> {
<span class="kw">type</span> <span class="prelude-ty">Result</span> <span class="op">=</span> <span class="ident">ResponseFuture</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">RespValue</span>, <span class="ident">Error</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">impl </span>Handler&lt;Command&gt; <span class="kw">for </span>RedisActor {
<span class="kw">type </span><span class="prelude-ty">Result </span>= ResponseFuture&lt;<span class="prelude-ty">Result</span>&lt;RespValue, Error&gt;&gt;;
<span class="kw">fn</span> <span class="ident">handle</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>, <span class="ident">msg</span>: <span class="ident">Command</span>, <span class="kw">_</span>: <span class="kw-2">&amp;mut</span> <span class="ident"><span class="self">Self</span>::Context</span>) -&gt; <span class="ident"><span class="self">Self</span>::Result</span> {
<span class="kw">let</span> (<span class="ident">tx</span>, <span class="ident">rx</span>) <span class="op">=</span> <span class="ident">oneshot::channel</span>();
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="kw-2">mut</span> <span class="ident">cell</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">cell</span> {
<span class="self">self</span>.<span class="ident">queue</span>.<span class="ident">push_back</span>(<span class="ident">tx</span>);
<span class="ident">cell</span>.<span class="ident">write</span>(<span class="ident">msg</span>.<span class="number">0</span>);
} <span class="kw">else</span> {
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="ident">tx</span>.<span class="ident">send</span>(<span class="prelude-val">Err</span>(<span class="ident">Error::NotConnected</span>));
<span class="kw">fn </span>handle(<span class="kw-2">&amp;mut </span><span class="self">self</span>, msg: Command, <span class="kw">_</span>: <span class="kw-2">&amp;mut </span><span class="self">Self</span>::Context) -&gt; <span class="self">Self</span>::Result {
<span class="kw">let </span>(tx, rx) = oneshot::channel();
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref mut </span>cell) = <span class="self">self</span>.cell {
<span class="self">self</span>.queue.push_back(tx);
cell.write(msg.<span class="number">0</span>);
} <span class="kw">else </span>{
<span class="kw">let _ </span>= tx.send(<span class="prelude-val">Err</span>(Error::NotConnected));
}
<span class="ident">Box::pin</span>(<span class="kw">async</span> <span class="kw">move</span> { <span class="ident">rx</span>.<span class="kw">await</span>.<span class="ident">map_err</span>(<span class="op">|</span><span class="kw">_</span><span class="op">|</span> <span class="ident">Error::Disconnected</span>)<span class="question-mark">?</span> })
Box::pin(<span class="kw">async move </span>{ rx.<span class="kw">await</span>.map_err(|<span class="kw">_</span>| Error::Disconnected)<span class="question-mark">? </span>})
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_redis" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_redis" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -396,401 +396,401 @@
<span id="394">394</span>
<span id="395">395</span>
<span id="396">396</span>
</pre><pre class="rust"><code><span class="doccomment">//! Configuration options to tune the behaviour of [`SessionMiddleware`].</span>
</pre><pre class="rust"><code><span class="doccomment">//! Configuration options to tune the behaviour of [`SessionMiddleware`].
<span class="kw">use</span> <span class="ident">actix_web::cookie</span>::{<span class="ident">time::Duration</span>, <span class="ident">Key</span>, <span class="ident">SameSite</span>};
<span class="kw">use</span> <span class="ident">derive_more::From</span>;
</span><span class="kw">use </span>actix_web::cookie::{time::Duration, Key, SameSite};
<span class="kw">use </span>derive_more::From;
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">storage::SessionStore</span>, <span class="ident">SessionMiddleware</span>};
<span class="kw">use crate</span>::{storage::SessionStore, SessionMiddleware};
<span class="doccomment">/// Determines what type of session cookie should be used and how its lifecycle should be managed.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Used by [`SessionMiddlewareBuilder::session_lifecycle`].</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">From</span>)]</span>
<span class="attribute">#[<span class="ident">non_exhaustive</span>]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">SessionLifecycle</span> {
<span class="doccomment">/// The session cookie will expire when the current browser session ends.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// When does a browser session end? It depends on the browser! Chrome, for example, will often</span>
<span class="doccomment">/// continue running in the background when the browser is closed—session cookies are not</span>
<span class="doccomment">/// deleted and they will still be available when the browser is opened again.</span>
<span class="doccomment">/// Check the documentation of the browsers you are targeting for up-to-date information.</span>
<span class="ident">BrowserSession</span>(<span class="ident">BrowserSession</span>),
<span class="doccomment">/// Determines what type of session cookie should be used and how its lifecycle should be managed.
///
/// Used by [`SessionMiddlewareBuilder::session_lifecycle`].
</span><span class="attribute">#[derive(Debug, Clone, From)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>SessionLifecycle {
<span class="doccomment">/// The session cookie will expire when the current browser session ends.
///
/// When does a browser session end? It depends on the browser! Chrome, for example, will often
/// continue running in the background when the browser is closed—session cookies are not
/// deleted and they will still be available when the browser is opened again.
/// Check the documentation of the browsers you are targeting for up-to-date information.
</span>BrowserSession(BrowserSession),
<span class="doccomment">/// The session cookie will be a [persistent cookie].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Persistent cookies have a pre-determined lifetime, specified via the `Max-Age` or `Expires`</span>
<span class="doccomment">/// attribute. They do not disappear when the current browser session ends.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [persistent cookie]: https://www.whitehatsec.com/glossary/content/persistent-session-cookie</span>
<span class="ident">PersistentSession</span>(<span class="ident">PersistentSession</span>),
<span class="doccomment">/// The session cookie will be a [persistent cookie].
///
/// Persistent cookies have a pre-determined lifetime, specified via the `Max-Age` or `Expires`
/// attribute. They do not disappear when the current browser session ends.
///
/// [persistent cookie]: https://www.whitehatsec.com/glossary/content/persistent-session-cookie
</span>PersistentSession(PersistentSession),
}
<span class="doccomment">/// A [session lifecycle](SessionLifecycle) strategy where the session cookie expires when the</span>
<span class="doccomment">/// browser&#39;s current session ends.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// When does a browser session end? It depends on the browser. Chrome, for example, will often</span>
<span class="doccomment">/// continue running in the background when the browser is closed—session cookies are not deleted</span>
<span class="doccomment">/// and they will still be available when the browser is opened again. Check the documentation of</span>
<span class="doccomment">/// the browsers you are targeting for up-to-date information.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Due to its `Into&lt;SessionLifecycle&gt;` implementation, a `BrowserSession` can be passed directly</span>
<span class="doccomment">/// to [`SessionMiddlewareBuilder::session_lifecycle()`].</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">BrowserSession</span> {
<span class="ident">state_ttl</span>: <span class="ident">Duration</span>,
<span class="ident">state_ttl_extension_policy</span>: <span class="ident">TtlExtensionPolicy</span>,
<span class="doccomment">/// A [session lifecycle](SessionLifecycle) strategy where the session cookie expires when the
/// browser&#39;s current session ends.
///
/// When does a browser session end? It depends on the browser. Chrome, for example, will often
/// continue running in the background when the browser is closed—session cookies are not deleted
/// and they will still be available when the browser is opened again. Check the documentation of
/// the browsers you are targeting for up-to-date information.
///
/// Due to its `Into&lt;SessionLifecycle&gt;` implementation, a `BrowserSession` can be passed directly
/// to [`SessionMiddlewareBuilder::session_lifecycle()`].
</span><span class="attribute">#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>BrowserSession {
state_ttl: Duration,
state_ttl_extension_policy: TtlExtensionPolicy,
}
<span class="kw">impl</span> <span class="ident">BrowserSession</span> {
<span class="doccomment">/// Sets a time-to-live (TTL) when storing the session state in the storage backend.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// We do not want to store session states indefinitely, otherwise we will inevitably run out of</span>
<span class="doccomment">/// storage by holding on to the state of countless abandoned or expired sessions!</span>
<span class="doccomment">///</span>
<span class="doccomment">/// We are dealing with the lifecycle of two uncorrelated object here: the session cookie</span>
<span class="doccomment">/// and the session state. It is not a big issue if the session state outlives the cookie—</span>
<span class="doccomment">/// we are wasting some space in the backend storage, but it will be cleaned up eventually.</span>
<span class="doccomment">/// What happens, instead, if the cookie outlives the session state? A new session starts—</span>
<span class="doccomment">/// e.g. if sessions are being used for authentication, the user is de-facto logged out.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// It is not possible to predict with certainty how long a browser session is going to</span>
<span class="doccomment">/// last—you need to provide a reasonable upper bound. You do so via `state_ttl`—it dictates</span>
<span class="doccomment">/// what TTL should be used for session state when the lifecycle of the session cookie is</span>
<span class="doccomment">/// tied to the browser session length. [`SessionMiddleware`] will default to 1 day if</span>
<span class="doccomment">/// `state_ttl` is left unspecified.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// You can mitigate the risk of the session cookie outliving the session state by</span>
<span class="doccomment">/// specifying a more aggressive state TTL extension policy - check out</span>
<span class="doccomment">/// [`BrowserSession::state_ttl_extension_policy`] for more details.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">state_ttl</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">ttl</span>: <span class="ident">Duration</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">state_ttl</span> <span class="op">=</span> <span class="ident">ttl</span>;
<span class="self">self</span>
}
<span class="kw">impl </span>BrowserSession {
<span class="doccomment">/// Sets a time-to-live (TTL) when storing the session state in the storage backend.
///
/// We do not want to store session states indefinitely, otherwise we will inevitably run out of
/// storage by holding on to the state of countless abandoned or expired sessions!
///
/// We are dealing with the lifecycle of two uncorrelated object here: the session cookie
/// and the session state. It is not a big issue if the session state outlives the cookie—
/// we are wasting some space in the backend storage, but it will be cleaned up eventually.
/// What happens, instead, if the cookie outlives the session state? A new session starts—
/// e.g. if sessions are being used for authentication, the user is de-facto logged out.
///
/// It is not possible to predict with certainty how long a browser session is going to
/// last—you need to provide a reasonable upper bound. You do so via `state_ttl`—it dictates
/// what TTL should be used for session state when the lifecycle of the session cookie is
/// tied to the browser session length. [`SessionMiddleware`] will default to 1 day if
/// `state_ttl` is left unspecified.
///
/// You can mitigate the risk of the session cookie outliving the session state by
/// specifying a more aggressive state TTL extension policy - check out
/// [`BrowserSession::state_ttl_extension_policy`] for more details.
</span><span class="kw">pub fn </span>state_ttl(<span class="kw-2">mut </span><span class="self">self</span>, ttl: Duration) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.state_ttl = ttl;
<span class="self">self
</span>}
<span class="doccomment">/// Determine under what circumstances the TTL of your session state should be extended.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Defaults to [`TtlExtensionPolicy::OnStateChanges`] if left unspecified.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// See [`TtlExtensionPolicy`] for more details.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">state_ttl_extension_policy</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">ttl_extension_policy</span>: <span class="ident">TtlExtensionPolicy</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">state_ttl_extension_policy</span> <span class="op">=</span> <span class="ident">ttl_extension_policy</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Determine under what circumstances the TTL of your session state should be extended.
///
/// Defaults to [`TtlExtensionPolicy::OnStateChanges`] if left unspecified.
///
/// See [`TtlExtensionPolicy`] for more details.
</span><span class="kw">pub fn </span>state_ttl_extension_policy(<span class="kw-2">mut </span><span class="self">self</span>, ttl_extension_policy: TtlExtensionPolicy) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.state_ttl_extension_policy = ttl_extension_policy;
<span class="self">self
</span>}
}
<span class="kw">impl</span> <span class="ident">Default</span> <span class="kw">for</span> <span class="ident">BrowserSession</span> {
<span class="kw">fn</span> <span class="ident">default</span>() -&gt; <span class="self">Self</span> {
<span class="self">Self</span> {
<span class="ident">state_ttl</span>: <span class="ident">default_ttl</span>(),
<span class="ident">state_ttl_extension_policy</span>: <span class="ident">default_ttl_extension_policy</span>(),
<span class="kw">impl </span>Default <span class="kw">for </span>BrowserSession {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{
state_ttl: default_ttl(),
state_ttl_extension_policy: default_ttl_extension_policy(),
}
}
}
<span class="doccomment">/// A [session lifecycle](SessionLifecycle) strategy where the session cookie will be [persistent].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Persistent cookies have a pre-determined expiration, specified via the `Max-Age` or `Expires`</span>
<span class="doccomment">/// attribute. They do not disappear when the current browser session ends.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Due to its `Into&lt;SessionLifecycle&gt;` implementation, a `PersistentSession` can be passed directly</span>
<span class="doccomment">/// to [`SessionMiddlewareBuilder::session_lifecycle()`].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_web::cookie::time::Duration;</span>
<span class="doccomment">/// use actix_session::SessionMiddleware;</span>
<span class="doccomment">/// use actix_session::config::{PersistentSession, TtlExtensionPolicy};</span>
<span class="doccomment">///</span>
<span class="doccomment">/// const SECS_IN_WEEK: i64 = 60 * 60 * 24 * 7;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// // a session lifecycle with a time-to-live (expiry) of 1 week and default extension policy</span>
<span class="doccomment">/// PersistentSession::default().session_ttl(Duration::seconds(SECS_IN_WEEK));</span>
<span class="doccomment">///</span>
<span class="doccomment">/// // a session lifecycle with the default time-to-live (expiry) and a custom extension policy</span>
<span class="doccomment">/// PersistentSession::default()</span>
<span class="doccomment">/// // this policy causes the session state&#39;s TTL to be refreshed on every request</span>
<span class="doccomment">/// .session_ttl_extension_policy(TtlExtensionPolicy::OnEveryRequest);</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [persistent]: https://www.whitehatsec.com/glossary/content/persistent-session-cookie</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">PersistentSession</span> {
<span class="ident">session_ttl</span>: <span class="ident">Duration</span>,
<span class="ident">ttl_extension_policy</span>: <span class="ident">TtlExtensionPolicy</span>,
<span class="doccomment">/// A [session lifecycle](SessionLifecycle) strategy where the session cookie will be [persistent].
///
/// Persistent cookies have a pre-determined expiration, specified via the `Max-Age` or `Expires`
/// attribute. They do not disappear when the current browser session ends.
///
/// Due to its `Into&lt;SessionLifecycle&gt;` implementation, a `PersistentSession` can be passed directly
/// to [`SessionMiddlewareBuilder::session_lifecycle()`].
///
/// # Examples
/// ```
/// use actix_web::cookie::time::Duration;
/// use actix_session::SessionMiddleware;
/// use actix_session::config::{PersistentSession, TtlExtensionPolicy};
///
/// const SECS_IN_WEEK: i64 = 60 * 60 * 24 * 7;
///
/// // a session lifecycle with a time-to-live (expiry) of 1 week and default extension policy
/// PersistentSession::default().session_ttl(Duration::seconds(SECS_IN_WEEK));
///
/// // a session lifecycle with the default time-to-live (expiry) and a custom extension policy
/// PersistentSession::default()
/// // this policy causes the session state&#39;s TTL to be refreshed on every request
/// .session_ttl_extension_policy(TtlExtensionPolicy::OnEveryRequest);
/// ```
///
/// [persistent]: https://www.whitehatsec.com/glossary/content/persistent-session-cookie
</span><span class="attribute">#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>PersistentSession {
session_ttl: Duration,
ttl_extension_policy: TtlExtensionPolicy,
}
<span class="kw">impl</span> <span class="ident">PersistentSession</span> {
<span class="doccomment">/// Specifies how long the session cookie should live.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// The session TTL is also used as the TTL for the session state in the storage backend.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Defaults to 1 day.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// A persistent session can live more than the specified TTL if the TTL is extended.</span>
<span class="doccomment">/// See [`session_ttl_extension_policy`](Self::session_ttl_extension_policy) for more details.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">session_ttl</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">session_ttl</span>: <span class="ident">Duration</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">session_ttl</span> <span class="op">=</span> <span class="ident">session_ttl</span>;
<span class="self">self</span>
}
<span class="kw">impl </span>PersistentSession {
<span class="doccomment">/// Specifies how long the session cookie should live.
///
/// The session TTL is also used as the TTL for the session state in the storage backend.
///
/// Defaults to 1 day.
///
/// A persistent session can live more than the specified TTL if the TTL is extended.
/// See [`session_ttl_extension_policy`](Self::session_ttl_extension_policy) for more details.
</span><span class="kw">pub fn </span>session_ttl(<span class="kw-2">mut </span><span class="self">self</span>, session_ttl: Duration) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.session_ttl = session_ttl;
<span class="self">self
</span>}
<span class="doccomment">/// Determines under what circumstances the TTL of your session should be extended.</span>
<span class="doccomment">/// See [`TtlExtensionPolicy`] for more details.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Defaults to [`TtlExtensionPolicy::OnStateChanges`].</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">session_ttl_extension_policy</span>(
<span class="kw-2">mut</span> <span class="self">self</span>,
<span class="ident">ttl_extension_policy</span>: <span class="ident">TtlExtensionPolicy</span>,
) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">ttl_extension_policy</span> <span class="op">=</span> <span class="ident">ttl_extension_policy</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Determines under what circumstances the TTL of your session should be extended.
/// See [`TtlExtensionPolicy`] for more details.
///
/// Defaults to [`TtlExtensionPolicy::OnStateChanges`].
</span><span class="kw">pub fn </span>session_ttl_extension_policy(
<span class="kw-2">mut </span><span class="self">self</span>,
ttl_extension_policy: TtlExtensionPolicy,
) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.ttl_extension_policy = ttl_extension_policy;
<span class="self">self
</span>}
}
<span class="kw">impl</span> <span class="ident">Default</span> <span class="kw">for</span> <span class="ident">PersistentSession</span> {
<span class="kw">fn</span> <span class="ident">default</span>() -&gt; <span class="self">Self</span> {
<span class="self">Self</span> {
<span class="ident">session_ttl</span>: <span class="ident">default_ttl</span>(),
<span class="ident">ttl_extension_policy</span>: <span class="ident">default_ttl_extension_policy</span>(),
<span class="kw">impl </span>Default <span class="kw">for </span>PersistentSession {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{
session_ttl: default_ttl(),
ttl_extension_policy: default_ttl_extension_policy(),
}
}
}
<span class="doccomment">/// Configuration for which events should trigger an extension of the time-to-live for your session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If you are using a [`BrowserSession`], `TtlExtensionPolicy` controls how often the TTL of the</span>
<span class="doccomment">/// session state should be refreshed. The browser is in control of the lifecycle of the session</span>
<span class="doccomment">/// cookie.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If you are using a [`PersistentSession`], `TtlExtensionPolicy` controls both the expiration of</span>
<span class="doccomment">/// the session cookie and the TTL of the session state on the storage backend.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="attribute">#[<span class="ident">non_exhaustive</span>]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">TtlExtensionPolicy</span> {
<span class="doccomment">/// The TTL is refreshed every time the server receives a request associated with a session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Performance impact</span>
<span class="doccomment">/// Refreshing the TTL on every request is not free. It implies a refresh of the TTL on the</span>
<span class="doccomment">/// session state. This translates into a request over the network if you are using a remote</span>
<span class="doccomment">/// system as storage backend (e.g. Redis). This impacts both the total load on your storage</span>
<span class="doccomment">/// backend (i.e. number of queries it has to handle) and the latency of the requests served by</span>
<span class="doccomment">/// your server.</span>
<span class="ident">OnEveryRequest</span>,
<span class="doccomment">/// Configuration for which events should trigger an extension of the time-to-live for your session.
///
/// If you are using a [`BrowserSession`], `TtlExtensionPolicy` controls how often the TTL of the
/// session state should be refreshed. The browser is in control of the lifecycle of the session
/// cookie.
///
/// If you are using a [`PersistentSession`], `TtlExtensionPolicy` controls both the expiration of
/// the session cookie and the TTL of the session state on the storage backend.
</span><span class="attribute">#[derive(Debug, Clone)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>TtlExtensionPolicy {
<span class="doccomment">/// The TTL is refreshed every time the server receives a request associated with a session.
///
/// # Performance impact
/// Refreshing the TTL on every request is not free. It implies a refresh of the TTL on the
/// session state. This translates into a request over the network if you are using a remote
/// system as storage backend (e.g. Redis). This impacts both the total load on your storage
/// backend (i.e. number of queries it has to handle) and the latency of the requests served by
/// your server.
</span>OnEveryRequest,
<span class="doccomment">/// The TTL is refreshed every time the session state changes or the session key is renewed.</span>
<span class="ident">OnStateChanges</span>,
<span class="doccomment">/// The TTL is refreshed every time the session state changes or the session key is renewed.
</span>OnStateChanges,
}
<span class="doccomment">/// Determines how to secure the content of the session cookie.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Used by [`SessionMiddlewareBuilder::cookie_content_security`].</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">Copy</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">CookieContentSecurity</span> {
<span class="doccomment">/// The cookie content is encrypted when using `CookieContentSecurity::Private`.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Encryption guarantees confidentiality and integrity: the client cannot tamper with the</span>
<span class="doccomment">/// cookie content nor decode it, as long as the encryption key remains confidential.</span>
<span class="ident">Private</span>,
<span class="doccomment">/// Determines how to secure the content of the session cookie.
///
/// Used by [`SessionMiddlewareBuilder::cookie_content_security`].
</span><span class="attribute">#[derive(Debug, Clone, Copy)]
</span><span class="kw">pub enum </span>CookieContentSecurity {
<span class="doccomment">/// The cookie content is encrypted when using `CookieContentSecurity::Private`.
///
/// Encryption guarantees confidentiality and integrity: the client cannot tamper with the
/// cookie content nor decode it, as long as the encryption key remains confidential.
</span>Private,
<span class="doccomment">/// The cookie content is signed when using `CookieContentSecurity::Signed`.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Signing guarantees integrity, but it doesn&#39;t ensure confidentiality: the client cannot</span>
<span class="doccomment">/// tamper with the cookie content, but they can read it.</span>
<span class="ident">Signed</span>,
<span class="doccomment">/// The cookie content is signed when using `CookieContentSecurity::Signed`.
///
/// Signing guarantees integrity, but it doesn&#39;t ensure confidentiality: the client cannot
/// tamper with the cookie content, but they can read it.
</span>Signed,
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const</span> <span class="kw">fn</span> <span class="ident">default_ttl</span>() -&gt; <span class="ident">Duration</span> {
<span class="ident">Duration::days</span>(<span class="number">1</span>)
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const fn </span>default_ttl() -&gt; Duration {
Duration::days(<span class="number">1</span>)
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const</span> <span class="kw">fn</span> <span class="ident">default_ttl_extension_policy</span>() -&gt; <span class="ident">TtlExtensionPolicy</span> {
<span class="ident">TtlExtensionPolicy::OnStateChanges</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const fn </span>default_ttl_extension_policy() -&gt; TtlExtensionPolicy {
TtlExtensionPolicy::OnStateChanges
}
<span class="doccomment">/// A fluent, customized [`SessionMiddleware`] builder.</span>
<span class="attribute">#[<span class="ident">must_use</span>]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">SessionMiddlewareBuilder</span><span class="op">&lt;</span><span class="ident">Store</span>: <span class="ident">SessionStore</span><span class="op">&gt;</span> {
<span class="ident">storage_backend</span>: <span class="ident">Store</span>,
<span class="ident">configuration</span>: <span class="ident">Configuration</span>,
<span class="doccomment">/// A fluent, customized [`SessionMiddleware`] builder.
</span><span class="attribute">#[must_use]
</span><span class="kw">pub struct </span>SessionMiddlewareBuilder&lt;Store: SessionStore&gt; {
storage_backend: Store,
configuration: Configuration,
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">Store</span>: <span class="ident">SessionStore</span><span class="op">&gt;</span> <span class="ident">SessionMiddlewareBuilder</span><span class="op">&lt;</span><span class="ident">Store</span><span class="op">&gt;</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">new</span>(<span class="ident">store</span>: <span class="ident">Store</span>, <span class="ident">configuration</span>: <span class="ident">Configuration</span>) -&gt; <span class="self">Self</span> {
<span class="self">Self</span> {
<span class="ident">storage_backend</span>: <span class="ident">store</span>,
<span class="ident">configuration</span>,
<span class="kw">impl</span>&lt;Store: SessionStore&gt; SessionMiddlewareBuilder&lt;Store&gt; {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new(store: Store, configuration: Configuration) -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{
storage_backend: store,
configuration,
}
}
<span class="doccomment">/// Set the name of the cookie used to store the session ID.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Defaults to `id`.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">cookie_name</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">name</span>: <span class="ident">String</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cookie</span>.<span class="ident">name</span> <span class="op">=</span> <span class="ident">name</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Set the name of the cookie used to store the session ID.
///
/// Defaults to `id`.
</span><span class="kw">pub fn </span>cookie_name(<span class="kw-2">mut </span><span class="self">self</span>, name: String) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.configuration.cookie.name = name;
<span class="self">self
</span>}
<span class="doccomment">/// Set the `Secure` attribute for the cookie used to store the session ID.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If the cookie is set as secure, it will only be transmitted when the connection is secure</span>
<span class="doccomment">/// (using `https`).</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Default is `true`.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">cookie_secure</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">secure</span>: <span class="ident">bool</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cookie</span>.<span class="ident">secure</span> <span class="op">=</span> <span class="ident">secure</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Set the `Secure` attribute for the cookie used to store the session ID.
///
/// If the cookie is set as secure, it will only be transmitted when the connection is secure
/// (using `https`).
///
/// Default is `true`.
</span><span class="kw">pub fn </span>cookie_secure(<span class="kw-2">mut </span><span class="self">self</span>, secure: bool) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.configuration.cookie.secure = secure;
<span class="self">self
</span>}
<span class="doccomment">/// Determines what type of session cookie should be used and how its lifecycle should be managed.</span>
<span class="doccomment">/// Check out [`SessionLifecycle`]&#39;s documentation for more details on the available options.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Default is [`SessionLifecycle::BrowserSession`].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_web::cookie::{Key, time::Duration};</span>
<span class="doccomment">/// use actix_session::{SessionMiddleware, config::PersistentSession};</span>
<span class="doccomment">/// use actix_session::storage::CookieSessionStore;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// const SECS_IN_WEEK: i64 = 60 * 60 * 24 * 7;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// // creates a session middleware with a time-to-live (expiry) of 1 week</span>
<span class="doccomment">/// SessionMiddleware::builder(CookieSessionStore::default(), Key::from(&amp;[0; 64]))</span>
<span class="doccomment">/// .session_lifecycle(</span>
<span class="doccomment">/// PersistentSession::default().session_ttl(Duration::seconds(SECS_IN_WEEK))</span>
<span class="doccomment">/// )</span>
<span class="doccomment">/// .build();</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">session_lifecycle</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">SessionLifecycle</span><span class="op">&gt;</span><span class="op">&gt;</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">session_lifecycle</span>: <span class="ident">S</span>) -&gt; <span class="self">Self</span> {
<span class="kw">match</span> <span class="ident">session_lifecycle</span>.<span class="ident">into</span>() {
<span class="ident">SessionLifecycle::BrowserSession</span>(<span class="ident">BrowserSession</span> {
<span class="ident">state_ttl</span>,
<span class="ident">state_ttl_extension_policy</span>,
<span class="doccomment">/// Determines what type of session cookie should be used and how its lifecycle should be managed.
/// Check out [`SessionLifecycle`]&#39;s documentation for more details on the available options.
///
/// Default is [`SessionLifecycle::BrowserSession`].
///
/// # Examples
/// ```
/// use actix_web::cookie::{Key, time::Duration};
/// use actix_session::{SessionMiddleware, config::PersistentSession};
/// use actix_session::storage::CookieSessionStore;
///
/// const SECS_IN_WEEK: i64 = 60 * 60 * 24 * 7;
///
/// // creates a session middleware with a time-to-live (expiry) of 1 week
/// SessionMiddleware::builder(CookieSessionStore::default(), Key::from(&amp;[0; 64]))
/// .session_lifecycle(
/// PersistentSession::default().session_ttl(Duration::seconds(SECS_IN_WEEK))
/// )
/// .build();
/// ```
</span><span class="kw">pub fn </span>session_lifecycle&lt;S: Into&lt;SessionLifecycle&gt;&gt;(<span class="kw-2">mut </span><span class="self">self</span>, session_lifecycle: S) -&gt; <span class="self">Self </span>{
<span class="kw">match </span>session_lifecycle.into() {
SessionLifecycle::BrowserSession(BrowserSession {
state_ttl,
state_ttl_extension_policy,
}) =&gt; {
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cookie</span>.<span class="ident">max_age</span> <span class="op">=</span> <span class="prelude-val">None</span>;
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">session</span>.<span class="ident">state_ttl</span> <span class="op">=</span> <span class="ident">state_ttl</span>;
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">ttl_extension_policy</span> <span class="op">=</span> <span class="ident">state_ttl_extension_policy</span>;
<span class="self">self</span>.configuration.cookie.max_age = <span class="prelude-val">None</span>;
<span class="self">self</span>.configuration.session.state_ttl = state_ttl;
<span class="self">self</span>.configuration.ttl_extension_policy = state_ttl_extension_policy;
}
<span class="ident">SessionLifecycle::PersistentSession</span>(<span class="ident">PersistentSession</span> {
<span class="ident">session_ttl</span>,
<span class="ident">ttl_extension_policy</span>,
SessionLifecycle::PersistentSession(PersistentSession {
session_ttl,
ttl_extension_policy,
}) =&gt; {
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cookie</span>.<span class="ident">max_age</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">session_ttl</span>);
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">session</span>.<span class="ident">state_ttl</span> <span class="op">=</span> <span class="ident">session_ttl</span>;
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">ttl_extension_policy</span> <span class="op">=</span> <span class="ident">ttl_extension_policy</span>;
<span class="self">self</span>.configuration.cookie.max_age = <span class="prelude-val">Some</span>(session_ttl);
<span class="self">self</span>.configuration.session.state_ttl = session_ttl;
<span class="self">self</span>.configuration.ttl_extension_policy = ttl_extension_policy;
}
}
<span class="self">self</span>
}
<span class="self">self
</span>}
<span class="doccomment">/// Set the `SameSite` attribute for the cookie used to store the session ID.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// By default, the attribute is set to `Lax`.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">cookie_same_site</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">same_site</span>: <span class="ident">SameSite</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cookie</span>.<span class="ident">same_site</span> <span class="op">=</span> <span class="ident">same_site</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Set the `SameSite` attribute for the cookie used to store the session ID.
///
/// By default, the attribute is set to `Lax`.
</span><span class="kw">pub fn </span>cookie_same_site(<span class="kw-2">mut </span><span class="self">self</span>, same_site: SameSite) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.configuration.cookie.same_site = same_site;
<span class="self">self
</span>}
<span class="doccomment">/// Set the `Path` attribute for the cookie used to store the session ID.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// By default, the attribute is set to `/`.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">cookie_path</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">path</span>: <span class="ident">String</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cookie</span>.<span class="ident">path</span> <span class="op">=</span> <span class="ident">path</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Set the `Path` attribute for the cookie used to store the session ID.
///
/// By default, the attribute is set to `/`.
</span><span class="kw">pub fn </span>cookie_path(<span class="kw-2">mut </span><span class="self">self</span>, path: String) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.configuration.cookie.path = path;
<span class="self">self
</span>}
<span class="doccomment">/// Set the `Domain` attribute for the cookie used to store the session ID.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Use `None` to leave the attribute unspecified. If unspecified, the attribute defaults</span>
<span class="doccomment">/// to the same host that set the cookie, excluding subdomains.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// By default, the attribute is left unspecified.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">cookie_domain</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">domain</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cookie</span>.<span class="ident">domain</span> <span class="op">=</span> <span class="ident">domain</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Set the `Domain` attribute for the cookie used to store the session ID.
///
/// Use `None` to leave the attribute unspecified. If unspecified, the attribute defaults
/// to the same host that set the cookie, excluding subdomains.
///
/// By default, the attribute is left unspecified.
</span><span class="kw">pub fn </span>cookie_domain(<span class="kw-2">mut </span><span class="self">self</span>, domain: <span class="prelude-ty">Option</span>&lt;String&gt;) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.configuration.cookie.domain = domain;
<span class="self">self
</span>}
<span class="doccomment">/// Choose how the session cookie content should be secured.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// - [`CookieContentSecurity::Private`] selects encrypted cookie content.</span>
<span class="doccomment">/// - [`CookieContentSecurity::Signed`] selects signed cookie content.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Default</span>
<span class="doccomment">/// By default, the cookie content is encrypted. Encrypted was chosen instead of signed as</span>
<span class="doccomment">/// default because it reduces the chances of sensitive information being exposed in the session</span>
<span class="doccomment">/// key by accident, regardless of [`SessionStore`] implementation you chose to use.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// For example, if you are using cookie-based storage, you definitely want the cookie content</span>
<span class="doccomment">/// to be encrypted—the whole session state is embedded in the cookie! If you are using</span>
<span class="doccomment">/// Redis-based storage, signed is more than enough - the cookie content is just a unique</span>
<span class="doccomment">/// tamper-proof session key.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">cookie_content_security</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">content_security</span>: <span class="ident">CookieContentSecurity</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cookie</span>.<span class="ident">content_security</span> <span class="op">=</span> <span class="ident">content_security</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Choose how the session cookie content should be secured.
///
/// - [`CookieContentSecurity::Private`] selects encrypted cookie content.
/// - [`CookieContentSecurity::Signed`] selects signed cookie content.
///
/// # Default
/// By default, the cookie content is encrypted. Encrypted was chosen instead of signed as
/// default because it reduces the chances of sensitive information being exposed in the session
/// key by accident, regardless of [`SessionStore`] implementation you chose to use.
///
/// For example, if you are using cookie-based storage, you definitely want the cookie content
/// to be encrypted—the whole session state is embedded in the cookie! If you are using
/// Redis-based storage, signed is more than enough - the cookie content is just a unique
/// tamper-proof session key.
</span><span class="kw">pub fn </span>cookie_content_security(<span class="kw-2">mut </span><span class="self">self</span>, content_security: CookieContentSecurity) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.configuration.cookie.content_security = content_security;
<span class="self">self
</span>}
<span class="doccomment">/// Set the `HttpOnly` attribute for the cookie used to store the session ID.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If the cookie is set as `HttpOnly`, it will not be visible to any JavaScript snippets</span>
<span class="doccomment">/// running in the browser.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Default is `true`.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">cookie_http_only</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">http_only</span>: <span class="ident">bool</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cookie</span>.<span class="ident">http_only</span> <span class="op">=</span> <span class="ident">http_only</span>;
<span class="self">self</span>
}
<span class="doccomment">/// Set the `HttpOnly` attribute for the cookie used to store the session ID.
///
/// If the cookie is set as `HttpOnly`, it will not be visible to any JavaScript snippets
/// running in the browser.
///
/// Default is `true`.
</span><span class="kw">pub fn </span>cookie_http_only(<span class="kw-2">mut </span><span class="self">self</span>, http_only: bool) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.configuration.cookie.http_only = http_only;
<span class="self">self
</span>}
<span class="doccomment">/// Finalise the builder and return a [`SessionMiddleware`] instance.</span>
<span class="attribute">#[<span class="ident">must_use</span>]</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">build</span>(<span class="self">self</span>) -&gt; <span class="ident">SessionMiddleware</span><span class="op">&lt;</span><span class="ident">Store</span><span class="op">&gt;</span> {
<span class="ident">SessionMiddleware::from_parts</span>(<span class="self">self</span>.<span class="ident">storage_backend</span>, <span class="self">self</span>.<span class="ident">configuration</span>)
<span class="doccomment">/// Finalise the builder and return a [`SessionMiddleware`] instance.
</span><span class="attribute">#[must_use]
</span><span class="kw">pub fn </span>build(<span class="self">self</span>) -&gt; SessionMiddleware&lt;Store&gt; {
SessionMiddleware::from_parts(<span class="self">self</span>.storage_backend, <span class="self">self</span>.configuration)
}
}
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Clone</span>)]</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct</span> <span class="ident">Configuration</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">cookie</span>: <span class="ident">CookieConfiguration</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">session</span>: <span class="ident">SessionConfiguration</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">ttl_extension_policy</span>: <span class="ident">TtlExtensionPolicy</span>,
<span class="attribute">#[derive(Clone)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>Configuration {
<span class="kw">pub</span>(<span class="kw">crate</span>) cookie: CookieConfiguration,
<span class="kw">pub</span>(<span class="kw">crate</span>) session: SessionConfiguration,
<span class="kw">pub</span>(<span class="kw">crate</span>) ttl_extension_policy: TtlExtensionPolicy,
}
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Clone</span>)]</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct</span> <span class="ident">SessionConfiguration</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">state_ttl</span>: <span class="ident">Duration</span>,
<span class="attribute">#[derive(Clone)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>SessionConfiguration {
<span class="kw">pub</span>(<span class="kw">crate</span>) state_ttl: Duration,
}
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Clone</span>)]</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct</span> <span class="ident">CookieConfiguration</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">secure</span>: <span class="ident">bool</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">http_only</span>: <span class="ident">bool</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">name</span>: <span class="ident">String</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">same_site</span>: <span class="ident">SameSite</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">path</span>: <span class="ident">String</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">domain</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">max_age</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Duration</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">content_security</span>: <span class="ident">CookieContentSecurity</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">key</span>: <span class="ident">Key</span>,
<span class="attribute">#[derive(Clone)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>CookieConfiguration {
<span class="kw">pub</span>(<span class="kw">crate</span>) secure: bool,
<span class="kw">pub</span>(<span class="kw">crate</span>) http_only: bool,
<span class="kw">pub</span>(<span class="kw">crate</span>) name: String,
<span class="kw">pub</span>(<span class="kw">crate</span>) same_site: SameSite,
<span class="kw">pub</span>(<span class="kw">crate</span>) path: String,
<span class="kw">pub</span>(<span class="kw">crate</span>) domain: <span class="prelude-ty">Option</span>&lt;String&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) max_age: <span class="prelude-ty">Option</span>&lt;Duration&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) content_security: CookieContentSecurity,
<span class="kw">pub</span>(<span class="kw">crate</span>) key: Key,
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">default_configuration</span>(<span class="ident">key</span>: <span class="ident">Key</span>) -&gt; <span class="ident">Configuration</span> {
<span class="ident">Configuration</span> {
<span class="ident">cookie</span>: <span class="ident">CookieConfiguration</span> {
<span class="ident">secure</span>: <span class="bool-val">true</span>,
<span class="ident">http_only</span>: <span class="bool-val">true</span>,
<span class="ident">name</span>: <span class="string">&quot;id&quot;</span>.<span class="ident">into</span>(),
<span class="ident">same_site</span>: <span class="ident">SameSite::Lax</span>,
<span class="ident">path</span>: <span class="string">&quot;/&quot;</span>.<span class="ident">into</span>(),
<span class="ident">domain</span>: <span class="prelude-val">None</span>,
<span class="ident">max_age</span>: <span class="prelude-val">None</span>,
<span class="ident">content_security</span>: <span class="ident">CookieContentSecurity::Private</span>,
<span class="ident">key</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>default_configuration(key: Key) -&gt; Configuration {
Configuration {
cookie: CookieConfiguration {
secure: <span class="bool-val">true</span>,
http_only: <span class="bool-val">true</span>,
name: <span class="string">&quot;id&quot;</span>.into(),
same_site: SameSite::Lax,
path: <span class="string">&quot;/&quot;</span>.into(),
domain: <span class="prelude-val">None</span>,
max_age: <span class="prelude-val">None</span>,
content_security: CookieContentSecurity::Private,
key,
},
<span class="ident">session</span>: <span class="ident">SessionConfiguration</span> {
<span class="ident">state_ttl</span>: <span class="ident">default_ttl</span>(),
session: SessionConfiguration {
state_ttl: default_ttl(),
},
<span class="ident">ttl_extension_policy</span>: <span class="ident">default_ttl_extension_policy</span>(),
ttl_extension_policy: default_ttl_extension_policy(),
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

File diff suppressed because it is too large Load Diff

View File

@@ -463,313 +463,313 @@
<span id="461">461</span>
<span id="462">462</span>
<span id="463">463</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">collections::HashMap</span>, <span class="ident">convert::TryInto</span>, <span class="ident">fmt</span>, <span class="ident">future::Future</span>, <span class="ident">pin::Pin</span>, <span class="ident">rc::Rc</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{collections::HashMap, convert::TryInto, fmt, future::Future, pin::Pin, rc::Rc};
<span class="kw">use</span> <span class="ident">actix_utils::future</span>::{<span class="ident">ready</span>, <span class="ident">Ready</span>};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">body::MessageBody</span>,
<span class="ident">cookie</span>::{<span class="ident">Cookie</span>, <span class="ident">CookieJar</span>, <span class="ident">Key</span>},
<span class="ident">dev</span>::{<span class="ident">forward_ready</span>, <span class="ident">ResponseHead</span>, <span class="ident">Service</span>, <span class="ident">ServiceRequest</span>, <span class="ident">ServiceResponse</span>, <span class="ident">Transform</span>},
<span class="ident">http::header</span>::{<span class="ident">HeaderValue</span>, <span class="ident">SET_COOKIE</span>},
<span class="ident">HttpResponse</span>,
<span class="kw">use </span>actix_utils::future::{ready, Ready};
<span class="kw">use </span>actix_web::{
body::MessageBody,
cookie::{Cookie, CookieJar, Key},
dev::{forward_ready, ResponseHead, Service, ServiceRequest, ServiceResponse, Transform},
http::header::{HeaderValue, SET_COOKIE},
HttpResponse,
};
<span class="kw">use</span> <span class="ident">anyhow::Context</span>;
<span class="kw">use </span>anyhow::Context;
<span class="kw">use</span> <span class="kw">crate</span>::{
<span class="ident">config</span>::{
<span class="self">self</span>, <span class="ident">Configuration</span>, <span class="ident">CookieConfiguration</span>, <span class="ident">CookieContentSecurity</span>, <span class="ident">SessionMiddlewareBuilder</span>,
<span class="ident">TtlExtensionPolicy</span>,
<span class="kw">use crate</span>::{
config::{
<span class="self">self</span>, Configuration, CookieConfiguration, CookieContentSecurity, SessionMiddlewareBuilder,
TtlExtensionPolicy,
},
<span class="ident">storage</span>::{<span class="ident">LoadError</span>, <span class="ident">SessionKey</span>, <span class="ident">SessionStore</span>},
<span class="ident">Session</span>, <span class="ident">SessionStatus</span>,
storage::{LoadError, SessionKey, SessionStore},
Session, SessionStatus,
};
<span class="doccomment">/// A middleware for session management in Actix Web applications.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`SessionMiddleware`] takes care of a few jobs:</span>
<span class="doccomment">///</span>
<span class="doccomment">/// - Instructs the session storage backend to create/update/delete/retrieve the state attached to</span>
<span class="doccomment">/// a session according to its status and the operations that have been performed against it;</span>
<span class="doccomment">/// - Set/remove a cookie, on the client side, to enable a user to be consistently associated with</span>
<span class="doccomment">/// the same session across multiple HTTP requests.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Use [`SessionMiddleware::new`] to initialize the session framework using the default parameters.</span>
<span class="doccomment">/// To create a new instance of [`SessionMiddleware`] you need to provide:</span>
<span class="doccomment">///</span>
<span class="doccomment">/// - an instance of the session storage backend you wish to use (i.e. an implementation of</span>
<span class="doccomment">/// [`SessionStore`]);</span>
<span class="doccomment">/// - a secret key, to sign or encrypt the content of client-side session cookie.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # How did we choose defaults?</span>
<span class="doccomment">/// You should not regret adding `actix-session` to your dependencies and going to production using</span>
<span class="doccomment">/// the default configuration. That is why, when in doubt, we opt to use the most secure option for</span>
<span class="doccomment">/// each configuration parameter.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// We expose knobs to change the default to suit your needs—i.e., if you know what you are doing,</span>
<span class="doccomment">/// we will not stop you. But being a subject-matter expert should not be a requirement to deploy</span>
<span class="doccomment">/// reasonably secure implementation of sessions.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```no_run</span>
<span class="doccomment">/// use actix_web::{web, App, HttpServer, HttpResponse, Error};</span>
<span class="doccomment">/// use actix_session::{Session, SessionMiddleware, storage::RedisActorSessionStore};</span>
<span class="doccomment">/// use actix_web::cookie::Key;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// // The secret key would usually be read from a configuration file/environment variables.</span>
<span class="doccomment">/// fn get_secret_key() -&gt; Key {</span>
<span class="doccomment">/// # todo!()</span>
<span class="doccomment">/// // [...]</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[actix_web::main]</span>
<span class="doccomment">/// async fn main() -&gt; std::io::Result&lt;()&gt; {</span>
<span class="doccomment">/// let secret_key = get_secret_key();</span>
<span class="doccomment">/// let redis_connection_string = &quot;127.0.0.1:6379&quot;;</span>
<span class="doccomment">/// HttpServer::new(move ||</span>
<span class="doccomment">/// App::new()</span>
<span class="doccomment">/// // Add session management to your application using Redis for session state storage</span>
<span class="doccomment">/// .wrap(</span>
<span class="doccomment">/// SessionMiddleware::new(</span>
<span class="doccomment">/// RedisActorSessionStore::new(redis_connection_string),</span>
<span class="doccomment">/// secret_key.clone()</span>
<span class="doccomment">/// )</span>
<span class="doccomment">/// )</span>
<span class="doccomment">/// .default_service(web::to(|| HttpResponse::Ok())))</span>
<span class="doccomment">/// .bind((&quot;127.0.0.1&quot;, 8080))?</span>
<span class="doccomment">/// .run()</span>
<span class="doccomment">/// .await</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If you want to customise use [`builder`](Self::builder) instead of [`new`](Self::new):</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ```no_run</span>
<span class="doccomment">/// use actix_web::{App, cookie::{Key, time}, Error, HttpResponse, HttpServer, web};</span>
<span class="doccomment">/// use actix_session::{Session, SessionMiddleware, storage::RedisActorSessionStore};</span>
<span class="doccomment">/// use actix_session::config::PersistentSession;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// // The secret key would usually be read from a configuration file/environment variables.</span>
<span class="doccomment">/// fn get_secret_key() -&gt; Key {</span>
<span class="doccomment">/// # todo!()</span>
<span class="doccomment">/// // [...]</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[actix_web::main]</span>
<span class="doccomment">/// async fn main() -&gt; std::io::Result&lt;()&gt; {</span>
<span class="doccomment">/// let secret_key = get_secret_key();</span>
<span class="doccomment">/// let redis_connection_string = &quot;127.0.0.1:6379&quot;;</span>
<span class="doccomment">/// HttpServer::new(move ||</span>
<span class="doccomment">/// App::new()</span>
<span class="doccomment">/// // Customise session length!</span>
<span class="doccomment">/// .wrap(</span>
<span class="doccomment">/// SessionMiddleware::builder(</span>
<span class="doccomment">/// RedisActorSessionStore::new(redis_connection_string),</span>
<span class="doccomment">/// secret_key.clone()</span>
<span class="doccomment">/// )</span>
<span class="doccomment">/// .session_lifecycle(</span>
<span class="doccomment">/// PersistentSession::default()</span>
<span class="doccomment">/// .session_ttl(time::Duration::days(5))</span>
<span class="doccomment">/// )</span>
<span class="doccomment">/// .build(),</span>
<span class="doccomment">/// )</span>
<span class="doccomment">/// .default_service(web::to(|| HttpResponse::Ok())))</span>
<span class="doccomment">/// .bind((&quot;127.0.0.1&quot;, 8080))?</span>
<span class="doccomment">/// .run()</span>
<span class="doccomment">/// .await</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">SessionMiddleware</span><span class="op">&lt;</span><span class="ident">Store</span>: <span class="ident">SessionStore</span><span class="op">&gt;</span> {
<span class="ident">storage_backend</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">Store</span><span class="op">&gt;</span>,
<span class="ident">configuration</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">Configuration</span><span class="op">&gt;</span>,
<span class="doccomment">/// A middleware for session management in Actix Web applications.
///
/// [`SessionMiddleware`] takes care of a few jobs:
///
/// - Instructs the session storage backend to create/update/delete/retrieve the state attached to
/// a session according to its status and the operations that have been performed against it;
/// - Set/remove a cookie, on the client side, to enable a user to be consistently associated with
/// the same session across multiple HTTP requests.
///
/// Use [`SessionMiddleware::new`] to initialize the session framework using the default parameters.
/// To create a new instance of [`SessionMiddleware`] you need to provide:
///
/// - an instance of the session storage backend you wish to use (i.e. an implementation of
/// [`SessionStore`]);
/// - a secret key, to sign or encrypt the content of client-side session cookie.
///
/// # How did we choose defaults?
/// You should not regret adding `actix-session` to your dependencies and going to production using
/// the default configuration. That is why, when in doubt, we opt to use the most secure option for
/// each configuration parameter.
///
/// We expose knobs to change the default to suit your needs—i.e., if you know what you are doing,
/// we will not stop you. But being a subject-matter expert should not be a requirement to deploy
/// reasonably secure implementation of sessions.
///
/// # Examples
/// ```no_run
/// use actix_web::{web, App, HttpServer, HttpResponse, Error};
/// use actix_session::{Session, SessionMiddleware, storage::RedisActorSessionStore};
/// use actix_web::cookie::Key;
///
/// // The secret key would usually be read from a configuration file/environment variables.
/// fn get_secret_key() -&gt; Key {
/// # todo!()
/// // [...]
/// }
///
/// #[actix_web::main]
/// async fn main() -&gt; std::io::Result&lt;()&gt; {
/// let secret_key = get_secret_key();
/// let redis_connection_string = &quot;127.0.0.1:6379&quot;;
/// HttpServer::new(move ||
/// App::new()
/// // Add session management to your application using Redis for session state storage
/// .wrap(
/// SessionMiddleware::new(
/// RedisActorSessionStore::new(redis_connection_string),
/// secret_key.clone()
/// )
/// )
/// .default_service(web::to(|| HttpResponse::Ok())))
/// .bind((&quot;127.0.0.1&quot;, 8080))?
/// .run()
/// .await
/// }
/// ```
///
/// If you want to customise use [`builder`](Self::builder) instead of [`new`](Self::new):
///
/// ```no_run
/// use actix_web::{App, cookie::{Key, time}, Error, HttpResponse, HttpServer, web};
/// use actix_session::{Session, SessionMiddleware, storage::RedisActorSessionStore};
/// use actix_session::config::PersistentSession;
///
/// // The secret key would usually be read from a configuration file/environment variables.
/// fn get_secret_key() -&gt; Key {
/// # todo!()
/// // [...]
/// }
///
/// #[actix_web::main]
/// async fn main() -&gt; std::io::Result&lt;()&gt; {
/// let secret_key = get_secret_key();
/// let redis_connection_string = &quot;127.0.0.1:6379&quot;;
/// HttpServer::new(move ||
/// App::new()
/// // Customise session length!
/// .wrap(
/// SessionMiddleware::builder(
/// RedisActorSessionStore::new(redis_connection_string),
/// secret_key.clone()
/// )
/// .session_lifecycle(
/// PersistentSession::default()
/// .session_ttl(time::Duration::days(5))
/// )
/// .build(),
/// )
/// .default_service(web::to(|| HttpResponse::Ok())))
/// .bind((&quot;127.0.0.1&quot;, 8080))?
/// .run()
/// .await
/// }
/// ```
</span><span class="attribute">#[derive(Clone)]
</span><span class="kw">pub struct </span>SessionMiddleware&lt;Store: SessionStore&gt; {
storage_backend: Rc&lt;Store&gt;,
configuration: Rc&lt;Configuration&gt;,
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">Store</span>: <span class="ident">SessionStore</span><span class="op">&gt;</span> <span class="ident">SessionMiddleware</span><span class="op">&lt;</span><span class="ident">Store</span><span class="op">&gt;</span> {
<span class="doccomment">/// Use [`SessionMiddleware::new`] to initialize the session framework using the default</span>
<span class="doccomment">/// parameters.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// To create a new instance of [`SessionMiddleware`] you need to provide:</span>
<span class="doccomment">/// - an instance of the session storage backend you wish to use (i.e. an implementation of</span>
<span class="doccomment">/// [`SessionStore`]);</span>
<span class="doccomment">/// - a secret key, to sign or encrypt the content of client-side session cookie.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">new</span>(<span class="ident">store</span>: <span class="ident">Store</span>, <span class="ident">key</span>: <span class="ident">Key</span>) -&gt; <span class="self">Self</span> {
<span class="ident"><span class="self">Self</span>::builder</span>(<span class="ident">store</span>, <span class="ident">key</span>).<span class="ident">build</span>()
<span class="kw">impl</span>&lt;Store: SessionStore&gt; SessionMiddleware&lt;Store&gt; {
<span class="doccomment">/// Use [`SessionMiddleware::new`] to initialize the session framework using the default
/// parameters.
///
/// To create a new instance of [`SessionMiddleware`] you need to provide:
/// - an instance of the session storage backend you wish to use (i.e. an implementation of
/// [`SessionStore`]);
/// - a secret key, to sign or encrypt the content of client-side session cookie.
</span><span class="kw">pub fn </span>new(store: Store, key: Key) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::builder(store, key).build()
}
<span class="doccomment">/// A fluent API to configure [`SessionMiddleware`].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// It takes as input the two required inputs to create a new instance of [`SessionMiddleware`]:</span>
<span class="doccomment">/// - an instance of the session storage backend you wish to use (i.e. an implementation of</span>
<span class="doccomment">/// [`SessionStore`]);</span>
<span class="doccomment">/// - a secret key, to sign or encrypt the content of client-side session cookie.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">builder</span>(<span class="ident">store</span>: <span class="ident">Store</span>, <span class="ident">key</span>: <span class="ident">Key</span>) -&gt; <span class="ident">SessionMiddlewareBuilder</span><span class="op">&lt;</span><span class="ident">Store</span><span class="op">&gt;</span> {
<span class="ident">SessionMiddlewareBuilder::new</span>(<span class="ident">store</span>, <span class="ident">config::default_configuration</span>(<span class="ident">key</span>))
<span class="doccomment">/// A fluent API to configure [`SessionMiddleware`].
///
/// It takes as input the two required inputs to create a new instance of [`SessionMiddleware`]:
/// - an instance of the session storage backend you wish to use (i.e. an implementation of
/// [`SessionStore`]);
/// - a secret key, to sign or encrypt the content of client-side session cookie.
</span><span class="kw">pub fn </span>builder(store: Store, key: Key) -&gt; SessionMiddlewareBuilder&lt;Store&gt; {
SessionMiddlewareBuilder::new(store, config::default_configuration(key))
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">from_parts</span>(<span class="ident">store</span>: <span class="ident">Store</span>, <span class="ident">configuration</span>: <span class="ident">Configuration</span>) -&gt; <span class="self">Self</span> {
<span class="self">Self</span> {
<span class="ident">storage_backend</span>: <span class="ident">Rc::new</span>(<span class="ident">store</span>),
<span class="ident">configuration</span>: <span class="ident">Rc::new</span>(<span class="ident">configuration</span>),
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>from_parts(store: Store, configuration: Configuration) -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{
storage_backend: Rc::new(store),
configuration: Rc::new(configuration),
}
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">B</span>, <span class="ident">Store</span><span class="op">&gt;</span> <span class="ident">Transform</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">ServiceRequest</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">SessionMiddleware</span><span class="op">&lt;</span><span class="ident">Store</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">S</span>: <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>, <span class="ident">Error</span> <span class="op">=</span> <span class="ident">actix_web::Error</span><span class="op">&gt;</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">S::Future</span>: <span class="lifetime">&#39;static</span>,
<span class="ident">B</span>: <span class="ident">MessageBody</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">Store</span>: <span class="ident">SessionStore</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="kw">impl</span>&lt;S, B, Store&gt; Transform&lt;S, ServiceRequest&gt; <span class="kw">for </span>SessionMiddleware&lt;Store&gt;
<span class="kw">where
</span>S: Service&lt;ServiceRequest, Response = ServiceResponse&lt;B&gt;, Error = actix_web::Error&gt; + <span class="lifetime">&#39;static</span>,
S::Future: <span class="lifetime">&#39;static</span>,
B: MessageBody + <span class="lifetime">&#39;static</span>,
Store: SessionStore + <span class="lifetime">&#39;static</span>,
{
<span class="kw">type</span> <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">actix_web::Error</span>;
<span class="kw">type</span> <span class="ident">Transform</span> <span class="op">=</span> <span class="ident">InnerSessionMiddleware</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">Store</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">InitError</span> <span class="op">=</span> ();
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">Ready</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Transform</span>, <span class="ident"><span class="self">Self</span>::InitError</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type </span>Response = ServiceResponse&lt;B&gt;;
<span class="kw">type </span>Error = actix_web::Error;
<span class="kw">type </span>Transform = InnerSessionMiddleware&lt;S, Store&gt;;
<span class="kw">type </span>InitError = ();
<span class="kw">type </span>Future = Ready&lt;<span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Transform, <span class="self">Self</span>::InitError&gt;&gt;;
<span class="kw">fn</span> <span class="ident">new_transform</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">service</span>: <span class="ident">S</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="ident">ready</span>(<span class="prelude-val">Ok</span>(<span class="ident">InnerSessionMiddleware</span> {
<span class="ident">service</span>: <span class="ident">Rc::new</span>(<span class="ident">service</span>),
<span class="ident">configuration</span>: <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">configuration</span>),
<span class="ident">storage_backend</span>: <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">storage_backend</span>),
<span class="kw">fn </span>new_transform(<span class="kw-2">&amp;</span><span class="self">self</span>, service: S) -&gt; <span class="self">Self</span>::Future {
ready(<span class="prelude-val">Ok</span>(InnerSessionMiddleware {
service: Rc::new(service),
configuration: Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.configuration),
storage_backend: Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.storage_backend),
}))
}
}
<span class="doccomment">/// Short-hand to create an `actix_web::Error` instance that will result in an `Internal Server</span>
<span class="doccomment">/// Error` response while preserving the error root cause (e.g. in logs).</span>
<span class="kw">fn</span> <span class="ident">e500</span><span class="op">&lt;</span><span class="ident">E</span>: <span class="ident">fmt::Debug</span> <span class="op">+</span> <span class="ident">fmt::Display</span> <span class="op">+</span> <span class="lifetime">&#39;static</span><span class="op">&gt;</span>(<span class="ident">err</span>: <span class="ident">E</span>) -&gt; <span class="ident">actix_web::Error</span> {
<span class="comment">// We do not use `actix_web::error::ErrorInternalServerError` because we do not want to</span>
<span class="comment">// leak internal implementation details to the caller.</span>
<span class="comment">//</span>
<span class="comment">// `actix_web::error::ErrorInternalServerError` includes the error Display representation</span>
<span class="comment">// as body of the error responses, leading to messages like &quot;There was an issue persisting</span>
<span class="comment">// the session state&quot; reaching API clients. We don&#39;t want that, we want opaque 500s.</span>
<span class="ident">actix_web::error::InternalError::from_response</span>(
<span class="ident">err</span>,
<span class="ident">HttpResponse::InternalServerError</span>().<span class="ident">finish</span>(),
<span class="doccomment">/// Short-hand to create an `actix_web::Error` instance that will result in an `Internal Server
/// Error` response while preserving the error root cause (e.g. in logs).
</span><span class="kw">fn </span>e500&lt;E: fmt::Debug + fmt::Display + <span class="lifetime">&#39;static</span>&gt;(err: E) -&gt; actix_web::Error {
<span class="comment">// We do not use `actix_web::error::ErrorInternalServerError` because we do not want to
// leak internal implementation details to the caller.
//
// `actix_web::error::ErrorInternalServerError` includes the error Display representation
// as body of the error responses, leading to messages like &quot;There was an issue persisting
// the session state&quot; reaching API clients. We don&#39;t want that, we want opaque 500s.
</span>actix_web::error::InternalError::from_response(
err,
HttpResponse::InternalServerError().finish(),
)
.<span class="ident">into</span>()
.into()
}
<span class="attribute">#[<span class="ident">doc</span>(<span class="ident">hidden</span>)]</span>
<span class="attribute">#[<span class="ident">non_exhaustive</span>]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">InnerSessionMiddleware</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">Store</span>: <span class="ident">SessionStore</span> <span class="op">+</span> <span class="lifetime">&#39;static</span><span class="op">&gt;</span> {
<span class="ident">service</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span>,
<span class="ident">configuration</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">Configuration</span><span class="op">&gt;</span>,
<span class="ident">storage_backend</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">Store</span><span class="op">&gt;</span>,
<span class="attribute">#[doc(hidden)]
#[non_exhaustive]
</span><span class="kw">pub struct </span>InnerSessionMiddleware&lt;S, Store: SessionStore + <span class="lifetime">&#39;static</span>&gt; {
service: Rc&lt;S&gt;,
configuration: Rc&lt;Configuration&gt;,
storage_backend: Rc&lt;Store&gt;,
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">B</span>, <span class="ident">Store</span><span class="op">&gt;</span> <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">InnerSessionMiddleware</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">Store</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">S</span>: <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>, <span class="ident">Error</span> <span class="op">=</span> <span class="ident">actix_web::Error</span><span class="op">&gt;</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">S::Future</span>: <span class="lifetime">&#39;static</span>,
<span class="ident">Store</span>: <span class="ident">SessionStore</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="kw">impl</span>&lt;S, B, Store&gt; Service&lt;ServiceRequest&gt; <span class="kw">for </span>InnerSessionMiddleware&lt;S, Store&gt;
<span class="kw">where
</span>S: Service&lt;ServiceRequest, Response = ServiceResponse&lt;B&gt;, Error = actix_web::Error&gt; + <span class="lifetime">&#39;static</span>,
S::Future: <span class="lifetime">&#39;static</span>,
Store: SessionStore + <span class="lifetime">&#39;static</span>,
{
<span class="kw">type</span> <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">actix_web::Error</span>;
<span class="attribute">#[<span class="ident">allow</span>(<span class="ident">clippy::type_complexity</span>)]</span>
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">Pin</span><span class="op">&lt;</span><span class="ident">Box</span><span class="op">&lt;</span><span class="kw">dyn</span> <span class="ident">Future</span><span class="op">&lt;</span><span class="ident">Output</span> <span class="op">=</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Response</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type </span>Response = ServiceResponse&lt;B&gt;;
<span class="kw">type </span>Error = actix_web::Error;
<span class="attribute">#[allow(clippy::type_complexity)]
</span><span class="kw">type </span>Future = Pin&lt;Box&lt;<span class="kw">dyn </span>Future&lt;Output = <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Response, <span class="self">Self</span>::Error&gt;&gt;&gt;&gt;;
<span class="macro">forward_ready!</span>(<span class="ident">service</span>);
<span class="macro">forward_ready!</span>(service);
<span class="kw">fn</span> <span class="ident">call</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw-2">mut</span> <span class="ident">req</span>: <span class="ident">ServiceRequest</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="kw">let</span> <span class="ident">service</span> <span class="op">=</span> <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">service</span>);
<span class="kw">let</span> <span class="ident">storage_backend</span> <span class="op">=</span> <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">storage_backend</span>);
<span class="kw">let</span> <span class="ident">configuration</span> <span class="op">=</span> <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">configuration</span>);
<span class="kw">fn </span>call(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw-2">mut </span>req: ServiceRequest) -&gt; <span class="self">Self</span>::Future {
<span class="kw">let </span>service = Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.service);
<span class="kw">let </span>storage_backend = Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.storage_backend);
<span class="kw">let </span>configuration = Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.configuration);
<span class="ident">Box::pin</span>(<span class="kw">async</span> <span class="kw">move</span> {
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">extract_session_key</span>(<span class="kw-2">&amp;</span><span class="ident">req</span>, <span class="kw-2">&amp;</span><span class="ident">configuration</span>.<span class="ident">cookie</span>);
<span class="kw">let</span> (<span class="ident">session_key</span>, <span class="ident">session_state</span>) <span class="op">=</span>
<span class="ident">load_session_state</span>(<span class="ident">session_key</span>, <span class="ident">storage_backend</span>.<span class="ident">as_ref</span>()).<span class="kw">await</span><span class="question-mark">?</span>;
Box::pin(<span class="kw">async move </span>{
<span class="kw">let </span>session_key = extract_session_key(<span class="kw-2">&amp;</span>req, <span class="kw-2">&amp;</span>configuration.cookie);
<span class="kw">let </span>(session_key, session_state) =
load_session_state(session_key, storage_backend.as_ref()).<span class="kw">await</span><span class="question-mark">?</span>;
<span class="ident">Session::set_session</span>(<span class="kw-2">&amp;mut</span> <span class="ident">req</span>, <span class="ident">session_state</span>);
Session::set_session(<span class="kw-2">&amp;mut </span>req, session_state);
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">res</span> <span class="op">=</span> <span class="ident">service</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span><span class="question-mark">?</span>;
<span class="kw">let</span> (<span class="ident">status</span>, <span class="ident">session_state</span>) <span class="op">=</span> <span class="ident">Session::get_changes</span>(<span class="kw-2">&amp;mut</span> <span class="ident">res</span>);
<span class="kw">let </span><span class="kw-2">mut </span>res = service.call(req).<span class="kw">await</span><span class="question-mark">?</span>;
<span class="kw">let </span>(status, session_state) = Session::get_changes(<span class="kw-2">&amp;mut </span>res);
<span class="kw">match</span> <span class="ident">session_key</span> {
<span class="prelude-val">None</span> =&gt; {
<span class="comment">// we do not create an entry in the session store if there is no state attached</span>
<span class="comment">// to a fresh session</span>
<span class="kw">if</span> <span class="op">!</span><span class="ident">session_state</span>.<span class="ident">is_empty</span>() {
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">storage_backend</span>
.<span class="ident">save</span>(<span class="ident">session_state</span>, <span class="kw-2">&amp;</span><span class="ident">configuration</span>.<span class="ident">session</span>.<span class="ident">state_ttl</span>)
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="ident">e500</span>)<span class="question-mark">?</span>;
<span class="kw">match </span>session_key {
<span class="prelude-val">None </span>=&gt; {
<span class="comment">// we do not create an entry in the session store if there is no state attached
// to a fresh session
</span><span class="kw">if </span>!session_state.is_empty() {
<span class="kw">let </span>session_key = storage_backend
.save(session_state, <span class="kw-2">&amp;</span>configuration.session.state_ttl)
.<span class="kw">await
</span>.map_err(e500)<span class="question-mark">?</span>;
<span class="ident">set_session_cookie</span>(
<span class="ident">res</span>.<span class="ident">response_mut</span>().<span class="ident">head_mut</span>(),
<span class="ident">session_key</span>,
<span class="kw-2">&amp;</span><span class="ident">configuration</span>.<span class="ident">cookie</span>,
set_session_cookie(
res.response_mut().head_mut(),
session_key,
<span class="kw-2">&amp;</span>configuration.cookie,
)
.<span class="ident">map_err</span>(<span class="ident">e500</span>)<span class="question-mark">?</span>;
.map_err(e500)<span class="question-mark">?</span>;
}
}
<span class="prelude-val">Some</span>(<span class="ident">session_key</span>) =&gt; {
<span class="kw">match</span> <span class="ident">status</span> {
<span class="ident">SessionStatus::Changed</span> =&gt; {
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">storage_backend</span>
.<span class="ident">update</span>(
<span class="ident">session_key</span>,
<span class="ident">session_state</span>,
<span class="kw-2">&amp;</span><span class="ident">configuration</span>.<span class="ident">session</span>.<span class="ident">state_ttl</span>,
<span class="prelude-val">Some</span>(session_key) =&gt; {
<span class="kw">match </span>status {
SessionStatus::Changed =&gt; {
<span class="kw">let </span>session_key = storage_backend
.update(
session_key,
session_state,
<span class="kw-2">&amp;</span>configuration.session.state_ttl,
)
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="ident">e500</span>)<span class="question-mark">?</span>;
.<span class="kw">await
</span>.map_err(e500)<span class="question-mark">?</span>;
<span class="ident">set_session_cookie</span>(
<span class="ident">res</span>.<span class="ident">response_mut</span>().<span class="ident">head_mut</span>(),
<span class="ident">session_key</span>,
<span class="kw-2">&amp;</span><span class="ident">configuration</span>.<span class="ident">cookie</span>,
set_session_cookie(
res.response_mut().head_mut(),
session_key,
<span class="kw-2">&amp;</span>configuration.cookie,
)
.<span class="ident">map_err</span>(<span class="ident">e500</span>)<span class="question-mark">?</span>;
.map_err(e500)<span class="question-mark">?</span>;
}
<span class="ident">SessionStatus::Purged</span> =&gt; {
<span class="ident">storage_backend</span>.<span class="ident">delete</span>(<span class="kw-2">&amp;</span><span class="ident">session_key</span>).<span class="kw">await</span>.<span class="ident">map_err</span>(<span class="ident">e500</span>)<span class="question-mark">?</span>;
SessionStatus::Purged =&gt; {
storage_backend.delete(<span class="kw-2">&amp;</span>session_key).<span class="kw">await</span>.map_err(e500)<span class="question-mark">?</span>;
<span class="ident">delete_session_cookie</span>(
<span class="ident">res</span>.<span class="ident">response_mut</span>().<span class="ident">head_mut</span>(),
<span class="kw-2">&amp;</span><span class="ident">configuration</span>.<span class="ident">cookie</span>,
delete_session_cookie(
res.response_mut().head_mut(),
<span class="kw-2">&amp;</span>configuration.cookie,
)
.<span class="ident">map_err</span>(<span class="ident">e500</span>)<span class="question-mark">?</span>;
.map_err(e500)<span class="question-mark">?</span>;
}
<span class="ident">SessionStatus::Renewed</span> =&gt; {
<span class="ident">storage_backend</span>.<span class="ident">delete</span>(<span class="kw-2">&amp;</span><span class="ident">session_key</span>).<span class="kw">await</span>.<span class="ident">map_err</span>(<span class="ident">e500</span>)<span class="question-mark">?</span>;
SessionStatus::Renewed =&gt; {
storage_backend.delete(<span class="kw-2">&amp;</span>session_key).<span class="kw">await</span>.map_err(e500)<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">storage_backend</span>
.<span class="ident">save</span>(<span class="ident">session_state</span>, <span class="kw-2">&amp;</span><span class="ident">configuration</span>.<span class="ident">session</span>.<span class="ident">state_ttl</span>)
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="ident">e500</span>)<span class="question-mark">?</span>;
<span class="kw">let </span>session_key = storage_backend
.save(session_state, <span class="kw-2">&amp;</span>configuration.session.state_ttl)
.<span class="kw">await
</span>.map_err(e500)<span class="question-mark">?</span>;
<span class="ident">set_session_cookie</span>(
<span class="ident">res</span>.<span class="ident">response_mut</span>().<span class="ident">head_mut</span>(),
<span class="ident">session_key</span>,
<span class="kw-2">&amp;</span><span class="ident">configuration</span>.<span class="ident">cookie</span>,
set_session_cookie(
res.response_mut().head_mut(),
session_key,
<span class="kw-2">&amp;</span>configuration.cookie,
)
.<span class="ident">map_err</span>(<span class="ident">e500</span>)<span class="question-mark">?</span>;
.map_err(e500)<span class="question-mark">?</span>;
}
<span class="ident">SessionStatus::Unchanged</span> =&gt; {
<span class="kw">if</span> <span class="macro">matches!</span>(
<span class="ident">configuration</span>.<span class="ident">ttl_extension_policy</span>,
<span class="ident">TtlExtensionPolicy::OnEveryRequest</span>
SessionStatus::Unchanged =&gt; {
<span class="kw">if </span><span class="macro">matches!</span>(
configuration.ttl_extension_policy,
TtlExtensionPolicy::OnEveryRequest
) {
<span class="ident">storage_backend</span>
.<span class="ident">update_ttl</span>(<span class="kw-2">&amp;</span><span class="ident">session_key</span>, <span class="kw-2">&amp;</span><span class="ident">configuration</span>.<span class="ident">session</span>.<span class="ident">state_ttl</span>)
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="ident">e500</span>)<span class="question-mark">?</span>;
storage_backend
.update_ttl(<span class="kw-2">&amp;</span>session_key, <span class="kw-2">&amp;</span>configuration.session.state_ttl)
.<span class="kw">await
</span>.map_err(e500)<span class="question-mark">?</span>;
<span class="kw">if</span> <span class="ident">configuration</span>.<span class="ident">cookie</span>.<span class="ident">max_age</span>.<span class="ident">is_some</span>() {
<span class="ident">set_session_cookie</span>(
<span class="ident">res</span>.<span class="ident">response_mut</span>().<span class="ident">head_mut</span>(),
<span class="ident">session_key</span>,
<span class="kw-2">&amp;</span><span class="ident">configuration</span>.<span class="ident">cookie</span>,
<span class="kw">if </span>configuration.cookie.max_age.is_some() {
set_session_cookie(
res.response_mut().head_mut(),
session_key,
<span class="kw-2">&amp;</span>configuration.cookie,
)
.<span class="ident">map_err</span>(<span class="ident">e500</span>)<span class="question-mark">?</span>;
.map_err(e500)<span class="question-mark">?</span>;
}
}
}
@@ -777,154 +777,154 @@
}
}
<span class="prelude-val">Ok</span>(<span class="ident">res</span>)
<span class="prelude-val">Ok</span>(res)
})
}
}
<span class="doccomment">/// Examines the session cookie attached to the incoming request, if there is one, and tries</span>
<span class="doccomment">/// to extract the session key.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// It returns `None` if there is no session cookie or if the session cookie is considered invalid</span>
<span class="doccomment">/// (e.g., when failing a signature check).</span>
<span class="kw">fn</span> <span class="ident">extract_session_key</span>(<span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">ServiceRequest</span>, <span class="ident">config</span>: <span class="kw-2">&amp;</span><span class="ident">CookieConfiguration</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">SessionKey</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">cookies</span> <span class="op">=</span> <span class="ident">req</span>.<span class="ident">cookies</span>().<span class="ident">ok</span>()<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">session_cookie</span> <span class="op">=</span> <span class="ident">cookies</span>
.<span class="ident">iter</span>()
.<span class="ident">find</span>(<span class="op">|</span><span class="kw-2">&amp;</span><span class="ident">cookie</span><span class="op">|</span> <span class="ident">cookie</span>.<span class="ident">name</span>() <span class="op">==</span> <span class="ident">config</span>.<span class="ident">name</span>)<span class="question-mark">?</span>;
<span class="doccomment">/// Examines the session cookie attached to the incoming request, if there is one, and tries
/// to extract the session key.
///
/// It returns `None` if there is no session cookie or if the session cookie is considered invalid
/// (e.g., when failing a signature check).
</span><span class="kw">fn </span>extract_session_key(req: <span class="kw-2">&amp;</span>ServiceRequest, config: <span class="kw-2">&amp;</span>CookieConfiguration) -&gt; <span class="prelude-ty">Option</span>&lt;SessionKey&gt; {
<span class="kw">let </span>cookies = req.cookies().ok()<span class="question-mark">?</span>;
<span class="kw">let </span>session_cookie = cookies
.iter()
.find(|<span class="kw-2">&amp;</span>cookie| cookie.name() == config.name)<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">jar</span> <span class="op">=</span> <span class="ident">CookieJar::new</span>();
<span class="ident">jar</span>.<span class="ident">add_original</span>(<span class="ident">session_cookie</span>.<span class="ident">clone</span>());
<span class="kw">let </span><span class="kw-2">mut </span>jar = CookieJar::new();
jar.add_original(session_cookie.clone());
<span class="kw">let</span> <span class="ident">verification_result</span> <span class="op">=</span> <span class="kw">match</span> <span class="ident">config</span>.<span class="ident">content_security</span> {
<span class="ident">CookieContentSecurity::Signed</span> =&gt; <span class="ident">jar</span>.<span class="ident">signed</span>(<span class="kw-2">&amp;</span><span class="ident">config</span>.<span class="ident">key</span>).<span class="ident">get</span>(<span class="kw-2">&amp;</span><span class="ident">config</span>.<span class="ident">name</span>),
<span class="ident">CookieContentSecurity::Private</span> =&gt; <span class="ident">jar</span>.<span class="ident">private</span>(<span class="kw-2">&amp;</span><span class="ident">config</span>.<span class="ident">key</span>).<span class="ident">get</span>(<span class="kw-2">&amp;</span><span class="ident">config</span>.<span class="ident">name</span>),
<span class="kw">let </span>verification_result = <span class="kw">match </span>config.content_security {
CookieContentSecurity::Signed =&gt; jar.signed(<span class="kw-2">&amp;</span>config.key).get(<span class="kw-2">&amp;</span>config.name),
CookieContentSecurity::Private =&gt; jar.private(<span class="kw-2">&amp;</span>config.key).get(<span class="kw-2">&amp;</span>config.name),
};
<span class="kw">if</span> <span class="ident">verification_result</span>.<span class="ident">is_none</span>() {
<span class="kw">if </span>verification_result.is_none() {
<span class="macro">tracing::warn!</span>(
<span class="string">&quot;The session cookie attached to the incoming request failed to pass cryptographic \
checks (signature verification/decryption).&quot;</span>
);
checks (signature verification/decryption).&quot;
</span>);
}
<span class="kw">match</span> <span class="ident">verification_result</span><span class="question-mark">?</span>.<span class="ident">value</span>().<span class="ident">to_owned</span>().<span class="ident">try_into</span>() {
<span class="prelude-val">Ok</span>(<span class="ident">session_key</span>) =&gt; <span class="prelude-val">Some</span>(<span class="ident">session_key</span>),
<span class="prelude-val">Err</span>(<span class="ident">err</span>) =&gt; {
<span class="kw">match </span>verification_result<span class="question-mark">?</span>.value().to_owned().try_into() {
<span class="prelude-val">Ok</span>(session_key) =&gt; <span class="prelude-val">Some</span>(session_key),
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="macro">tracing::warn!</span>(
<span class="ident">error</span>.<span class="ident">message</span> <span class="op">=</span> <span class="op">%</span><span class="ident">err</span>,
<span class="ident">error</span>.<span class="ident">cause_chain</span> <span class="op">=</span> <span class="question-mark">?</span><span class="ident">err</span>,
<span class="string">&quot;Invalid session key, ignoring.&quot;</span>
);
error.message = %err,
error.cause_chain = <span class="question-mark">?</span>err,
<span class="string">&quot;Invalid session key, ignoring.&quot;
</span>);
<span class="prelude-val">None</span>
}
<span class="prelude-val">None
</span>}
}
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">load_session_state</span><span class="op">&lt;</span><span class="ident">Store</span>: <span class="ident">SessionStore</span><span class="op">&gt;</span>(
<span class="ident">session_key</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">SessionKey</span><span class="op">&gt;</span>,
<span class="ident">storage_backend</span>: <span class="kw-2">&amp;</span><span class="ident">Store</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(<span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">SessionKey</span><span class="op">&gt;</span>, <span class="ident">HashMap</span><span class="op">&lt;</span><span class="ident">String</span>, <span class="ident">String</span><span class="op">&gt;</span>), <span class="ident">actix_web::Error</span><span class="op">&gt;</span> {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">session_key</span>) <span class="op">=</span> <span class="ident">session_key</span> {
<span class="kw">match</span> <span class="ident">storage_backend</span>.<span class="ident">load</span>(<span class="kw-2">&amp;</span><span class="ident">session_key</span>).<span class="kw">await</span> {
<span class="prelude-val">Ok</span>(<span class="ident">state</span>) =&gt; {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">state</span>) <span class="op">=</span> <span class="ident">state</span> {
<span class="prelude-val">Ok</span>((<span class="prelude-val">Some</span>(<span class="ident">session_key</span>), <span class="ident">state</span>))
} <span class="kw">else</span> {
<span class="comment">// We discard the existing session key given that the state attached to it can</span>
<span class="comment">// no longer be found (e.g. it expired or we suffered some data loss in the</span>
<span class="comment">// storage). Regenerating the session key will trigger the `save` workflow</span>
<span class="comment">// instead of the `update` workflow if the session state is modified during the</span>
<span class="comment">// lifecycle of the current request.</span>
<span class="kw">async fn </span>load_session_state&lt;Store: SessionStore&gt;(
session_key: <span class="prelude-ty">Option</span>&lt;SessionKey&gt;,
storage_backend: <span class="kw-2">&amp;</span>Store,
) -&gt; <span class="prelude-ty">Result</span>&lt;(<span class="prelude-ty">Option</span>&lt;SessionKey&gt;, HashMap&lt;String, String&gt;), actix_web::Error&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(session_key) = session_key {
<span class="kw">match </span>storage_backend.load(<span class="kw-2">&amp;</span>session_key).<span class="kw">await </span>{
<span class="prelude-val">Ok</span>(state) =&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(state) = state {
<span class="prelude-val">Ok</span>((<span class="prelude-val">Some</span>(session_key), state))
} <span class="kw">else </span>{
<span class="comment">// We discard the existing session key given that the state attached to it can
// no longer be found (e.g. it expired or we suffered some data loss in the
// storage). Regenerating the session key will trigger the `save` workflow
// instead of the `update` workflow if the session state is modified during the
// lifecycle of the current request.
<span class="macro">tracing::info!</span>(
</span><span class="macro">tracing::info!</span>(
<span class="string">&quot;No session state has been found for a valid session key, creating a new \
empty session.&quot;</span>
);
empty session.&quot;
</span>);
<span class="prelude-val">Ok</span>((<span class="prelude-val">None</span>, <span class="ident">HashMap::new</span>()))
<span class="prelude-val">Ok</span>((<span class="prelude-val">None</span>, HashMap::new()))
}
}
<span class="prelude-val">Err</span>(<span class="ident">err</span>) =&gt; <span class="kw">match</span> <span class="ident">err</span> {
<span class="ident">LoadError::Deserialization</span>(<span class="ident">err</span>) =&gt; {
<span class="prelude-val">Err</span>(err) =&gt; <span class="kw">match </span>err {
LoadError::Deserialization(err) =&gt; {
<span class="macro">tracing::warn!</span>(
<span class="ident">error</span>.<span class="ident">message</span> <span class="op">=</span> <span class="op">%</span><span class="ident">err</span>,
<span class="ident">error</span>.<span class="ident">cause_chain</span> <span class="op">=</span> <span class="question-mark">?</span><span class="ident">err</span>,
<span class="string">&quot;Invalid session state, creating a new empty session.&quot;</span>
);
error.message = %err,
error.cause_chain = <span class="question-mark">?</span>err,
<span class="string">&quot;Invalid session state, creating a new empty session.&quot;
</span>);
<span class="prelude-val">Ok</span>((<span class="prelude-val">Some</span>(<span class="ident">session_key</span>), <span class="ident">HashMap::new</span>()))
<span class="prelude-val">Ok</span>((<span class="prelude-val">Some</span>(session_key), HashMap::new()))
}
<span class="ident">LoadError::Other</span>(<span class="ident">err</span>) =&gt; <span class="prelude-val">Err</span>(<span class="ident">e500</span>(<span class="ident">err</span>)),
LoadError::Other(err) =&gt; <span class="prelude-val">Err</span>(e500(err)),
},
}
} <span class="kw">else</span> {
<span class="prelude-val">Ok</span>((<span class="prelude-val">None</span>, <span class="ident">HashMap::new</span>()))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>((<span class="prelude-val">None</span>, HashMap::new()))
}
}
<span class="kw">fn</span> <span class="ident">set_session_cookie</span>(
<span class="ident">response</span>: <span class="kw-2">&amp;mut</span> <span class="ident">ResponseHead</span>,
<span class="ident">session_key</span>: <span class="ident">SessionKey</span>,
<span class="ident">config</span>: <span class="kw-2">&amp;</span><span class="ident">CookieConfiguration</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">value</span>: <span class="ident">String</span> <span class="op">=</span> <span class="ident">session_key</span>.<span class="ident">into</span>();
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">cookie</span> <span class="op">=</span> <span class="ident">Cookie::new</span>(<span class="ident">config</span>.<span class="ident">name</span>.<span class="ident">clone</span>(), <span class="ident">value</span>);
<span class="kw">fn </span>set_session_cookie(
response: <span class="kw-2">&amp;mut </span>ResponseHead,
session_key: SessionKey,
config: <span class="kw-2">&amp;</span>CookieConfiguration,
) -&gt; <span class="prelude-ty">Result</span>&lt;(), anyhow::Error&gt; {
<span class="kw">let </span>value: String = session_key.into();
<span class="kw">let </span><span class="kw-2">mut </span>cookie = Cookie::new(config.name.clone(), value);
<span class="ident">cookie</span>.<span class="ident">set_secure</span>(<span class="ident">config</span>.<span class="ident">secure</span>);
<span class="ident">cookie</span>.<span class="ident">set_http_only</span>(<span class="ident">config</span>.<span class="ident">http_only</span>);
<span class="ident">cookie</span>.<span class="ident">set_same_site</span>(<span class="ident">config</span>.<span class="ident">same_site</span>);
<span class="ident">cookie</span>.<span class="ident">set_path</span>(<span class="ident">config</span>.<span class="ident">path</span>.<span class="ident">clone</span>());
cookie.set_secure(config.secure);
cookie.set_http_only(config.http_only);
cookie.set_same_site(config.same_site);
cookie.set_path(config.path.clone());
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">max_age</span>) <span class="op">=</span> <span class="ident">config</span>.<span class="ident">max_age</span> {
<span class="ident">cookie</span>.<span class="ident">set_max_age</span>(<span class="ident">max_age</span>);
<span class="kw">if let </span><span class="prelude-val">Some</span>(max_age) = config.max_age {
cookie.set_max_age(max_age);
}
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="ident">domain</span>) <span class="op">=</span> <span class="ident">config</span>.<span class="ident">domain</span> {
<span class="ident">cookie</span>.<span class="ident">set_domain</span>(<span class="ident">domain</span>.<span class="ident">clone</span>());
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>domain) = config.domain {
cookie.set_domain(domain.clone());
}
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">jar</span> <span class="op">=</span> <span class="ident">CookieJar::new</span>();
<span class="kw">match</span> <span class="ident">config</span>.<span class="ident">content_security</span> {
<span class="ident">CookieContentSecurity::Signed</span> =&gt; <span class="ident">jar</span>.<span class="ident">signed_mut</span>(<span class="kw-2">&amp;</span><span class="ident">config</span>.<span class="ident">key</span>).<span class="ident">add</span>(<span class="ident">cookie</span>),
<span class="ident">CookieContentSecurity::Private</span> =&gt; <span class="ident">jar</span>.<span class="ident">private_mut</span>(<span class="kw-2">&amp;</span><span class="ident">config</span>.<span class="ident">key</span>).<span class="ident">add</span>(<span class="ident">cookie</span>),
<span class="kw">let </span><span class="kw-2">mut </span>jar = CookieJar::new();
<span class="kw">match </span>config.content_security {
CookieContentSecurity::Signed =&gt; jar.signed_mut(<span class="kw-2">&amp;</span>config.key).add(cookie),
CookieContentSecurity::Private =&gt; jar.private_mut(<span class="kw-2">&amp;</span>config.key).add(cookie),
}
<span class="comment">// set cookie</span>
<span class="kw">let</span> <span class="ident">cookie</span> <span class="op">=</span> <span class="ident">jar</span>.<span class="ident">delta</span>().<span class="ident">next</span>().<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">val</span> <span class="op">=</span> <span class="ident">HeaderValue::from_str</span>(<span class="kw-2">&amp;</span><span class="ident">cookie</span>.<span class="ident">encoded</span>().<span class="ident">to_string</span>())
.<span class="ident">context</span>(<span class="string">&quot;Failed to attach a session cookie to the outgoing response&quot;</span>)<span class="question-mark">?</span>;
<span class="comment">// set cookie
</span><span class="kw">let </span>cookie = jar.delta().next().unwrap();
<span class="kw">let </span>val = HeaderValue::from_str(<span class="kw-2">&amp;</span>cookie.encoded().to_string())
.context(<span class="string">&quot;Failed to attach a session cookie to the outgoing response&quot;</span>)<span class="question-mark">?</span>;
<span class="ident">response</span>.<span class="ident">headers_mut</span>().<span class="ident">append</span>(<span class="ident">SET_COOKIE</span>, <span class="ident">val</span>);
response.headers_mut().append(SET_COOKIE, val);
<span class="prelude-val">Ok</span>(())
}
<span class="kw">fn</span> <span class="ident">delete_session_cookie</span>(
<span class="ident">response</span>: <span class="kw-2">&amp;mut</span> <span class="ident">ResponseHead</span>,
<span class="ident">config</span>: <span class="kw-2">&amp;</span><span class="ident">CookieConfiguration</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">removal_cookie</span> <span class="op">=</span> <span class="ident">Cookie::build</span>(<span class="ident">config</span>.<span class="ident">name</span>.<span class="ident">clone</span>(), <span class="string">&quot;&quot;</span>)
.<span class="ident">path</span>(<span class="ident">config</span>.<span class="ident">path</span>.<span class="ident">clone</span>())
.<span class="ident">http_only</span>(<span class="ident">config</span>.<span class="ident">http_only</span>);
<span class="kw">fn </span>delete_session_cookie(
response: <span class="kw-2">&amp;mut </span>ResponseHead,
config: <span class="kw-2">&amp;</span>CookieConfiguration,
) -&gt; <span class="prelude-ty">Result</span>&lt;(), anyhow::Error&gt; {
<span class="kw">let </span>removal_cookie = Cookie::build(config.name.clone(), <span class="string">&quot;&quot;</span>)
.path(config.path.clone())
.http_only(config.http_only);
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">removal_cookie</span> <span class="op">=</span> <span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="ident">domain</span>) <span class="op">=</span> <span class="ident">config</span>.<span class="ident">domain</span> {
<span class="ident">removal_cookie</span>.<span class="ident">domain</span>(<span class="ident">domain</span>)
} <span class="kw">else</span> {
<span class="ident">removal_cookie</span>
<span class="kw">let </span><span class="kw-2">mut </span>removal_cookie = <span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>domain) = config.domain {
removal_cookie.domain(domain)
} <span class="kw">else </span>{
removal_cookie
}
.<span class="ident">finish</span>();
.finish();
<span class="ident">removal_cookie</span>.<span class="ident">make_removal</span>();
removal_cookie.make_removal();
<span class="kw">let</span> <span class="ident">val</span> <span class="op">=</span> <span class="ident">HeaderValue::from_str</span>(<span class="kw-2">&amp;</span><span class="ident">removal_cookie</span>.<span class="ident">to_string</span>())
.<span class="ident">context</span>(<span class="string">&quot;Failed to attach a session removal cookie to the outgoing response&quot;</span>)<span class="question-mark">?</span>;
<span class="ident">response</span>.<span class="ident">headers_mut</span>().<span class="ident">append</span>(<span class="ident">SET_COOKIE</span>, <span class="ident">val</span>);
<span class="kw">let </span>val = HeaderValue::from_str(<span class="kw-2">&amp;</span>removal_cookie.to_string())
.context(<span class="string">&quot;Failed to attach a session removal cookie to the outgoing response&quot;</span>)<span class="question-mark">?</span>;
response.headers_mut().append(SET_COOKIE, val);
<span class="prelude-val">Ok</span>(())
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -324,329 +324,329 @@
<span id="322">322</span>
<span id="323">323</span>
<span id="324">324</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{
<span class="ident">cell</span>::{<span class="ident">Ref</span>, <span class="ident">RefCell</span>},
<span class="ident">collections::HashMap</span>,
<span class="ident">error::Error</span> <span class="kw">as</span> <span class="ident">StdError</span>,
<span class="ident">mem</span>,
<span class="ident">rc::Rc</span>,
</pre><pre class="rust"><code><span class="kw">use </span>std::{
cell::{Ref, RefCell},
collections::HashMap,
error::Error <span class="kw">as </span>StdError,
mem,
rc::Rc,
};
<span class="kw">use</span> <span class="ident">actix_utils::future</span>::{<span class="ident">ready</span>, <span class="ident">Ready</span>};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">body::BoxBody</span>,
<span class="ident">dev</span>::{<span class="ident">Extensions</span>, <span class="ident">Payload</span>, <span class="ident">ServiceRequest</span>, <span class="ident">ServiceResponse</span>},
<span class="ident">error::Error</span>,
<span class="ident">FromRequest</span>, <span class="ident">HttpMessage</span>, <span class="ident">HttpRequest</span>, <span class="ident">HttpResponse</span>, <span class="ident">ResponseError</span>,
<span class="kw">use </span>actix_utils::future::{ready, Ready};
<span class="kw">use </span>actix_web::{
body::BoxBody,
dev::{Extensions, Payload, ServiceRequest, ServiceResponse},
error::Error,
FromRequest, HttpMessage, HttpRequest, HttpResponse, ResponseError,
};
<span class="kw">use</span> <span class="ident">anyhow::Context</span>;
<span class="kw">use</span> <span class="ident">derive_more</span>::{<span class="ident">Display</span>, <span class="ident">From</span>};
<span class="kw">use</span> <span class="ident">serde</span>::{<span class="ident">de::DeserializeOwned</span>, <span class="ident">Serialize</span>};
<span class="kw">use </span>anyhow::Context;
<span class="kw">use </span>derive_more::{Display, From};
<span class="kw">use </span>serde::{de::DeserializeOwned, Serialize};
<span class="doccomment">/// The primary interface to access and modify session state.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`Session`] is an [extractor](#impl-FromRequest)—you can specify it as an input type for your</span>
<span class="doccomment">/// request handlers and it will be automatically extracted from the incoming request.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_session::Session;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// async fn index(session: Session) -&gt; actix_web::Result&lt;&amp;&#39;static str&gt; {</span>
<span class="doccomment">/// // access session data</span>
<span class="doccomment">/// if let Some(count) = session.get::&lt;i32&gt;(&quot;counter&quot;)? {</span>
<span class="doccomment">/// session.insert(&quot;counter&quot;, count + 1)?;</span>
<span class="doccomment">/// } else {</span>
<span class="doccomment">/// session.insert(&quot;counter&quot;, 1)?;</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Ok(&quot;Welcome!&quot;)</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// # actix_web::web::to(index);</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// You can also retrieve a [`Session`] object from an `HttpRequest` or a `ServiceRequest` using</span>
<span class="doccomment">/// [`SessionExt`].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`SessionExt`]: crate::SessionExt</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Session</span>(<span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">RefCell</span><span class="op">&lt;</span><span class="ident">SessionInner</span><span class="op">&gt;</span><span class="op">&gt;</span>);
<span class="doccomment">/// The primary interface to access and modify session state.
///
/// [`Session`] is an [extractor](#impl-FromRequest)—you can specify it as an input type for your
/// request handlers and it will be automatically extracted from the incoming request.
///
/// ```
/// use actix_session::Session;
///
/// async fn index(session: Session) -&gt; actix_web::Result&lt;&amp;&#39;static str&gt; {
/// // access session data
/// if let Some(count) = session.get::&lt;i32&gt;(&quot;counter&quot;)? {
/// session.insert(&quot;counter&quot;, count + 1)?;
/// } else {
/// session.insert(&quot;counter&quot;, 1)?;
/// }
///
/// Ok(&quot;Welcome!&quot;)
/// }
/// # actix_web::web::to(index);
/// ```
///
/// You can also retrieve a [`Session`] object from an `HttpRequest` or a `ServiceRequest` using
/// [`SessionExt`].
///
/// [`SessionExt`]: crate::SessionExt
</span><span class="attribute">#[derive(Clone)]
</span><span class="kw">pub struct </span>Session(Rc&lt;RefCell&lt;SessionInner&gt;&gt;);
<span class="doccomment">/// Status of a [`Session`].</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">SessionStatus</span> {
<span class="doccomment">/// Session state has been updated - the changes will have to be persisted to the backend.</span>
<span class="ident">Changed</span>,
<span class="doccomment">/// Status of a [`Session`].
</span><span class="attribute">#[derive(Debug, Clone, PartialEq, Eq)]
</span><span class="kw">pub enum </span>SessionStatus {
<span class="doccomment">/// Session state has been updated - the changes will have to be persisted to the backend.
</span>Changed,
<span class="doccomment">/// The session has been flagged for deletion - the session cookie will be removed from</span>
<span class="doccomment">/// the client and the session state will be deleted from the session store.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Most operations on the session after it has been marked for deletion will have no effect.</span>
<span class="ident">Purged</span>,
<span class="doccomment">/// The session has been flagged for deletion - the session cookie will be removed from
/// the client and the session state will be deleted from the session store.
///
/// Most operations on the session after it has been marked for deletion will have no effect.
</span>Purged,
<span class="doccomment">/// The session has been flagged for renewal.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// The session key will be regenerated and the time-to-live of the session state will be</span>
<span class="doccomment">/// extended.</span>
<span class="ident">Renewed</span>,
<span class="doccomment">/// The session has been flagged for renewal.
///
/// The session key will be regenerated and the time-to-live of the session state will be
/// extended.
</span>Renewed,
<span class="doccomment">/// The session state has not been modified since its creation/retrieval.</span>
<span class="ident">Unchanged</span>,
<span class="doccomment">/// The session state has not been modified since its creation/retrieval.
</span>Unchanged,
}
<span class="kw">impl</span> <span class="ident">Default</span> <span class="kw">for</span> <span class="ident">SessionStatus</span> {
<span class="kw">fn</span> <span class="ident">default</span>() -&gt; <span class="ident">SessionStatus</span> {
<span class="ident">SessionStatus::Unchanged</span>
<span class="kw">impl </span>Default <span class="kw">for </span>SessionStatus {
<span class="kw">fn </span>default() -&gt; SessionStatus {
SessionStatus::Unchanged
}
}
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Default</span>)]</span>
<span class="kw">struct</span> <span class="ident">SessionInner</span> {
<span class="ident">state</span>: <span class="ident">HashMap</span><span class="op">&lt;</span><span class="ident">String</span>, <span class="ident">String</span><span class="op">&gt;</span>,
<span class="ident">status</span>: <span class="ident">SessionStatus</span>,
<span class="attribute">#[derive(Default)]
</span><span class="kw">struct </span>SessionInner {
state: HashMap&lt;String, String&gt;,
status: SessionStatus,
}
<span class="kw">impl</span> <span class="ident">Session</span> {
<span class="doccomment">/// Get a `value` from the session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// It returns an error if it fails to deserialize as `T` the JSON value associated with `key`.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">get</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">DeserializeOwned</span><span class="op">&gt;</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">key</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>, <span class="ident">SessionGetError</span><span class="op">&gt;</span> {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">val_str</span>) <span class="op">=</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow</span>().<span class="ident">state</span>.<span class="ident">get</span>(<span class="ident">key</span>) {
<span class="kw">impl </span>Session {
<span class="doccomment">/// Get a `value` from the session.
///
/// It returns an error if it fails to deserialize as `T` the JSON value associated with `key`.
</span><span class="kw">pub fn </span>get&lt;T: DeserializeOwned&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, key: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;T&gt;, SessionGetError&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(val_str) = <span class="self">self</span>.<span class="number">0</span>.borrow().state.get(key) {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(
<span class="ident">serde_json::from_str</span>(<span class="ident">val_str</span>)
.<span class="ident">with_context</span>(<span class="op">|</span><span class="op">|</span> {
serde_json::from_str(val_str)
.with_context(|| {
<span class="macro">format!</span>(
<span class="string">&quot;Failed to deserialize the JSON-encoded session data attached to key \
`{}` as a `{}` type&quot;</span>,
<span class="ident">key</span>,
<span class="ident">std::any::type_name</span>::<span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>()
key,
std::any::type_name::&lt;T&gt;()
)
})
.<span class="ident">map_err</span>(<span class="ident">SessionGetError</span>)<span class="question-mark">?</span>,
.map_err(SessionGetError)<span class="question-mark">?</span>,
))
} <span class="kw">else</span> {
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
}
<span class="doccomment">/// Get all raw key-value data from the session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Note that values are JSON encoded.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">entries</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Ref</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span>, <span class="ident">HashMap</span><span class="op">&lt;</span><span class="ident">String</span>, <span class="ident">String</span><span class="op">&gt;</span><span class="op">&gt;</span> {
<span class="ident">Ref::map</span>(<span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow</span>(), <span class="op">|</span><span class="ident">inner</span><span class="op">|</span> <span class="kw-2">&amp;</span><span class="ident">inner</span>.<span class="ident">state</span>)
<span class="doccomment">/// Get all raw key-value data from the session.
///
/// Note that values are JSON encoded.
</span><span class="kw">pub fn </span>entries(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Ref&lt;<span class="lifetime">&#39;_</span>, HashMap&lt;String, String&gt;&gt; {
Ref::map(<span class="self">self</span>.<span class="number">0</span>.borrow(), |inner| <span class="kw-2">&amp;</span>inner.state)
}
<span class="doccomment">/// Returns session status.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">status</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">SessionStatus</span> {
<span class="ident">Ref::map</span>(<span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow</span>(), <span class="op">|</span><span class="ident">inner</span><span class="op">|</span> <span class="kw-2">&amp;</span><span class="ident">inner</span>.<span class="ident">status</span>).<span class="ident">clone</span>()
<span class="doccomment">/// Returns session status.
</span><span class="kw">pub fn </span>status(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SessionStatus {
Ref::map(<span class="self">self</span>.<span class="number">0</span>.borrow(), |inner| <span class="kw-2">&amp;</span>inner.status).clone()
}
<span class="doccomment">/// Inserts a key-value pair into the session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Any serializable value can be used and will be encoded as JSON in session data, hence why</span>
<span class="doccomment">/// only a reference to the value is taken.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// It returns an error if it fails to serialize `value` to JSON.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">insert</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Serialize</span><span class="op">&gt;</span>(
<span class="doccomment">/// Inserts a key-value pair into the session.
///
/// Any serializable value can be used and will be encoded as JSON in session data, hence why
/// only a reference to the value is taken.
///
/// It returns an error if it fails to serialize `value` to JSON.
</span><span class="kw">pub fn </span>insert&lt;T: Serialize&gt;(
<span class="kw-2">&amp;</span><span class="self">self</span>,
<span class="ident">key</span>: <span class="kw">impl</span> <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>,
<span class="ident">value</span>: <span class="ident">T</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">SessionInsertError</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">inner</span> <span class="op">=</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow_mut</span>();
key: <span class="kw">impl </span>Into&lt;String&gt;,
value: T,
) -&gt; <span class="prelude-ty">Result</span>&lt;(), SessionInsertError&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>inner = <span class="self">self</span>.<span class="number">0</span>.borrow_mut();
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">status</span> <span class="op">!</span><span class="op">=</span> <span class="ident">SessionStatus::Purged</span> {
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">status</span> <span class="op">!</span><span class="op">=</span> <span class="ident">SessionStatus::Renewed</span> {
<span class="ident">inner</span>.<span class="ident">status</span> <span class="op">=</span> <span class="ident">SessionStatus::Changed</span>;
<span class="kw">if </span>inner.status != SessionStatus::Purged {
<span class="kw">if </span>inner.status != SessionStatus::Renewed {
inner.status = SessionStatus::Changed;
}
<span class="kw">let</span> <span class="ident">key</span> <span class="op">=</span> <span class="ident">key</span>.<span class="ident">into</span>();
<span class="kw">let</span> <span class="ident">val</span> <span class="op">=</span> <span class="ident">serde_json::to_string</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>)
.<span class="ident">with_context</span>(<span class="op">|</span><span class="op">|</span> {
<span class="kw">let </span>key = key.into();
<span class="kw">let </span>val = serde_json::to_string(<span class="kw-2">&amp;</span>value)
.with_context(|| {
<span class="macro">format!</span>(
<span class="string">&quot;Failed to serialize the provided `{}` type instance as JSON in order to \
attach as session data to the `{}` key&quot;</span>,
<span class="ident">std::any::type_name</span>::<span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>(),
<span class="kw-2">&amp;</span><span class="ident">key</span>
std::any::type_name::&lt;T&gt;(),
<span class="kw-2">&amp;</span>key
)
})
.<span class="ident">map_err</span>(<span class="ident">SessionInsertError</span>)<span class="question-mark">?</span>;
.map_err(SessionInsertError)<span class="question-mark">?</span>;
<span class="ident">inner</span>.<span class="ident">state</span>.<span class="ident">insert</span>(<span class="ident">key</span>, <span class="ident">val</span>);
inner.state.insert(key, val);
}
<span class="prelude-val">Ok</span>(())
}
<span class="doccomment">/// Remove value from the session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If present, the JSON encoded value is returned.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">remove</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">key</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">inner</span> <span class="op">=</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow_mut</span>();
<span class="doccomment">/// Remove value from the session.
///
/// If present, the JSON encoded value is returned.
</span><span class="kw">pub fn </span>remove(<span class="kw-2">&amp;</span><span class="self">self</span>, key: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;String&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>inner = <span class="self">self</span>.<span class="number">0</span>.borrow_mut();
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">status</span> <span class="op">!</span><span class="op">=</span> <span class="ident">SessionStatus::Purged</span> {
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">status</span> <span class="op">!</span><span class="op">=</span> <span class="ident">SessionStatus::Renewed</span> {
<span class="ident">inner</span>.<span class="ident">status</span> <span class="op">=</span> <span class="ident">SessionStatus::Changed</span>;
<span class="kw">if </span>inner.status != SessionStatus::Purged {
<span class="kw">if </span>inner.status != SessionStatus::Renewed {
inner.status = SessionStatus::Changed;
}
<span class="kw">return</span> <span class="ident">inner</span>.<span class="ident">state</span>.<span class="ident">remove</span>(<span class="ident">key</span>);
<span class="kw">return </span>inner.state.remove(key);
}
<span class="prelude-val">None</span>
}
<span class="prelude-val">None
</span>}
<span class="doccomment">/// Remove value from the session and deserialize.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Returns `None` if key was not present in session. Returns `T` if deserialization succeeds,</span>
<span class="doccomment">/// otherwise returns un-deserialized JSON string.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">remove_as</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">DeserializeOwned</span><span class="op">&gt;</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">key</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">T</span>, <span class="ident">String</span><span class="op">&gt;</span><span class="op">&gt;</span> {
<span class="self">self</span>.<span class="ident">remove</span>(<span class="ident">key</span>)
.<span class="ident">map</span>(<span class="op">|</span><span class="ident">val_str</span><span class="op">|</span> <span class="kw">match</span> <span class="ident">serde_json::from_str</span>(<span class="kw-2">&amp;</span><span class="ident">val_str</span>) {
<span class="prelude-val">Ok</span>(<span class="ident">val</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">val</span>),
<span class="prelude-val">Err</span>(<span class="ident">_err</span>) =&gt; {
<span class="doccomment">/// Remove value from the session and deserialize.
///
/// Returns `None` if key was not present in session. Returns `T` if deserialization succeeds,
/// otherwise returns un-deserialized JSON string.
</span><span class="kw">pub fn </span>remove_as&lt;T: DeserializeOwned&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, key: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="prelude-ty">Result</span>&lt;T, String&gt;&gt; {
<span class="self">self</span>.remove(key)
.map(|val_str| <span class="kw">match </span>serde_json::from_str(<span class="kw-2">&amp;</span>val_str) {
<span class="prelude-val">Ok</span>(val) =&gt; <span class="prelude-val">Ok</span>(val),
<span class="prelude-val">Err</span>(_err) =&gt; {
<span class="macro">tracing::debug!</span>(
<span class="string">&quot;Removed value (key: {}) could not be deserialized as {}&quot;</span>,
<span class="ident">key</span>,
<span class="ident">std::any::type_name</span>::<span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>()
key,
std::any::type_name::&lt;T&gt;()
);
<span class="prelude-val">Err</span>(<span class="ident">val_str</span>)
<span class="prelude-val">Err</span>(val_str)
}
})
}
<span class="doccomment">/// Clear the session.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">clear</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">inner</span> <span class="op">=</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow_mut</span>();
<span class="doccomment">/// Clear the session.
</span><span class="kw">pub fn </span>clear(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<span class="kw">let </span><span class="kw-2">mut </span>inner = <span class="self">self</span>.<span class="number">0</span>.borrow_mut();
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">status</span> <span class="op">!</span><span class="op">=</span> <span class="ident">SessionStatus::Purged</span> {
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">status</span> <span class="op">!</span><span class="op">=</span> <span class="ident">SessionStatus::Renewed</span> {
<span class="ident">inner</span>.<span class="ident">status</span> <span class="op">=</span> <span class="ident">SessionStatus::Changed</span>;
<span class="kw">if </span>inner.status != SessionStatus::Purged {
<span class="kw">if </span>inner.status != SessionStatus::Renewed {
inner.status = SessionStatus::Changed;
}
<span class="ident">inner</span>.<span class="ident">state</span>.<span class="ident">clear</span>()
inner.state.clear()
}
}
<span class="doccomment">/// Removes session both client and server side.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">purge</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">inner</span> <span class="op">=</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow_mut</span>();
<span class="ident">inner</span>.<span class="ident">status</span> <span class="op">=</span> <span class="ident">SessionStatus::Purged</span>;
<span class="ident">inner</span>.<span class="ident">state</span>.<span class="ident">clear</span>();
<span class="doccomment">/// Removes session both client and server side.
</span><span class="kw">pub fn </span>purge(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<span class="kw">let </span><span class="kw-2">mut </span>inner = <span class="self">self</span>.<span class="number">0</span>.borrow_mut();
inner.status = SessionStatus::Purged;
inner.state.clear();
}
<span class="doccomment">/// Renews the session key, assigning existing session state to new key.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">renew</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">inner</span> <span class="op">=</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow_mut</span>();
<span class="doccomment">/// Renews the session key, assigning existing session state to new key.
</span><span class="kw">pub fn </span>renew(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<span class="kw">let </span><span class="kw-2">mut </span>inner = <span class="self">self</span>.<span class="number">0</span>.borrow_mut();
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">status</span> <span class="op">!</span><span class="op">=</span> <span class="ident">SessionStatus::Purged</span> {
<span class="ident">inner</span>.<span class="ident">status</span> <span class="op">=</span> <span class="ident">SessionStatus::Renewed</span>;
<span class="kw">if </span>inner.status != SessionStatus::Purged {
inner.status = SessionStatus::Renewed;
}
}
<span class="doccomment">/// Adds the given key-value pairs to the session on the request.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Values that match keys already existing on the session will be overwritten. Values should</span>
<span class="doccomment">/// already be JSON serialized.</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">set_session</span>(
<span class="ident">req</span>: <span class="kw-2">&amp;mut</span> <span class="ident">ServiceRequest</span>,
<span class="ident">data</span>: <span class="kw">impl</span> <span class="ident">IntoIterator</span><span class="op">&lt;</span><span class="ident">Item</span> <span class="op">=</span> (<span class="ident">String</span>, <span class="ident">String</span>)<span class="op">&gt;</span>,
<span class="doccomment">/// Adds the given key-value pairs to the session on the request.
///
/// Values that match keys already existing on the session will be overwritten. Values should
/// already be JSON serialized.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>set_session(
req: <span class="kw-2">&amp;mut </span>ServiceRequest,
data: <span class="kw">impl </span>IntoIterator&lt;Item = (String, String)&gt;,
) {
<span class="kw">let</span> <span class="ident">session</span> <span class="op">=</span> <span class="ident">Session::get_session</span>(<span class="kw-2">&amp;mut</span> <span class="kw-2">*</span><span class="ident">req</span>.<span class="ident">extensions_mut</span>());
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">inner</span> <span class="op">=</span> <span class="ident">session</span>.<span class="number">0</span>.<span class="ident">borrow_mut</span>();
<span class="ident">inner</span>.<span class="ident">state</span>.<span class="ident">extend</span>(<span class="ident">data</span>);
<span class="kw">let </span>session = Session::get_session(<span class="kw-2">&amp;mut *</span>req.extensions_mut());
<span class="kw">let </span><span class="kw-2">mut </span>inner = session.<span class="number">0</span>.borrow_mut();
inner.state.extend(data);
}
<span class="doccomment">/// Returns session status and iterator of key-value pairs of changes.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// This is a destructive operation - the session state is removed from the request extensions</span>
<span class="doccomment">/// typemap, leaving behind a new empty map. It should only be used when the session is being</span>
<span class="doccomment">/// finalised (i.e. in `SessionMiddleware`).</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">get_changes</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>(
<span class="ident">res</span>: <span class="kw-2">&amp;mut</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>,
) -&gt; (<span class="ident">SessionStatus</span>, <span class="ident">HashMap</span><span class="op">&lt;</span><span class="ident">String</span>, <span class="ident">String</span><span class="op">&gt;</span>) {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">s_impl</span>) <span class="op">=</span> <span class="ident">res</span>
.<span class="ident">request</span>()
.<span class="ident">extensions</span>()
.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">RefCell</span><span class="op">&lt;</span><span class="ident">SessionInner</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span>()
<span class="doccomment">/// Returns session status and iterator of key-value pairs of changes.
///
/// This is a destructive operation - the session state is removed from the request extensions
/// typemap, leaving behind a new empty map. It should only be used when the session is being
/// finalised (i.e. in `SessionMiddleware`).
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>get_changes&lt;B&gt;(
res: <span class="kw-2">&amp;mut </span>ServiceResponse&lt;B&gt;,
) -&gt; (SessionStatus, HashMap&lt;String, String&gt;) {
<span class="kw">if let </span><span class="prelude-val">Some</span>(s_impl) = res
.request()
.extensions()
.get::&lt;Rc&lt;RefCell&lt;SessionInner&gt;&gt;&gt;()
{
<span class="kw">let</span> <span class="ident">state</span> <span class="op">=</span> <span class="ident">mem::take</span>(<span class="kw-2">&amp;mut</span> <span class="ident">s_impl</span>.<span class="ident">borrow_mut</span>().<span class="ident">state</span>);
(<span class="ident">s_impl</span>.<span class="ident">borrow</span>().<span class="ident">status</span>.<span class="ident">clone</span>(), <span class="ident">state</span>)
} <span class="kw">else</span> {
(<span class="ident">SessionStatus::Unchanged</span>, <span class="ident">HashMap::new</span>())
<span class="kw">let </span>state = mem::take(<span class="kw-2">&amp;mut </span>s_impl.borrow_mut().state);
(s_impl.borrow().status.clone(), state)
} <span class="kw">else </span>{
(SessionStatus::Unchanged, HashMap::new())
}
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">get_session</span>(<span class="ident">extensions</span>: <span class="kw-2">&amp;mut</span> <span class="ident">Extensions</span>) -&gt; <span class="ident">Session</span> {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">s_impl</span>) <span class="op">=</span> <span class="ident">extensions</span>.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">RefCell</span><span class="op">&lt;</span><span class="ident">SessionInner</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span>() {
<span class="kw">return</span> <span class="ident">Session</span>(<span class="ident">Rc::clone</span>(<span class="ident">s_impl</span>));
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>get_session(extensions: <span class="kw-2">&amp;mut </span>Extensions) -&gt; Session {
<span class="kw">if let </span><span class="prelude-val">Some</span>(s_impl) = extensions.get::&lt;Rc&lt;RefCell&lt;SessionInner&gt;&gt;&gt;() {
<span class="kw">return </span>Session(Rc::clone(s_impl));
}
<span class="kw">let</span> <span class="ident">inner</span> <span class="op">=</span> <span class="ident">Rc::new</span>(<span class="ident">RefCell::new</span>(<span class="ident">SessionInner::default</span>()));
<span class="ident">extensions</span>.<span class="ident">insert</span>(<span class="ident">inner</span>.<span class="ident">clone</span>());
<span class="kw">let </span>inner = Rc::new(RefCell::new(SessionInner::default()));
extensions.insert(inner.clone());
<span class="ident">Session</span>(<span class="ident">inner</span>)
Session(inner)
}
}
<span class="doccomment">/// Extractor implementation for [`Session`]s.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web::*;</span>
<span class="doccomment">/// use actix_session::Session;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[get(&quot;/&quot;)]</span>
<span class="doccomment">/// async fn index(session: Session) -&gt; Result&lt;impl Responder&gt; {</span>
<span class="doccomment">/// // access session data</span>
<span class="doccomment">/// if let Some(count) = session.get::&lt;i32&gt;(&quot;counter&quot;)? {</span>
<span class="doccomment">/// session.insert(&quot;counter&quot;, count + 1)?;</span>
<span class="doccomment">/// } else {</span>
<span class="doccomment">/// session.insert(&quot;counter&quot;, 1)?;</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// let count = session.get::&lt;i32&gt;(&quot;counter&quot;)?.unwrap();</span>
<span class="doccomment">/// Ok(format!(&quot;Counter: {}&quot;, count))</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="kw">impl</span> <span class="ident">FromRequest</span> <span class="kw">for</span> <span class="ident">Session</span> {
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span>;
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">Ready</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">Session</span>, <span class="ident">Error</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="doccomment">/// Extractor implementation for [`Session`]s.
///
/// # Examples
/// ```
/// # use actix_web::*;
/// use actix_session::Session;
///
/// #[get(&quot;/&quot;)]
/// async fn index(session: Session) -&gt; Result&lt;impl Responder&gt; {
/// // access session data
/// if let Some(count) = session.get::&lt;i32&gt;(&quot;counter&quot;)? {
/// session.insert(&quot;counter&quot;, count + 1)?;
/// } else {
/// session.insert(&quot;counter&quot;, 1)?;
/// }
///
/// let count = session.get::&lt;i32&gt;(&quot;counter&quot;)?.unwrap();
/// Ok(format!(&quot;Counter: {}&quot;, count))
/// }
/// ```
</span><span class="kw">impl </span>FromRequest <span class="kw">for </span>Session {
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Future = Ready&lt;<span class="prelude-ty">Result</span>&lt;Session, Error&gt;&gt;;
<span class="attribute">#[<span class="ident">inline</span>]</span>
<span class="kw">fn</span> <span class="ident">from_request</span>(<span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">HttpRequest</span>, <span class="kw">_</span>: <span class="kw-2">&amp;mut</span> <span class="ident">Payload</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="ident">ready</span>(<span class="prelude-val">Ok</span>(<span class="ident">Session::get_session</span>(<span class="kw-2">&amp;mut</span> <span class="kw-2">*</span><span class="ident">req</span>.<span class="ident">extensions_mut</span>())))
<span class="attribute">#[inline]
</span><span class="kw">fn </span>from_request(req: <span class="kw-2">&amp;</span>HttpRequest, <span class="kw">_</span>: <span class="kw-2">&amp;mut </span>Payload) -&gt; <span class="self">Self</span>::Future {
ready(<span class="prelude-val">Ok</span>(Session::get_session(<span class="kw-2">&amp;mut *</span>req.extensions_mut())))
}
}
<span class="doccomment">/// Error returned by [`Session::get`].</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Display</span>, <span class="ident">From</span>)]</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;{}&quot;</span>, <span class="ident">_0</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">SessionGetError</span>(<span class="ident">anyhow::Error</span>);
<span class="doccomment">/// Error returned by [`Session::get`].
</span><span class="attribute">#[derive(Debug, Display, From)]
#[display(fmt = <span class="string">&quot;{}&quot;</span>, _0)]
</span><span class="kw">pub struct </span>SessionGetError(anyhow::Error);
<span class="kw">impl</span> <span class="ident">StdError</span> <span class="kw">for</span> <span class="ident">SessionGetError</span> {
<span class="kw">fn</span> <span class="ident">source</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="kw-2">&amp;</span>(<span class="kw">dyn</span> <span class="ident">StdError</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>)<span class="op">&gt;</span> {
<span class="prelude-val">Some</span>(<span class="self">self</span>.<span class="number">0</span>.<span class="ident">as_ref</span>())
<span class="kw">impl </span>StdError <span class="kw">for </span>SessionGetError {
<span class="kw">fn </span>source(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>(<span class="kw">dyn </span>StdError + <span class="lifetime">&#39;static</span>)&gt; {
<span class="prelude-val">Some</span>(<span class="self">self</span>.<span class="number">0</span>.as_ref())
}
}
<span class="kw">impl</span> <span class="ident">ResponseError</span> <span class="kw">for</span> <span class="ident">SessionGetError</span> {
<span class="kw">fn</span> <span class="ident">error_response</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">HttpResponse</span><span class="op">&lt;</span><span class="ident">BoxBody</span><span class="op">&gt;</span> {
<span class="ident">HttpResponse::new</span>(<span class="self">self</span>.<span class="ident">status_code</span>())
<span class="kw">impl </span>ResponseError <span class="kw">for </span>SessionGetError {
<span class="kw">fn </span>error_response(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; HttpResponse&lt;BoxBody&gt; {
HttpResponse::new(<span class="self">self</span>.status_code())
}
}
<span class="doccomment">/// Error returned by [`Session::insert`].</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Display</span>, <span class="ident">From</span>)]</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;{}&quot;</span>, <span class="ident">_0</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">SessionInsertError</span>(<span class="ident">anyhow::Error</span>);
<span class="doccomment">/// Error returned by [`Session::insert`].
</span><span class="attribute">#[derive(Debug, Display, From)]
#[display(fmt = <span class="string">&quot;{}&quot;</span>, _0)]
</span><span class="kw">pub struct </span>SessionInsertError(anyhow::Error);
<span class="kw">impl</span> <span class="ident">StdError</span> <span class="kw">for</span> <span class="ident">SessionInsertError</span> {
<span class="kw">fn</span> <span class="ident">source</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="kw-2">&amp;</span>(<span class="kw">dyn</span> <span class="ident">StdError</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>)<span class="op">&gt;</span> {
<span class="prelude-val">Some</span>(<span class="self">self</span>.<span class="number">0</span>.<span class="ident">as_ref</span>())
<span class="kw">impl </span>StdError <span class="kw">for </span>SessionInsertError {
<span class="kw">fn </span>source(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>(<span class="kw">dyn </span>StdError + <span class="lifetime">&#39;static</span>)&gt; {
<span class="prelude-val">Some</span>(<span class="self">self</span>.<span class="number">0</span>.as_ref())
}
}
<span class="kw">impl</span> <span class="ident">ResponseError</span> <span class="kw">for</span> <span class="ident">SessionInsertError</span> {
<span class="kw">fn</span> <span class="ident">error_response</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">HttpResponse</span><span class="op">&lt;</span><span class="ident">BoxBody</span><span class="op">&gt;</span> {
<span class="ident">HttpResponse::new</span>(<span class="self">self</span>.<span class="ident">status_code</span>())
<span class="kw">impl </span>ResponseError <span class="kw">for </span>SessionInsertError {
<span class="kw">fn </span>error_response(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; HttpResponse&lt;BoxBody&gt; {
HttpResponse::new(<span class="self">self</span>.status_code())
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -38,43 +38,43 @@
<span id="36">36</span>
<span id="37">37</span>
<span id="38">38</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">dev</span>::{<span class="ident">ServiceRequest</span>, <span class="ident">ServiceResponse</span>},
<span class="ident">guard::GuardContext</span>,
<span class="ident">HttpMessage</span>, <span class="ident">HttpRequest</span>,
</pre><pre class="rust"><code><span class="kw">use </span>actix_web::{
dev::{ServiceRequest, ServiceResponse},
guard::GuardContext,
HttpMessage, HttpRequest,
};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::Session</span>;
<span class="kw">use </span><span class="kw">crate</span>::Session;
<span class="doccomment">/// Extract a [`Session`] object from various `actix-web` types (e.g. `HttpRequest`,</span>
<span class="doccomment">/// `ServiceRequest`, `ServiceResponse`).</span>
<span class="kw">pub</span> <span class="kw">trait</span> <span class="ident">SessionExt</span> {
<span class="doccomment">/// Extract a [`Session`] object.</span>
<span class="kw">fn</span> <span class="ident">get_session</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Session</span>;
<span class="doccomment">/// Extract a [`Session`] object from various `actix-web` types (e.g. `HttpRequest`,
/// `ServiceRequest`, `ServiceResponse`).
</span><span class="kw">pub trait </span>SessionExt {
<span class="doccomment">/// Extract a [`Session`] object.
</span><span class="kw">fn </span>get_session(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Session;
}
<span class="kw">impl</span> <span class="ident">SessionExt</span> <span class="kw">for</span> <span class="ident">HttpRequest</span> {
<span class="kw">fn</span> <span class="ident">get_session</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Session</span> {
<span class="ident">Session::get_session</span>(<span class="kw-2">&amp;mut</span> <span class="kw-2">*</span><span class="self">self</span>.<span class="ident">extensions_mut</span>())
<span class="kw">impl </span>SessionExt <span class="kw">for </span>HttpRequest {
<span class="kw">fn </span>get_session(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Session {
Session::get_session(<span class="kw-2">&amp;mut *</span><span class="self">self</span>.extensions_mut())
}
}
<span class="kw">impl</span> <span class="ident">SessionExt</span> <span class="kw">for</span> <span class="ident">ServiceRequest</span> {
<span class="kw">fn</span> <span class="ident">get_session</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Session</span> {
<span class="ident">Session::get_session</span>(<span class="kw-2">&amp;mut</span> <span class="kw-2">*</span><span class="self">self</span>.<span class="ident">extensions_mut</span>())
<span class="kw">impl </span>SessionExt <span class="kw">for </span>ServiceRequest {
<span class="kw">fn </span>get_session(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Session {
Session::get_session(<span class="kw-2">&amp;mut *</span><span class="self">self</span>.extensions_mut())
}
}
<span class="kw">impl</span> <span class="ident">SessionExt</span> <span class="kw">for</span> <span class="ident">ServiceResponse</span> {
<span class="kw">fn</span> <span class="ident">get_session</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Session</span> {
<span class="self">self</span>.<span class="ident">request</span>().<span class="ident">get_session</span>()
<span class="kw">impl </span>SessionExt <span class="kw">for </span>ServiceResponse {
<span class="kw">fn </span>get_session(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Session {
<span class="self">self</span>.request().get_session()
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span> <span class="ident">SessionExt</span> <span class="kw">for</span> <span class="ident">GuardContext</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">get_session</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Session</span> {
<span class="ident">Session::get_session</span>(<span class="kw-2">&amp;mut</span> <span class="kw-2">*</span><span class="self">self</span>.<span class="ident">req_data_mut</span>())
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;a</span>&gt; SessionExt <span class="kw">for </span>GuardContext&lt;<span class="lifetime">&#39;a</span>&gt; {
<span class="kw">fn </span>get_session(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Session {
Session::get_session(<span class="kw-2">&amp;mut *</span><span class="self">self</span>.req_data_mut())
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -121,126 +121,126 @@
<span id="119">119</span>
<span id="120">120</span>
<span id="121">121</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::convert::TryInto</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::convert::TryInto;
<span class="kw">use</span> <span class="ident">actix_web::cookie::time::Duration</span>;
<span class="kw">use</span> <span class="ident">anyhow::Error</span>;
<span class="kw">use </span>actix_web::cookie::time::Duration;
<span class="kw">use </span>anyhow::Error;
<span class="kw">use</span> <span class="ident"><span class="kw">super</span>::SessionKey</span>;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::storage</span>::{
<span class="ident">interface</span>::{<span class="ident">LoadError</span>, <span class="ident">SaveError</span>, <span class="ident">SessionState</span>, <span class="ident">UpdateError</span>},
<span class="ident">SessionStore</span>,
<span class="kw">use </span><span class="kw">super</span>::SessionKey;
<span class="kw">use </span><span class="kw">crate</span>::storage::{
interface::{LoadError, SaveError, SessionState, UpdateError},
SessionStore,
};
<span class="doccomment">/// Use the session key, stored in the session cookie, as storage backend for the session state.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ```no_run</span>
<span class="doccomment">/// use actix_web::{cookie::Key, web, App, HttpServer, HttpResponse, Error};</span>
<span class="doccomment">/// use actix_session::{SessionMiddleware, storage::CookieSessionStore};</span>
<span class="doccomment">///</span>
<span class="doccomment">/// // The secret key would usually be read from a configuration file/environment variables.</span>
<span class="doccomment">/// fn get_secret_key() -&gt; Key {</span>
<span class="doccomment">/// # todo!()</span>
<span class="doccomment">/// // [...]</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[actix_web::main]</span>
<span class="doccomment">/// async fn main() -&gt; std::io::Result&lt;()&gt; {</span>
<span class="doccomment">/// let secret_key = get_secret_key();</span>
<span class="doccomment">/// HttpServer::new(move ||</span>
<span class="doccomment">/// App::new()</span>
<span class="doccomment">/// .wrap(SessionMiddleware::new(CookieSessionStore::default(), secret_key.clone()))</span>
<span class="doccomment">/// .default_service(web::to(|| HttpResponse::Ok())))</span>
<span class="doccomment">/// .bind((&quot;127.0.0.1&quot;, 8080))?</span>
<span class="doccomment">/// .run()</span>
<span class="doccomment">/// .await</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Limitations</span>
<span class="doccomment">/// Cookies are subject to size limits so we require session keys to be shorter than 4096 bytes.</span>
<span class="doccomment">/// This translates into a limit on the maximum size of the session state when using cookies as</span>
<span class="doccomment">/// storage backend.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// The session cookie can always be inspected by end users via the developer tools exposed by their</span>
<span class="doccomment">/// browsers. We strongly recommend setting the policy to [`CookieContentSecurity::Private`] when</span>
<span class="doccomment">/// using cookies as storage backend.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// There is no way to invalidate a session before its natural expiry when using cookies as the</span>
<span class="doccomment">/// storage backend.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`CookieContentSecurity::Private`]: crate::config::CookieContentSecurity::Private</span>
<span class="attribute">#[<span class="ident">cfg_attr</span>(<span class="ident">docsrs</span>, <span class="ident">doc</span>(<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;cookie-session&quot;</span>)))]</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Default</span>)]</span>
<span class="attribute">#[<span class="ident">non_exhaustive</span>]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">CookieSessionStore</span>;
<span class="doccomment">/// Use the session key, stored in the session cookie, as storage backend for the session state.
///
/// ```no_run
/// use actix_web::{cookie::Key, web, App, HttpServer, HttpResponse, Error};
/// use actix_session::{SessionMiddleware, storage::CookieSessionStore};
///
/// // The secret key would usually be read from a configuration file/environment variables.
/// fn get_secret_key() -&gt; Key {
/// # todo!()
/// // [...]
/// }
///
/// #[actix_web::main]
/// async fn main() -&gt; std::io::Result&lt;()&gt; {
/// let secret_key = get_secret_key();
/// HttpServer::new(move ||
/// App::new()
/// .wrap(SessionMiddleware::new(CookieSessionStore::default(), secret_key.clone()))
/// .default_service(web::to(|| HttpResponse::Ok())))
/// .bind((&quot;127.0.0.1&quot;, 8080))?
/// .run()
/// .await
/// }
/// ```
///
/// # Limitations
/// Cookies are subject to size limits so we require session keys to be shorter than 4096 bytes.
/// This translates into a limit on the maximum size of the session state when using cookies as
/// storage backend.
///
/// The session cookie can always be inspected by end users via the developer tools exposed by their
/// browsers. We strongly recommend setting the policy to [`CookieContentSecurity::Private`] when
/// using cookies as storage backend.
///
/// There is no way to invalidate a session before its natural expiry when using cookies as the
/// storage backend.
///
/// [`CookieContentSecurity::Private`]: crate::config::CookieContentSecurity::Private
</span><span class="attribute">#[cfg_attr(docsrs, doc(cfg(feature = <span class="string">&quot;cookie-session&quot;</span>)))]
#[derive(Default)]
#[non_exhaustive]
</span><span class="kw">pub struct </span>CookieSessionStore;
<span class="attribute">#[<span class="ident">async_trait::async_trait</span>(<span class="question-mark">?</span><span class="ident">Send</span>)]</span>
<span class="kw">impl</span> <span class="ident">SessionStore</span> <span class="kw">for</span> <span class="ident">CookieSessionStore</span> {
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">load</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">session_key</span>: <span class="kw-2">&amp;</span><span class="ident">SessionKey</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">SessionState</span><span class="op">&gt;</span>, <span class="ident">LoadError</span><span class="op">&gt;</span> {
<span class="ident">serde_json::from_str</span>(<span class="ident">session_key</span>.<span class="ident">as_ref</span>())
.<span class="ident">map</span>(<span class="prelude-val">Some</span>)
.<span class="ident">map_err</span>(<span class="ident">anyhow::Error::new</span>)
.<span class="ident">map_err</span>(<span class="ident">LoadError::Deserialization</span>)
<span class="attribute">#[async_trait::async_trait(<span class="question-mark">?</span>Send)]
</span><span class="kw">impl </span>SessionStore <span class="kw">for </span>CookieSessionStore {
<span class="kw">async fn </span>load(<span class="kw-2">&amp;</span><span class="self">self</span>, session_key: <span class="kw-2">&amp;</span>SessionKey) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;SessionState&gt;, LoadError&gt; {
serde_json::from_str(session_key.as_ref())
.map(<span class="prelude-val">Some</span>)
.map_err(anyhow::Error::new)
.map_err(LoadError::Deserialization)
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">save</span>(
<span class="kw">async fn </span>save(
<span class="kw-2">&amp;</span><span class="self">self</span>,
<span class="ident">session_state</span>: <span class="ident">SessionState</span>,
<span class="ident">_ttl</span>: <span class="kw-2">&amp;</span><span class="ident">Duration</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">SessionKey</span>, <span class="ident">SaveError</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">serde_json::to_string</span>(<span class="kw-2">&amp;</span><span class="ident">session_state</span>)
.<span class="ident">map_err</span>(<span class="ident">anyhow::Error::new</span>)
.<span class="ident">map_err</span>(<span class="ident">SaveError::Serialization</span>)<span class="question-mark">?</span>;
session_state: SessionState,
_ttl: <span class="kw-2">&amp;</span>Duration,
) -&gt; <span class="prelude-ty">Result</span>&lt;SessionKey, SaveError&gt; {
<span class="kw">let </span>session_key = serde_json::to_string(<span class="kw-2">&amp;</span>session_state)
.map_err(anyhow::Error::new)
.map_err(SaveError::Serialization)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(<span class="ident">session_key</span>
.<span class="ident">try_into</span>()
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">SaveError::Other</span>)<span class="question-mark">?</span>)
<span class="prelude-val">Ok</span>(session_key
.try_into()
.map_err(Into::into)
.map_err(SaveError::Other)<span class="question-mark">?</span>)
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">update</span>(
<span class="kw">async fn </span>update(
<span class="kw-2">&amp;</span><span class="self">self</span>,
<span class="ident">_session_key</span>: <span class="ident">SessionKey</span>,
<span class="ident">session_state</span>: <span class="ident">SessionState</span>,
<span class="ident">ttl</span>: <span class="kw-2">&amp;</span><span class="ident">Duration</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">SessionKey</span>, <span class="ident">UpdateError</span><span class="op">&gt;</span> {
<span class="self">self</span>.<span class="ident">save</span>(<span class="ident">session_state</span>, <span class="ident">ttl</span>)
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="op">|</span><span class="ident">err</span><span class="op">|</span> <span class="kw">match</span> <span class="ident">err</span> {
<span class="ident">SaveError::Serialization</span>(<span class="ident">err</span>) =&gt; <span class="ident">UpdateError::Serialization</span>(<span class="ident">err</span>),
<span class="ident">SaveError::Other</span>(<span class="ident">err</span>) =&gt; <span class="ident">UpdateError::Other</span>(<span class="ident">err</span>),
_session_key: SessionKey,
session_state: SessionState,
ttl: <span class="kw-2">&amp;</span>Duration,
) -&gt; <span class="prelude-ty">Result</span>&lt;SessionKey, UpdateError&gt; {
<span class="self">self</span>.save(session_state, ttl)
.<span class="kw">await
</span>.map_err(|err| <span class="kw">match </span>err {
SaveError::Serialization(err) =&gt; UpdateError::Serialization(err),
SaveError::Other(err) =&gt; UpdateError::Other(err),
})
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">update_ttl</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">_session_key</span>: <span class="kw-2">&amp;</span><span class="ident">SessionKey</span>, <span class="ident">_ttl</span>: <span class="kw-2">&amp;</span><span class="ident">Duration</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="kw">async fn </span>update_ttl(<span class="kw-2">&amp;</span><span class="self">self</span>, _session_key: <span class="kw-2">&amp;</span>SessionKey, _ttl: <span class="kw-2">&amp;</span>Duration) -&gt; <span class="prelude-ty">Result</span>&lt;(), Error&gt; {
<span class="prelude-val">Ok</span>(())
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">delete</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">_session_key</span>: <span class="kw-2">&amp;</span><span class="ident">SessionKey</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="kw">async fn </span>delete(<span class="kw-2">&amp;</span><span class="self">self</span>, _session_key: <span class="kw-2">&amp;</span>SessionKey) -&gt; <span class="prelude-ty">Result</span>&lt;(), anyhow::Error&gt; {
<span class="prelude-val">Ok</span>(())
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">storage::utils::generate_session_key</span>, <span class="ident">test_helpers::acceptance_test_suite</span>};
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use crate</span>::{storage::utils::generate_session_key, test_helpers::acceptance_test_suite};
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_session_workflow</span>() {
<span class="ident">acceptance_test_suite</span>(<span class="ident">CookieSessionStore::default</span>, <span class="bool-val">false</span>).<span class="kw">await</span>;
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_session_workflow() {
acceptance_test_suite(CookieSessionStore::default, <span class="bool-val">false</span>).<span class="kw">await</span>;
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">loading_a_random_session_key_returns_deserialization_error</span>() {
<span class="kw">let</span> <span class="ident">store</span> <span class="op">=</span> <span class="ident">CookieSessionStore::default</span>();
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">generate_session_key</span>();
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>loading_a_random_session_key_returns_deserialization_error() {
<span class="kw">let </span>store = CookieSessionStore::default();
<span class="kw">let </span>session_key = generate_session_key();
<span class="macro">assert!</span>(<span class="macro">matches!</span>(
<span class="ident">store</span>.<span class="ident">load</span>(<span class="kw-2">&amp;</span><span class="ident">session_key</span>).<span class="kw">await</span>.<span class="ident">unwrap_err</span>(),
<span class="ident">LoadError::Deserialization</span>(<span class="kw">_</span>),
store.load(<span class="kw-2">&amp;</span>session_key).<span class="kw">await</span>.unwrap_err(),
LoadError::Deserialization(<span class="kw">_</span>),
));
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -115,120 +115,120 @@
<span id="113">113</span>
<span id="114">114</span>
<span id="115">115</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::collections::HashMap</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::collections::HashMap;
<span class="kw">use</span> <span class="ident">actix_web::cookie::time::Duration</span>;
<span class="kw">use</span> <span class="ident">derive_more::Display</span>;
<span class="kw">use </span>actix_web::cookie::time::Duration;
<span class="kw">use </span>derive_more::Display;
<span class="kw">use</span> <span class="ident"><span class="kw">super</span>::SessionKey</span>;
<span class="kw">use </span><span class="kw">super</span>::SessionKey;
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">type</span> <span class="ident">SessionState</span> <span class="op">=</span> <span class="ident">HashMap</span><span class="op">&lt;</span><span class="ident">String</span>, <span class="ident">String</span><span class="op">&gt;</span>;
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">type </span>SessionState = HashMap&lt;String, String&gt;;
<span class="doccomment">/// The interface to retrieve and save the current session data from/to the chosen storage backend.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// You can provide your own custom session store backend by implementing this trait.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`async-trait`](https://docs.rs/async-trait) is used for this trait&#39;s definition. Therefore, it</span>
<span class="doccomment">/// is required for implementations, too. In particular, we use the send-optional variant:</span>
<span class="doccomment">/// `#[async_trait(?Send)]`.</span>
<span class="attribute">#[<span class="ident">async_trait::async_trait</span>(<span class="question-mark">?</span><span class="ident">Send</span>)]</span>
<span class="kw">pub</span> <span class="kw">trait</span> <span class="ident">SessionStore</span> {
<span class="doccomment">/// Loads the session state associated to a session key.</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">load</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">session_key</span>: <span class="kw-2">&amp;</span><span class="ident">SessionKey</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">SessionState</span><span class="op">&gt;</span>, <span class="ident">LoadError</span><span class="op">&gt;</span>;
<span class="doccomment">/// The interface to retrieve and save the current session data from/to the chosen storage backend.
///
/// You can provide your own custom session store backend by implementing this trait.
///
/// [`async-trait`](https://docs.rs/async-trait) is used for this trait&#39;s definition. Therefore, it
/// is required for implementations, too. In particular, we use the send-optional variant:
/// `#[async_trait(?Send)]`.
</span><span class="attribute">#[async_trait::async_trait(<span class="question-mark">?</span>Send)]
</span><span class="kw">pub trait </span>SessionStore {
<span class="doccomment">/// Loads the session state associated to a session key.
</span><span class="kw">async fn </span>load(<span class="kw-2">&amp;</span><span class="self">self</span>, session_key: <span class="kw-2">&amp;</span>SessionKey) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;SessionState&gt;, LoadError&gt;;
<span class="doccomment">/// Persist the session state for a newly created session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Returns the corresponding session key.</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">save</span>(
<span class="doccomment">/// Persist the session state for a newly created session.
///
/// Returns the corresponding session key.
</span><span class="kw">async fn </span>save(
<span class="kw-2">&amp;</span><span class="self">self</span>,
<span class="ident">session_state</span>: <span class="ident">SessionState</span>,
<span class="ident">ttl</span>: <span class="kw-2">&amp;</span><span class="ident">Duration</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">SessionKey</span>, <span class="ident">SaveError</span><span class="op">&gt;</span>;
session_state: SessionState,
ttl: <span class="kw-2">&amp;</span>Duration,
) -&gt; <span class="prelude-ty">Result</span>&lt;SessionKey, SaveError&gt;;
<span class="doccomment">/// Updates the session state associated to a pre-existing session key.</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">update</span>(
<span class="doccomment">/// Updates the session state associated to a pre-existing session key.
</span><span class="kw">async fn </span>update(
<span class="kw-2">&amp;</span><span class="self">self</span>,
<span class="ident">session_key</span>: <span class="ident">SessionKey</span>,
<span class="ident">session_state</span>: <span class="ident">SessionState</span>,
<span class="ident">ttl</span>: <span class="kw-2">&amp;</span><span class="ident">Duration</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">SessionKey</span>, <span class="ident">UpdateError</span><span class="op">&gt;</span>;
session_key: SessionKey,
session_state: SessionState,
ttl: <span class="kw-2">&amp;</span>Duration,
) -&gt; <span class="prelude-ty">Result</span>&lt;SessionKey, UpdateError&gt;;
<span class="doccomment">/// Updates the TTL of the session state associated to a pre-existing session key.</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">update_ttl</span>(
<span class="doccomment">/// Updates the TTL of the session state associated to a pre-existing session key.
</span><span class="kw">async fn </span>update_ttl(
<span class="kw-2">&amp;</span><span class="self">self</span>,
<span class="ident">session_key</span>: <span class="kw-2">&amp;</span><span class="ident">SessionKey</span>,
<span class="ident">ttl</span>: <span class="kw-2">&amp;</span><span class="ident">Duration</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">anyhow::Error</span><span class="op">&gt;</span>;
session_key: <span class="kw-2">&amp;</span>SessionKey,
ttl: <span class="kw-2">&amp;</span>Duration,
) -&gt; <span class="prelude-ty">Result</span>&lt;(), anyhow::Error&gt;;
<span class="doccomment">/// Deletes a session from the store.</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">delete</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">session_key</span>: <span class="kw-2">&amp;</span><span class="ident">SessionKey</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">anyhow::Error</span><span class="op">&gt;</span>;
<span class="doccomment">/// Deletes a session from the store.
</span><span class="kw">async fn </span>delete(<span class="kw-2">&amp;</span><span class="self">self</span>, session_key: <span class="kw-2">&amp;</span>SessionKey) -&gt; <span class="prelude-ty">Result</span>&lt;(), anyhow::Error&gt;;
}
<span class="comment">// We cannot derive the `Error` implementation using `derive_more` for our custom errors:</span>
<span class="comment">// `derive_more`&#39;s `#[error(source)]` attribute requires the source implement the `Error` trait,</span>
<span class="comment">// while it&#39;s actually enough for it to be able to produce a reference to a dyn Error.</span>
<span class="comment">// We cannot derive the `Error` implementation using `derive_more` for our custom errors:
// `derive_more`&#39;s `#[error(source)]` attribute requires the source implement the `Error` trait,
// while it&#39;s actually enough for it to be able to produce a reference to a dyn Error.
<span class="doccomment">/// Possible failures modes for [`SessionStore::load`].</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Display</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">LoadError</span> {
<span class="doccomment">/// Failed to deserialize session state.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Failed to deserialize session state&quot;</span>)]</span>
<span class="ident">Deserialization</span>(<span class="ident">anyhow::Error</span>),
</span><span class="doccomment">/// Possible failures modes for [`SessionStore::load`].
</span><span class="attribute">#[derive(Debug, Display)]
</span><span class="kw">pub enum </span>LoadError {
<span class="doccomment">/// Failed to deserialize session state.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Failed to deserialize session state&quot;</span>)]
</span>Deserialization(anyhow::Error),
<span class="doccomment">/// Something went wrong when retrieving the session state.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Something went wrong when retrieving the session state&quot;</span>)]</span>
<span class="ident">Other</span>(<span class="ident">anyhow::Error</span>),
<span class="doccomment">/// Something went wrong when retrieving the session state.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Something went wrong when retrieving the session state&quot;</span>)]
</span>Other(anyhow::Error),
}
<span class="kw">impl</span> <span class="ident">std::error::Error</span> <span class="kw">for</span> <span class="ident">LoadError</span> {
<span class="kw">fn</span> <span class="ident">source</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="kw-2">&amp;</span>(<span class="kw">dyn</span> <span class="ident">std::error::Error</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>)<span class="op">&gt;</span> {
<span class="kw">match</span> <span class="self">self</span> {
<span class="ident"><span class="self">Self</span>::Deserialization</span>(<span class="ident">err</span>) =&gt; <span class="prelude-val">Some</span>(<span class="ident">err</span>.<span class="ident">as_ref</span>()),
<span class="ident"><span class="self">Self</span>::Other</span>(<span class="ident">err</span>) =&gt; <span class="prelude-val">Some</span>(<span class="ident">err</span>.<span class="ident">as_ref</span>()),
<span class="kw">impl </span>std::error::Error <span class="kw">for </span>LoadError {
<span class="kw">fn </span>source(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>(<span class="kw">dyn </span>std::error::Error + <span class="lifetime">&#39;static</span>)&gt; {
<span class="kw">match </span><span class="self">self </span>{
<span class="self">Self</span>::Deserialization(err) =&gt; <span class="prelude-val">Some</span>(err.as_ref()),
<span class="self">Self</span>::Other(err) =&gt; <span class="prelude-val">Some</span>(err.as_ref()),
}
}
}
<span class="doccomment">/// Possible failures modes for [`SessionStore::save`].</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Display</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">SaveError</span> {
<span class="doccomment">/// Failed to serialize session state.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Failed to serialize session state&quot;</span>)]</span>
<span class="ident">Serialization</span>(<span class="ident">anyhow::Error</span>),
<span class="doccomment">/// Possible failures modes for [`SessionStore::save`].
</span><span class="attribute">#[derive(Debug, Display)]
</span><span class="kw">pub enum </span>SaveError {
<span class="doccomment">/// Failed to serialize session state.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Failed to serialize session state&quot;</span>)]
</span>Serialization(anyhow::Error),
<span class="doccomment">/// Something went wrong when persisting the session state.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Something went wrong when persisting the session state&quot;</span>)]</span>
<span class="ident">Other</span>(<span class="ident">anyhow::Error</span>),
<span class="doccomment">/// Something went wrong when persisting the session state.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Something went wrong when persisting the session state&quot;</span>)]
</span>Other(anyhow::Error),
}
<span class="kw">impl</span> <span class="ident">std::error::Error</span> <span class="kw">for</span> <span class="ident">SaveError</span> {
<span class="kw">fn</span> <span class="ident">source</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="kw-2">&amp;</span>(<span class="kw">dyn</span> <span class="ident">std::error::Error</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>)<span class="op">&gt;</span> {
<span class="kw">match</span> <span class="self">self</span> {
<span class="ident"><span class="self">Self</span>::Serialization</span>(<span class="ident">err</span>) =&gt; <span class="prelude-val">Some</span>(<span class="ident">err</span>.<span class="ident">as_ref</span>()),
<span class="ident"><span class="self">Self</span>::Other</span>(<span class="ident">err</span>) =&gt; <span class="prelude-val">Some</span>(<span class="ident">err</span>.<span class="ident">as_ref</span>()),
<span class="kw">impl </span>std::error::Error <span class="kw">for </span>SaveError {
<span class="kw">fn </span>source(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>(<span class="kw">dyn </span>std::error::Error + <span class="lifetime">&#39;static</span>)&gt; {
<span class="kw">match </span><span class="self">self </span>{
<span class="self">Self</span>::Serialization(err) =&gt; <span class="prelude-val">Some</span>(err.as_ref()),
<span class="self">Self</span>::Other(err) =&gt; <span class="prelude-val">Some</span>(err.as_ref()),
}
}
}
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Display</span>)]</span>
<span class="doccomment">/// Possible failures modes for [`SessionStore::update`].</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">UpdateError</span> {
<span class="doccomment">/// Failed to serialize session state.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Failed to serialize session state&quot;</span>)]</span>
<span class="ident">Serialization</span>(<span class="ident">anyhow::Error</span>),
<span class="attribute">#[derive(Debug, Display)]
</span><span class="doccomment">/// Possible failures modes for [`SessionStore::update`].
</span><span class="kw">pub enum </span>UpdateError {
<span class="doccomment">/// Failed to serialize session state.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Failed to serialize session state&quot;</span>)]
</span>Serialization(anyhow::Error),
<span class="doccomment">/// Something went wrong when updating the session state.</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;Something went wrong when updating the session state.&quot;</span>)]</span>
<span class="ident">Other</span>(<span class="ident">anyhow::Error</span>),
<span class="doccomment">/// Something went wrong when updating the session state.
</span><span class="attribute">#[display(fmt = <span class="string">&quot;Something went wrong when updating the session state.&quot;</span>)]
</span>Other(anyhow::Error),
}
<span class="kw">impl</span> <span class="ident">std::error::Error</span> <span class="kw">for</span> <span class="ident">UpdateError</span> {
<span class="kw">fn</span> <span class="ident">source</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="kw-2">&amp;</span>(<span class="kw">dyn</span> <span class="ident">std::error::Error</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>)<span class="op">&gt;</span> {
<span class="kw">match</span> <span class="self">self</span> {
<span class="ident"><span class="self">Self</span>::Serialization</span>(<span class="ident">err</span>) =&gt; <span class="prelude-val">Some</span>(<span class="ident">err</span>.<span class="ident">as_ref</span>()),
<span class="ident"><span class="self">Self</span>::Other</span>(<span class="ident">err</span>) =&gt; <span class="prelude-val">Some</span>(<span class="ident">err</span>.<span class="ident">as_ref</span>()),
<span class="kw">impl </span>std::error::Error <span class="kw">for </span>UpdateError {
<span class="kw">fn </span>source(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>(<span class="kw">dyn </span>std::error::Error + <span class="lifetime">&#39;static</span>)&gt; {
<span class="kw">match </span><span class="self">self </span>{
<span class="self">Self</span>::Serialization(err) =&gt; <span class="prelude-val">Some</span>(err.as_ref()),
<span class="self">Self</span>::Other(err) =&gt; <span class="prelude-val">Some</span>(err.as_ref()),
}
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -26,31 +26,31 @@
<span id="24">24</span>
<span id="25">25</span>
<span id="26">26</span>
</pre><pre class="rust"><code><span class="doccomment">//! Pluggable storage backends for session state.</span>
</pre><pre class="rust"><code><span class="doccomment">//! Pluggable storage backends for session state.
<span class="kw">mod</span> <span class="ident">interface</span>;
<span class="kw">mod</span> <span class="ident">session_key</span>;
</span><span class="kw">mod </span>interface;
<span class="kw">mod </span>session_key;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::interface</span>::{<span class="ident">LoadError</span>, <span class="ident">SaveError</span>, <span class="ident">SessionStore</span>, <span class="ident">UpdateError</span>};
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::session_key::SessionKey</span>;
<span class="kw">pub use </span><span class="self">self</span>::interface::{LoadError, SaveError, SessionStore, UpdateError};
<span class="kw">pub use </span><span class="self">self</span>::session_key::SessionKey;
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;cookie-session&quot;</span>)]</span>
<span class="kw">mod</span> <span class="ident">cookie</span>;
<span class="attribute">#[cfg(feature = <span class="string">&quot;cookie-session&quot;</span>)]
</span><span class="kw">mod </span>cookie;
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;redis-actor-session&quot;</span>)]</span>
<span class="kw">mod</span> <span class="ident">redis_actor</span>;
<span class="attribute">#[cfg(feature = <span class="string">&quot;redis-actor-session&quot;</span>)]
</span><span class="kw">mod </span>redis_actor;
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;redis-rs-session&quot;</span>)]</span>
<span class="kw">mod</span> <span class="ident">redis_rs</span>;
<span class="attribute">#[cfg(feature = <span class="string">&quot;redis-rs-session&quot;</span>)]
</span><span class="kw">mod </span>redis_rs;
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">any</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;redis-actor-session&quot;</span>, <span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;redis-rs-session&quot;</span>))]</span>
<span class="kw">mod</span> <span class="ident">utils</span>;
<span class="attribute">#[cfg(any(feature = <span class="string">&quot;redis-actor-session&quot;</span>, feature = <span class="string">&quot;redis-rs-session&quot;</span>))]
</span><span class="kw">mod </span>utils;
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;cookie-session&quot;</span>)]</span>
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident">cookie::CookieSessionStore</span>;
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;redis-actor-session&quot;</span>)]</span>
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident">redis_actor</span>::{<span class="ident">RedisActorSessionStore</span>, <span class="ident">RedisActorSessionStoreBuilder</span>};
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;redis-rs-session&quot;</span>)]</span>
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident">redis_rs</span>::{<span class="ident">RedisSessionStore</span>, <span class="ident">RedisSessionStoreBuilder</span>};
<span class="attribute">#[cfg(feature = <span class="string">&quot;cookie-session&quot;</span>)]
</span><span class="kw">pub use </span>cookie::CookieSessionStore;
<span class="attribute">#[cfg(feature = <span class="string">&quot;redis-actor-session&quot;</span>)]
</span><span class="kw">pub use </span>redis_actor::{RedisActorSessionStore, RedisActorSessionStoreBuilder};
<span class="attribute">#[cfg(feature = <span class="string">&quot;redis-rs-session&quot;</span>)]
</span><span class="kw">pub use </span>redis_rs::{RedisSessionStore, RedisSessionStoreBuilder};
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -315,320 +315,320 @@
<span id="313">313</span>
<span id="314">314</span>
<span id="315">315</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">actix::Addr</span>;
<span class="kw">use</span> <span class="ident">actix_redis</span>::{<span class="ident">resp_array</span>, <span class="ident">Command</span>, <span class="ident">RedisActor</span>, <span class="ident">RespValue</span>};
<span class="kw">use</span> <span class="ident">actix_web::cookie::time::Duration</span>;
<span class="kw">use</span> <span class="ident">anyhow::Error</span>;
</pre><pre class="rust"><code><span class="kw">use </span>actix::Addr;
<span class="kw">use </span>actix_redis::{resp_array, Command, RedisActor, RespValue};
<span class="kw">use </span>actix_web::cookie::time::Duration;
<span class="kw">use </span>anyhow::Error;
<span class="kw">use</span> <span class="ident"><span class="kw">super</span>::SessionKey</span>;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::storage</span>::{
<span class="ident">interface</span>::{<span class="ident">LoadError</span>, <span class="ident">SaveError</span>, <span class="ident">SessionState</span>, <span class="ident">UpdateError</span>},
<span class="ident">utils::generate_session_key</span>,
<span class="ident">SessionStore</span>,
<span class="kw">use </span><span class="kw">super</span>::SessionKey;
<span class="kw">use </span><span class="kw">crate</span>::storage::{
interface::{LoadError, SaveError, SessionState, UpdateError},
utils::generate_session_key,
SessionStore,
};
<span class="doccomment">/// Use Redis as session storage backend.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ```no_run</span>
<span class="doccomment">/// use actix_web::{web, App, HttpServer, HttpResponse, Error};</span>
<span class="doccomment">/// use actix_session::{SessionMiddleware, storage::RedisActorSessionStore};</span>
<span class="doccomment">/// use actix_web::cookie::Key;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// // The secret key would usually be read from a configuration file/environment variables.</span>
<span class="doccomment">/// fn get_secret_key() -&gt; Key {</span>
<span class="doccomment">/// # todo!()</span>
<span class="doccomment">/// // [...]</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[actix_web::main]</span>
<span class="doccomment">/// async fn main() -&gt; std::io::Result&lt;()&gt; {</span>
<span class="doccomment">/// let secret_key = get_secret_key();</span>
<span class="doccomment">/// let redis_connection_string = &quot;127.0.0.1:6379&quot;;</span>
<span class="doccomment">/// HttpServer::new(move ||</span>
<span class="doccomment">/// App::new()</span>
<span class="doccomment">/// .wrap(</span>
<span class="doccomment">/// SessionMiddleware::new(</span>
<span class="doccomment">/// RedisActorSessionStore::new(redis_connection_string),</span>
<span class="doccomment">/// secret_key.clone()</span>
<span class="doccomment">/// )</span>
<span class="doccomment">/// )</span>
<span class="doccomment">/// .default_service(web::to(|| HttpResponse::Ok())))</span>
<span class="doccomment">/// .bind((&quot;127.0.0.1&quot;, 8080))?</span>
<span class="doccomment">/// .run()</span>
<span class="doccomment">/// .await</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Implementation notes</span>
<span class="doccomment">///</span>
<span class="doccomment">/// `RedisActorSessionStore` leverages `actix-redis`&#39;s `RedisActor` implementation - each thread</span>
<span class="doccomment">/// worker gets its own connection to Redis.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ## Limitations</span>
<span class="doccomment">///</span>
<span class="doccomment">/// `RedisActorSessionStore` does not currently support establishing authenticated connections to</span>
<span class="doccomment">/// Redis. Use [`RedisSessionStore`] if you need TLS support.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`RedisSessionStore`]: crate::storage::RedisSessionStore</span>
<span class="attribute">#[<span class="ident">cfg_attr</span>(<span class="ident">docsrs</span>, <span class="ident">doc</span>(<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;redis-actor-session&quot;</span>)))]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">RedisActorSessionStore</span> {
<span class="ident">configuration</span>: <span class="ident">CacheConfiguration</span>,
<span class="ident">addr</span>: <span class="ident">Addr</span><span class="op">&lt;</span><span class="ident">RedisActor</span><span class="op">&gt;</span>,
<span class="doccomment">/// Use Redis as session storage backend.
///
/// ```no_run
/// use actix_web::{web, App, HttpServer, HttpResponse, Error};
/// use actix_session::{SessionMiddleware, storage::RedisActorSessionStore};
/// use actix_web::cookie::Key;
///
/// // The secret key would usually be read from a configuration file/environment variables.
/// fn get_secret_key() -&gt; Key {
/// # todo!()
/// // [...]
/// }
///
/// #[actix_web::main]
/// async fn main() -&gt; std::io::Result&lt;()&gt; {
/// let secret_key = get_secret_key();
/// let redis_connection_string = &quot;127.0.0.1:6379&quot;;
/// HttpServer::new(move ||
/// App::new()
/// .wrap(
/// SessionMiddleware::new(
/// RedisActorSessionStore::new(redis_connection_string),
/// secret_key.clone()
/// )
/// )
/// .default_service(web::to(|| HttpResponse::Ok())))
/// .bind((&quot;127.0.0.1&quot;, 8080))?
/// .run()
/// .await
/// }
/// ```
///
/// # Implementation notes
///
/// `RedisActorSessionStore` leverages `actix-redis`&#39;s `RedisActor` implementation - each thread
/// worker gets its own connection to Redis.
///
/// ## Limitations
///
/// `RedisActorSessionStore` does not currently support establishing authenticated connections to
/// Redis. Use [`RedisSessionStore`] if you need TLS support.
///
/// [`RedisSessionStore`]: crate::storage::RedisSessionStore
</span><span class="attribute">#[cfg_attr(docsrs, doc(cfg(feature = <span class="string">&quot;redis-actor-session&quot;</span>)))]
</span><span class="kw">pub struct </span>RedisActorSessionStore {
configuration: CacheConfiguration,
addr: Addr&lt;RedisActor&gt;,
}
<span class="kw">impl</span> <span class="ident">RedisActorSessionStore</span> {
<span class="doccomment">/// A fluent API to configure [`RedisActorSessionStore`].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// It takes as input the only required input to create a new instance of</span>
<span class="doccomment">/// [`RedisActorSessionStore`]—a connection string for Redis.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">builder</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span><span class="op">&gt;</span>(<span class="ident">connection_string</span>: <span class="ident">S</span>) -&gt; <span class="ident">RedisActorSessionStoreBuilder</span> {
<span class="ident">RedisActorSessionStoreBuilder</span> {
<span class="ident">configuration</span>: <span class="ident">CacheConfiguration::default</span>(),
<span class="ident">connection_string</span>: <span class="ident">connection_string</span>.<span class="ident">into</span>(),
<span class="kw">impl </span>RedisActorSessionStore {
<span class="doccomment">/// A fluent API to configure [`RedisActorSessionStore`].
///
/// It takes as input the only required input to create a new instance of
/// [`RedisActorSessionStore`]—a connection string for Redis.
</span><span class="kw">pub fn </span>builder&lt;S: Into&lt;String&gt;&gt;(connection_string: S) -&gt; RedisActorSessionStoreBuilder {
RedisActorSessionStoreBuilder {
configuration: CacheConfiguration::default(),
connection_string: connection_string.into(),
}
}
<span class="doccomment">/// Create a new instance of [`RedisActorSessionStore`] using the default configuration.</span>
<span class="doccomment">/// It takes as input the only required input to create a new instance of [`RedisActorSessionStore`] - a</span>
<span class="doccomment">/// connection string for Redis.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">new</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span><span class="op">&gt;</span>(<span class="ident">connection_string</span>: <span class="ident">S</span>) -&gt; <span class="ident">RedisActorSessionStore</span> {
<span class="ident"><span class="self">Self</span>::builder</span>(<span class="ident">connection_string</span>).<span class="ident">build</span>()
<span class="doccomment">/// Create a new instance of [`RedisActorSessionStore`] using the default configuration.
/// It takes as input the only required input to create a new instance of [`RedisActorSessionStore`] - a
/// connection string for Redis.
</span><span class="kw">pub fn </span>new&lt;S: Into&lt;String&gt;&gt;(connection_string: S) -&gt; RedisActorSessionStore {
<span class="self">Self</span>::builder(connection_string).build()
}
}
<span class="kw">struct</span> <span class="ident">CacheConfiguration</span> {
<span class="ident">cache_keygen</span>: <span class="ident">Box</span><span class="op">&lt;</span><span class="kw">dyn</span> <span class="ident">Fn</span>(<span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="ident">String</span><span class="op">&gt;</span>,
<span class="kw">struct </span>CacheConfiguration {
cache_keygen: Box&lt;<span class="kw">dyn </span>Fn(<span class="kw-2">&amp;</span>str) -&gt; String&gt;,
}
<span class="kw">impl</span> <span class="ident">Default</span> <span class="kw">for</span> <span class="ident">CacheConfiguration</span> {
<span class="kw">fn</span> <span class="ident">default</span>() -&gt; <span class="self">Self</span> {
<span class="self">Self</span> {
<span class="ident">cache_keygen</span>: <span class="ident">Box::new</span>(<span class="ident">str::to_owned</span>),
<span class="kw">impl </span>Default <span class="kw">for </span>CacheConfiguration {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{
cache_keygen: Box::new(str::to_owned),
}
}
}
<span class="doccomment">/// A fluent builder to construct a [`RedisActorSessionStore`] instance with custom configuration</span>
<span class="doccomment">/// parameters.</span>
<span class="attribute">#[<span class="ident">cfg_attr</span>(<span class="ident">docsrs</span>, <span class="ident">doc</span>(<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;redis-actor-session&quot;</span>)))]</span>
<span class="attribute">#[<span class="ident">must_use</span>]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">RedisActorSessionStoreBuilder</span> {
<span class="ident">connection_string</span>: <span class="ident">String</span>,
<span class="ident">configuration</span>: <span class="ident">CacheConfiguration</span>,
<span class="doccomment">/// A fluent builder to construct a [`RedisActorSessionStore`] instance with custom configuration
/// parameters.
</span><span class="attribute">#[cfg_attr(docsrs, doc(cfg(feature = <span class="string">&quot;redis-actor-session&quot;</span>)))]
#[must_use]
</span><span class="kw">pub struct </span>RedisActorSessionStoreBuilder {
connection_string: String,
configuration: CacheConfiguration,
}
<span class="kw">impl</span> <span class="ident">RedisActorSessionStoreBuilder</span> {
<span class="doccomment">/// Set a custom cache key generation strategy, expecting a session key as input.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">cache_keygen</span><span class="op">&lt;</span><span class="ident">F</span><span class="op">&gt;</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">keygen</span>: <span class="ident">F</span>) -&gt; <span class="self">Self</span>
<span class="kw">where</span>
<span class="ident">F</span>: <span class="ident">Fn</span>(<span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="ident">String</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="kw">impl </span>RedisActorSessionStoreBuilder {
<span class="doccomment">/// Set a custom cache key generation strategy, expecting a session key as input.
</span><span class="kw">pub fn </span>cache_keygen&lt;F&gt;(<span class="kw-2">mut </span><span class="self">self</span>, keygen: F) -&gt; <span class="self">Self
</span><span class="kw">where
</span>F: Fn(<span class="kw-2">&amp;</span>str) -&gt; String + <span class="lifetime">&#39;static</span>,
{
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cache_keygen</span> <span class="op">=</span> <span class="ident">Box::new</span>(<span class="ident">keygen</span>);
<span class="self">self</span>
}
<span class="self">self</span>.configuration.cache_keygen = Box::new(keygen);
<span class="self">self
</span>}
<span class="doccomment">/// Finalise the builder and return a [`RedisActorSessionStore`] instance.</span>
<span class="attribute">#[<span class="ident">must_use</span>]</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">build</span>(<span class="self">self</span>) -&gt; <span class="ident">RedisActorSessionStore</span> {
<span class="ident">RedisActorSessionStore</span> {
<span class="ident">configuration</span>: <span class="self">self</span>.<span class="ident">configuration</span>,
<span class="ident">addr</span>: <span class="ident">RedisActor::start</span>(<span class="self">self</span>.<span class="ident">connection_string</span>),
<span class="doccomment">/// Finalise the builder and return a [`RedisActorSessionStore`] instance.
</span><span class="attribute">#[must_use]
</span><span class="kw">pub fn </span>build(<span class="self">self</span>) -&gt; RedisActorSessionStore {
RedisActorSessionStore {
configuration: <span class="self">self</span>.configuration,
addr: RedisActor::start(<span class="self">self</span>.connection_string),
}
}
}
<span class="attribute">#[<span class="ident">async_trait::async_trait</span>(<span class="question-mark">?</span><span class="ident">Send</span>)]</span>
<span class="kw">impl</span> <span class="ident">SessionStore</span> <span class="kw">for</span> <span class="ident">RedisActorSessionStore</span> {
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">load</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">session_key</span>: <span class="kw-2">&amp;</span><span class="ident">SessionKey</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">SessionState</span><span class="op">&gt;</span>, <span class="ident">LoadError</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">cache_key</span> <span class="op">=</span> (<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cache_keygen</span>)(<span class="ident">session_key</span>.<span class="ident">as_ref</span>());
<span class="kw">let</span> <span class="ident">val</span> <span class="op">=</span> <span class="self">self</span>
.<span class="ident">addr</span>
.<span class="ident">send</span>(<span class="ident">Command</span>(<span class="macro">resp_array!</span>[<span class="string">&quot;GET&quot;</span>, <span class="ident">cache_key</span>]))
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">LoadError::Other</span>)<span class="question-mark">?</span>
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">LoadError::Other</span>)<span class="question-mark">?</span>;
<span class="attribute">#[async_trait::async_trait(<span class="question-mark">?</span>Send)]
</span><span class="kw">impl </span>SessionStore <span class="kw">for </span>RedisActorSessionStore {
<span class="kw">async fn </span>load(<span class="kw-2">&amp;</span><span class="self">self</span>, session_key: <span class="kw-2">&amp;</span>SessionKey) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;SessionState&gt;, LoadError&gt; {
<span class="kw">let </span>cache_key = (<span class="self">self</span>.configuration.cache_keygen)(session_key.as_ref());
<span class="kw">let </span>val = <span class="self">self
</span>.addr
.send(Command(<span class="macro">resp_array!</span>[<span class="string">&quot;GET&quot;</span>, cache_key]))
.<span class="kw">await
</span>.map_err(Into::into)
.map_err(LoadError::Other)<span class="question-mark">?
</span>.map_err(Into::into)
.map_err(LoadError::Other)<span class="question-mark">?</span>;
<span class="kw">match</span> <span class="ident">val</span> {
<span class="ident">RespValue::Error</span>(<span class="ident">err</span>) =&gt; <span class="prelude-val">Err</span>(<span class="ident">LoadError::Other</span>(<span class="macro">anyhow::anyhow!</span>(<span class="ident">err</span>))),
<span class="kw">match </span>val {
RespValue::Error(err) =&gt; <span class="prelude-val">Err</span>(LoadError::Other(<span class="macro">anyhow::anyhow!</span>(err))),
<span class="ident">RespValue::SimpleString</span>(<span class="ident">s</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">serde_json::from_str</span>(<span class="kw-2">&amp;</span><span class="ident">s</span>)
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">LoadError::Deserialization</span>)<span class="question-mark">?</span>),
RespValue::SimpleString(s) =&gt; <span class="prelude-val">Ok</span>(serde_json::from_str(<span class="kw-2">&amp;</span>s)
.map_err(Into::into)
.map_err(LoadError::Deserialization)<span class="question-mark">?</span>),
<span class="ident">RespValue::BulkString</span>(<span class="ident">s</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">serde_json::from_slice</span>(<span class="kw-2">&amp;</span><span class="ident">s</span>)
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">LoadError::Deserialization</span>)<span class="question-mark">?</span>),
RespValue::BulkString(s) =&gt; <span class="prelude-val">Ok</span>(serde_json::from_slice(<span class="kw-2">&amp;</span>s)
.map_err(Into::into)
.map_err(LoadError::Deserialization)<span class="question-mark">?</span>),
<span class="kw">_</span> =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>),
<span class="kw">_ </span>=&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>),
}
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">save</span>(
<span class="kw">async fn </span>save(
<span class="kw-2">&amp;</span><span class="self">self</span>,
<span class="ident">session_state</span>: <span class="ident">SessionState</span>,
<span class="ident">ttl</span>: <span class="kw-2">&amp;</span><span class="ident">Duration</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">SessionKey</span>, <span class="ident">SaveError</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">body</span> <span class="op">=</span> <span class="ident">serde_json::to_string</span>(<span class="kw-2">&amp;</span><span class="ident">session_state</span>)
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">SaveError::Serialization</span>)<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">generate_session_key</span>();
<span class="kw">let</span> <span class="ident">cache_key</span> <span class="op">=</span> (<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cache_keygen</span>)(<span class="ident">session_key</span>.<span class="ident">as_ref</span>());
session_state: SessionState,
ttl: <span class="kw-2">&amp;</span>Duration,
) -&gt; <span class="prelude-ty">Result</span>&lt;SessionKey, SaveError&gt; {
<span class="kw">let </span>body = serde_json::to_string(<span class="kw-2">&amp;</span>session_state)
.map_err(Into::into)
.map_err(SaveError::Serialization)<span class="question-mark">?</span>;
<span class="kw">let </span>session_key = generate_session_key();
<span class="kw">let </span>cache_key = (<span class="self">self</span>.configuration.cache_keygen)(session_key.as_ref());
<span class="kw">let</span> <span class="ident">cmd</span> <span class="op">=</span> <span class="ident">Command</span>(<span class="macro">resp_array!</span>[
<span class="kw">let </span>cmd = Command(<span class="macro">resp_array!</span>[
<span class="string">&quot;SET&quot;</span>,
<span class="ident">cache_key</span>,
<span class="ident">body</span>,
<span class="string">&quot;NX&quot;</span>, <span class="comment">// NX: only set the key if it does not already exist</span>
<span class="string">&quot;EX&quot;</span>, <span class="comment">// EX: set expiry</span>
<span class="macro">format!</span>(<span class="string">&quot;{}&quot;</span>, <span class="ident">ttl</span>.<span class="ident">whole_seconds</span>())
cache_key,
body,
<span class="string">&quot;NX&quot;</span>, <span class="comment">// NX: only set the key if it does not already exist
</span><span class="string">&quot;EX&quot;</span>, <span class="comment">// EX: set expiry
</span><span class="macro">format!</span>(<span class="string">&quot;{}&quot;</span>, ttl.whole_seconds())
]);
<span class="kw">let</span> <span class="ident">result</span> <span class="op">=</span> <span class="self">self</span>
.<span class="ident">addr</span>
.<span class="ident">send</span>(<span class="ident">cmd</span>)
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">SaveError::Other</span>)<span class="question-mark">?</span>
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">SaveError::Other</span>)<span class="question-mark">?</span>;
<span class="kw">let </span>result = <span class="self">self
</span>.addr
.send(cmd)
.<span class="kw">await
</span>.map_err(Into::into)
.map_err(SaveError::Other)<span class="question-mark">?
</span>.map_err(Into::into)
.map_err(SaveError::Other)<span class="question-mark">?</span>;
<span class="kw">match</span> <span class="ident">result</span> {
<span class="ident">RespValue::SimpleString</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">session_key</span>),
<span class="ident">RespValue::Nil</span> =&gt; <span class="prelude-val">Err</span>(<span class="ident">SaveError::Other</span>(<span class="macro">anyhow::anyhow!</span>(
<span class="string">&quot;Failed to save session state. A record with the same key already existed in Redis&quot;</span>
))),
<span class="ident">err</span> =&gt; <span class="prelude-val">Err</span>(<span class="ident">SaveError::Other</span>(<span class="macro">anyhow::anyhow!</span>(
<span class="kw">match </span>result {
RespValue::SimpleString(<span class="kw">_</span>) =&gt; <span class="prelude-val">Ok</span>(session_key),
RespValue::Nil =&gt; <span class="prelude-val">Err</span>(SaveError::Other(<span class="macro">anyhow::anyhow!</span>(
<span class="string">&quot;Failed to save session state. A record with the same key already existed in Redis&quot;
</span>))),
err =&gt; <span class="prelude-val">Err</span>(SaveError::Other(<span class="macro">anyhow::anyhow!</span>(
<span class="string">&quot;Failed to save session state. {:?}&quot;</span>,
<span class="ident">err</span>
err
))),
}
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">update</span>(
<span class="kw">async fn </span>update(
<span class="kw-2">&amp;</span><span class="self">self</span>,
<span class="ident">session_key</span>: <span class="ident">SessionKey</span>,
<span class="ident">session_state</span>: <span class="ident">SessionState</span>,
<span class="ident">ttl</span>: <span class="kw-2">&amp;</span><span class="ident">Duration</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">SessionKey</span>, <span class="ident">UpdateError</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">body</span> <span class="op">=</span> <span class="ident">serde_json::to_string</span>(<span class="kw-2">&amp;</span><span class="ident">session_state</span>)
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">UpdateError::Serialization</span>)<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">cache_key</span> <span class="op">=</span> (<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cache_keygen</span>)(<span class="ident">session_key</span>.<span class="ident">as_ref</span>());
session_key: SessionKey,
session_state: SessionState,
ttl: <span class="kw-2">&amp;</span>Duration,
) -&gt; <span class="prelude-ty">Result</span>&lt;SessionKey, UpdateError&gt; {
<span class="kw">let </span>body = serde_json::to_string(<span class="kw-2">&amp;</span>session_state)
.map_err(Into::into)
.map_err(UpdateError::Serialization)<span class="question-mark">?</span>;
<span class="kw">let </span>cache_key = (<span class="self">self</span>.configuration.cache_keygen)(session_key.as_ref());
<span class="kw">let</span> <span class="ident">cmd</span> <span class="op">=</span> <span class="ident">Command</span>(<span class="macro">resp_array!</span>[
<span class="kw">let </span>cmd = Command(<span class="macro">resp_array!</span>[
<span class="string">&quot;SET&quot;</span>,
<span class="ident">cache_key</span>,
<span class="ident">body</span>,
<span class="string">&quot;XX&quot;</span>, <span class="comment">// XX: Only set the key if it already exist.</span>
<span class="string">&quot;EX&quot;</span>, <span class="comment">// EX: set expiry</span>
<span class="macro">format!</span>(<span class="string">&quot;{}&quot;</span>, <span class="ident">ttl</span>.<span class="ident">whole_seconds</span>())
cache_key,
body,
<span class="string">&quot;XX&quot;</span>, <span class="comment">// XX: Only set the key if it already exist.
</span><span class="string">&quot;EX&quot;</span>, <span class="comment">// EX: set expiry
</span><span class="macro">format!</span>(<span class="string">&quot;{}&quot;</span>, ttl.whole_seconds())
]);
<span class="kw">let</span> <span class="ident">result</span> <span class="op">=</span> <span class="self">self</span>
.<span class="ident">addr</span>
.<span class="ident">send</span>(<span class="ident">cmd</span>)
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">UpdateError::Other</span>)<span class="question-mark">?</span>
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">UpdateError::Other</span>)<span class="question-mark">?</span>;
<span class="kw">let </span>result = <span class="self">self
</span>.addr
.send(cmd)
.<span class="kw">await
</span>.map_err(Into::into)
.map_err(UpdateError::Other)<span class="question-mark">?
</span>.map_err(Into::into)
.map_err(UpdateError::Other)<span class="question-mark">?</span>;
<span class="kw">match</span> <span class="ident">result</span> {
<span class="ident">RespValue::Nil</span> =&gt; {
<span class="comment">// The SET operation was not performed because the XX condition was not verified.</span>
<span class="comment">// This can happen if the session state expired between the load operation and the</span>
<span class="comment">// update operation. Unlucky, to say the least. We fall back to the `save` routine</span>
<span class="comment">// to ensure that the new key is unique.</span>
<span class="self">self</span>.<span class="ident">save</span>(<span class="ident">session_state</span>, <span class="ident">ttl</span>)
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="op">|</span><span class="ident">err</span><span class="op">|</span> <span class="kw">match</span> <span class="ident">err</span> {
<span class="ident">SaveError::Serialization</span>(<span class="ident">err</span>) =&gt; <span class="ident">UpdateError::Serialization</span>(<span class="ident">err</span>),
<span class="ident">SaveError::Other</span>(<span class="ident">err</span>) =&gt; <span class="ident">UpdateError::Other</span>(<span class="ident">err</span>),
<span class="kw">match </span>result {
RespValue::Nil =&gt; {
<span class="comment">// The SET operation was not performed because the XX condition was not verified.
// This can happen if the session state expired between the load operation and the
// update operation. Unlucky, to say the least. We fall back to the `save` routine
// to ensure that the new key is unique.
</span><span class="self">self</span>.save(session_state, ttl)
.<span class="kw">await
</span>.map_err(|err| <span class="kw">match </span>err {
SaveError::Serialization(err) =&gt; UpdateError::Serialization(err),
SaveError::Other(err) =&gt; UpdateError::Other(err),
})
}
<span class="ident">RespValue::SimpleString</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">session_key</span>),
<span class="ident">val</span> =&gt; <span class="prelude-val">Err</span>(<span class="ident">UpdateError::Other</span>(<span class="macro">anyhow::anyhow!</span>(
RespValue::SimpleString(<span class="kw">_</span>) =&gt; <span class="prelude-val">Ok</span>(session_key),
val =&gt; <span class="prelude-val">Err</span>(UpdateError::Other(<span class="macro">anyhow::anyhow!</span>(
<span class="string">&quot;Failed to update session state. {:?}&quot;</span>,
<span class="ident">val</span>
val
))),
}
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">update_ttl</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">session_key</span>: <span class="kw-2">&amp;</span><span class="ident">SessionKey</span>, <span class="ident">ttl</span>: <span class="kw-2">&amp;</span><span class="ident">Duration</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">cache_key</span> <span class="op">=</span> (<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cache_keygen</span>)(<span class="ident">session_key</span>.<span class="ident">as_ref</span>());
<span class="kw">async fn </span>update_ttl(<span class="kw-2">&amp;</span><span class="self">self</span>, session_key: <span class="kw-2">&amp;</span>SessionKey, ttl: <span class="kw-2">&amp;</span>Duration) -&gt; <span class="prelude-ty">Result</span>&lt;(), Error&gt; {
<span class="kw">let </span>cache_key = (<span class="self">self</span>.configuration.cache_keygen)(session_key.as_ref());
<span class="kw">let</span> <span class="ident">cmd</span> <span class="op">=</span> <span class="ident">Command</span>(<span class="macro">resp_array!</span>[
<span class="kw">let </span>cmd = Command(<span class="macro">resp_array!</span>[
<span class="string">&quot;EXPIRE&quot;</span>,
<span class="ident">cache_key</span>,
<span class="ident">ttl</span>.<span class="ident">whole_seconds</span>().<span class="ident">to_string</span>()
cache_key,
ttl.whole_seconds().to_string()
]);
<span class="kw">match</span> <span class="self">self</span>.<span class="ident">addr</span>.<span class="ident">send</span>(<span class="ident">cmd</span>).<span class="kw">await</span><span class="question-mark">?</span> {
<span class="prelude-val">Ok</span>(<span class="ident">RespValue::Integer</span>(<span class="kw">_</span>)) =&gt; <span class="prelude-val">Ok</span>(()),
<span class="ident">val</span> =&gt; <span class="prelude-val">Err</span>(<span class="macro">anyhow::anyhow!</span>(
<span class="kw">match </span><span class="self">self</span>.addr.send(cmd).<span class="kw">await</span><span class="question-mark">? </span>{
<span class="prelude-val">Ok</span>(RespValue::Integer(<span class="kw">_</span>)) =&gt; <span class="prelude-val">Ok</span>(()),
val =&gt; <span class="prelude-val">Err</span>(<span class="macro">anyhow::anyhow!</span>(
<span class="string">&quot;Failed to update the session state TTL: {:?}&quot;</span>,
<span class="ident">val</span>
val
)),
}
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">delete</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">session_key</span>: <span class="kw-2">&amp;</span><span class="ident">SessionKey</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">cache_key</span> <span class="op">=</span> (<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cache_keygen</span>)(<span class="ident">session_key</span>.<span class="ident">as_ref</span>());
<span class="kw">async fn </span>delete(<span class="kw-2">&amp;</span><span class="self">self</span>, session_key: <span class="kw-2">&amp;</span>SessionKey) -&gt; <span class="prelude-ty">Result</span>&lt;(), anyhow::Error&gt; {
<span class="kw">let </span>cache_key = (<span class="self">self</span>.configuration.cache_keygen)(session_key.as_ref());
<span class="kw">let</span> <span class="ident">res</span> <span class="op">=</span> <span class="self">self</span>
.<span class="ident">addr</span>
.<span class="ident">send</span>(<span class="ident">Command</span>(<span class="macro">resp_array!</span>[<span class="string">&quot;DEL&quot;</span>, <span class="ident">cache_key</span>]))
<span class="kw">let </span>res = <span class="self">self
</span>.addr
.send(Command(<span class="macro">resp_array!</span>[<span class="string">&quot;DEL&quot;</span>, cache_key]))
.<span class="kw">await</span><span class="question-mark">?</span>;
<span class="kw">match</span> <span class="ident">res</span> {
<span class="comment">// Redis returns the number of deleted records</span>
<span class="prelude-val">Ok</span>(<span class="ident">RespValue::Integer</span>(<span class="kw">_</span>)) =&gt; <span class="prelude-val">Ok</span>(()),
<span class="ident">val</span> =&gt; <span class="prelude-val">Err</span>(<span class="macro">anyhow::anyhow!</span>(
<span class="kw">match </span>res {
<span class="comment">// Redis returns the number of deleted records
</span><span class="prelude-val">Ok</span>(RespValue::Integer(<span class="kw">_</span>)) =&gt; <span class="prelude-val">Ok</span>(()),
val =&gt; <span class="prelude-val">Err</span>(<span class="macro">anyhow::anyhow!</span>(
<span class="string">&quot;Failed to remove session from cache. {:?}&quot;</span>,
<span class="ident">val</span>
val
)),
}
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="ident">std::collections::HashMap</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::collections::HashMap;
<span class="kw">use</span> <span class="ident">actix_web::cookie::time::Duration</span>;
<span class="kw">use </span>actix_web::cookie::time::Duration;
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::test_helpers::acceptance_test_suite</span>;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use </span><span class="kw">crate</span>::test_helpers::acceptance_test_suite;
<span class="kw">fn</span> <span class="ident">redis_actor_store</span>() -&gt; <span class="ident">RedisActorSessionStore</span> {
<span class="ident">RedisActorSessionStore::new</span>(<span class="string">&quot;127.0.0.1:6379&quot;</span>)
<span class="kw">fn </span>redis_actor_store() -&gt; RedisActorSessionStore {
RedisActorSessionStore::new(<span class="string">&quot;127.0.0.1:6379&quot;</span>)
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_session_workflow</span>() {
<span class="ident">acceptance_test_suite</span>(<span class="ident">redis_actor_store</span>, <span class="bool-val">true</span>).<span class="kw">await</span>;
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_session_workflow() {
acceptance_test_suite(redis_actor_store, <span class="bool-val">true</span>).<span class="kw">await</span>;
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">loading_a_missing_session_returns_none</span>() {
<span class="kw">let</span> <span class="ident">store</span> <span class="op">=</span> <span class="ident">redis_actor_store</span>();
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">generate_session_key</span>();
<span class="macro">assert!</span>(<span class="ident">store</span>.<span class="ident">load</span>(<span class="kw-2">&amp;</span><span class="ident">session_key</span>).<span class="kw">await</span>.<span class="ident">unwrap</span>().<span class="ident">is_none</span>());
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>loading_a_missing_session_returns_none() {
<span class="kw">let </span>store = redis_actor_store();
<span class="kw">let </span>session_key = generate_session_key();
<span class="macro">assert!</span>(store.load(<span class="kw-2">&amp;</span>session_key).<span class="kw">await</span>.unwrap().is_none());
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">updating_of_an_expired_state_is_handled_gracefully</span>() {
<span class="kw">let</span> <span class="ident">store</span> <span class="op">=</span> <span class="ident">redis_actor_store</span>();
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">generate_session_key</span>();
<span class="kw">let</span> <span class="ident">initial_session_key</span> <span class="op">=</span> <span class="ident">session_key</span>.<span class="ident">as_ref</span>().<span class="ident">to_owned</span>();
<span class="kw">let</span> <span class="ident">updated_session_key</span> <span class="op">=</span> <span class="ident">store</span>
.<span class="ident">update</span>(<span class="ident">session_key</span>, <span class="ident">HashMap::new</span>(), <span class="kw-2">&amp;</span><span class="ident">Duration::seconds</span>(<span class="number">1</span>))
.<span class="kw">await</span>
.<span class="ident">unwrap</span>();
<span class="macro">assert_ne!</span>(<span class="ident">initial_session_key</span>, <span class="ident">updated_session_key</span>.<span class="ident">as_ref</span>());
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>updating_of_an_expired_state_is_handled_gracefully() {
<span class="kw">let </span>store = redis_actor_store();
<span class="kw">let </span>session_key = generate_session_key();
<span class="kw">let </span>initial_session_key = session_key.as_ref().to_owned();
<span class="kw">let </span>updated_session_key = store
.update(session_key, HashMap::new(), <span class="kw-2">&amp;</span>Duration::seconds(<span class="number">1</span>))
.<span class="kw">await
</span>.unwrap();
<span class="macro">assert_ne!</span>(initial_session_key, updated_session_key.as_ref());
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -347,239 +347,239 @@
<span id="345">345</span>
<span id="346">346</span>
<span id="347">347</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">convert::TryInto</span>, <span class="ident">sync::Arc</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{convert::TryInto, sync::Arc};
<span class="kw">use</span> <span class="ident">actix_web::cookie::time::Duration</span>;
<span class="kw">use</span> <span class="ident">anyhow</span>::{<span class="ident">Context</span>, <span class="ident">Error</span>};
<span class="kw">use</span> <span class="ident">redis</span>::{<span class="ident">aio::ConnectionManager</span>, <span class="ident">AsyncCommands</span>, <span class="ident">Cmd</span>, <span class="ident">FromRedisValue</span>, <span class="ident">RedisResult</span>, <span class="ident">Value</span>};
<span class="kw">use </span>actix_web::cookie::time::Duration;
<span class="kw">use </span>anyhow::{Context, Error};
<span class="kw">use </span>redis::{aio::ConnectionManager, AsyncCommands, Cmd, FromRedisValue, RedisResult, Value};
<span class="kw">use</span> <span class="ident"><span class="kw">super</span>::SessionKey</span>;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::storage</span>::{
<span class="ident">interface</span>::{<span class="ident">LoadError</span>, <span class="ident">SaveError</span>, <span class="ident">SessionState</span>, <span class="ident">UpdateError</span>},
<span class="ident">utils::generate_session_key</span>,
<span class="ident">SessionStore</span>,
<span class="kw">use </span><span class="kw">super</span>::SessionKey;
<span class="kw">use </span><span class="kw">crate</span>::storage::{
interface::{LoadError, SaveError, SessionState, UpdateError},
utils::generate_session_key,
SessionStore,
};
<span class="doccomment">/// Use Redis as session storage backend.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ```no_run</span>
<span class="doccomment">/// use actix_web::{web, App, HttpServer, HttpResponse, Error};</span>
<span class="doccomment">/// use actix_session::{SessionMiddleware, storage::RedisSessionStore};</span>
<span class="doccomment">/// use actix_web::cookie::Key;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// // The secret key would usually be read from a configuration file/environment variables.</span>
<span class="doccomment">/// fn get_secret_key() -&gt; Key {</span>
<span class="doccomment">/// # todo!()</span>
<span class="doccomment">/// // [...]</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[actix_web::main]</span>
<span class="doccomment">/// async fn main() -&gt; std::io::Result&lt;()&gt; {</span>
<span class="doccomment">/// let secret_key = get_secret_key();</span>
<span class="doccomment">/// let redis_connection_string = &quot;redis://127.0.0.1:6379&quot;;</span>
<span class="doccomment">/// let store = RedisSessionStore::new(redis_connection_string).await.unwrap();</span>
<span class="doccomment">///</span>
<span class="doccomment">/// HttpServer::new(move ||</span>
<span class="doccomment">/// App::new()</span>
<span class="doccomment">/// .wrap(SessionMiddleware::new(</span>
<span class="doccomment">/// store.clone(),</span>
<span class="doccomment">/// secret_key.clone()</span>
<span class="doccomment">/// ))</span>
<span class="doccomment">/// .default_service(web::to(|| HttpResponse::Ok())))</span>
<span class="doccomment">/// .bind((&quot;127.0.0.1&quot;, 8080))?</span>
<span class="doccomment">/// .run()</span>
<span class="doccomment">/// .await</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # TLS support</span>
<span class="doccomment">/// Add the `redis-rs-tls-session` feature flag to enable TLS support. You can then establish a TLS</span>
<span class="doccomment">/// connection to Redis using the `rediss://` URL scheme:</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ```no_run</span>
<span class="doccomment">/// use actix_session::{storage::RedisSessionStore};</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # actix_web::rt::System::new().block_on(async {</span>
<span class="doccomment">/// let redis_connection_string = &quot;rediss://127.0.0.1:6379&quot;;</span>
<span class="doccomment">/// let store = RedisSessionStore::new(redis_connection_string).await.unwrap();</span>
<span class="doccomment">/// # })</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Implementation notes</span>
<span class="doccomment">/// `RedisSessionStore` leverages [`redis-rs`] as Redis client.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`redis-rs`]: https://github.com/mitsuhiko/redis-rs</span>
<span class="attribute">#[<span class="ident">cfg_attr</span>(<span class="ident">docsrs</span>, <span class="ident">doc</span>(<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;redis-rs-session&quot;</span>)))]</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">RedisSessionStore</span> {
<span class="ident">configuration</span>: <span class="ident">CacheConfiguration</span>,
<span class="ident">client</span>: <span class="ident">ConnectionManager</span>,
<span class="doccomment">/// Use Redis as session storage backend.
///
/// ```no_run
/// use actix_web::{web, App, HttpServer, HttpResponse, Error};
/// use actix_session::{SessionMiddleware, storage::RedisSessionStore};
/// use actix_web::cookie::Key;
///
/// // The secret key would usually be read from a configuration file/environment variables.
/// fn get_secret_key() -&gt; Key {
/// # todo!()
/// // [...]
/// }
///
/// #[actix_web::main]
/// async fn main() -&gt; std::io::Result&lt;()&gt; {
/// let secret_key = get_secret_key();
/// let redis_connection_string = &quot;redis://127.0.0.1:6379&quot;;
/// let store = RedisSessionStore::new(redis_connection_string).await.unwrap();
///
/// HttpServer::new(move ||
/// App::new()
/// .wrap(SessionMiddleware::new(
/// store.clone(),
/// secret_key.clone()
/// ))
/// .default_service(web::to(|| HttpResponse::Ok())))
/// .bind((&quot;127.0.0.1&quot;, 8080))?
/// .run()
/// .await
/// }
/// ```
///
/// # TLS support
/// Add the `redis-rs-tls-session` feature flag to enable TLS support. You can then establish a TLS
/// connection to Redis using the `rediss://` URL scheme:
///
/// ```no_run
/// use actix_session::{storage::RedisSessionStore};
///
/// # actix_web::rt::System::new().block_on(async {
/// let redis_connection_string = &quot;rediss://127.0.0.1:6379&quot;;
/// let store = RedisSessionStore::new(redis_connection_string).await.unwrap();
/// # })
/// ```
///
/// # Implementation notes
/// `RedisSessionStore` leverages [`redis-rs`] as Redis client.
///
/// [`redis-rs`]: https://github.com/mitsuhiko/redis-rs
</span><span class="attribute">#[cfg_attr(docsrs, doc(cfg(feature = <span class="string">&quot;redis-rs-session&quot;</span>)))]
#[derive(Clone)]
</span><span class="kw">pub struct </span>RedisSessionStore {
configuration: CacheConfiguration,
client: ConnectionManager,
}
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Clone</span>)]</span>
<span class="kw">struct</span> <span class="ident">CacheConfiguration</span> {
<span class="ident">cache_keygen</span>: <span class="ident">Arc</span><span class="op">&lt;</span><span class="kw">dyn</span> <span class="ident">Fn</span>(<span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="ident">String</span> <span class="op">+</span> <span class="ident">Send</span> <span class="op">+</span> <span class="ident">Sync</span><span class="op">&gt;</span>,
<span class="attribute">#[derive(Clone)]
</span><span class="kw">struct </span>CacheConfiguration {
cache_keygen: Arc&lt;<span class="kw">dyn </span>Fn(<span class="kw-2">&amp;</span>str) -&gt; String + Send + Sync&gt;,
}
<span class="kw">impl</span> <span class="ident">Default</span> <span class="kw">for</span> <span class="ident">CacheConfiguration</span> {
<span class="kw">fn</span> <span class="ident">default</span>() -&gt; <span class="self">Self</span> {
<span class="self">Self</span> {
<span class="ident">cache_keygen</span>: <span class="ident">Arc::new</span>(<span class="ident">str::to_owned</span>),
<span class="kw">impl </span>Default <span class="kw">for </span>CacheConfiguration {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{
cache_keygen: Arc::new(str::to_owned),
}
}
}
<span class="kw">impl</span> <span class="ident">RedisSessionStore</span> {
<span class="doccomment">/// A fluent API to configure [`RedisSessionStore`].</span>
<span class="doccomment">/// It takes as input the only required input to create a new instance of [`RedisSessionStore`] - a</span>
<span class="doccomment">/// connection string for Redis.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">builder</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span><span class="op">&gt;</span>(<span class="ident">connection_string</span>: <span class="ident">S</span>) -&gt; <span class="ident">RedisSessionStoreBuilder</span> {
<span class="ident">RedisSessionStoreBuilder</span> {
<span class="ident">configuration</span>: <span class="ident">CacheConfiguration::default</span>(),
<span class="ident">connection_string</span>: <span class="ident">connection_string</span>.<span class="ident">into</span>(),
<span class="kw">impl </span>RedisSessionStore {
<span class="doccomment">/// A fluent API to configure [`RedisSessionStore`].
/// It takes as input the only required input to create a new instance of [`RedisSessionStore`] - a
/// connection string for Redis.
</span><span class="kw">pub fn </span>builder&lt;S: Into&lt;String&gt;&gt;(connection_string: S) -&gt; RedisSessionStoreBuilder {
RedisSessionStoreBuilder {
configuration: CacheConfiguration::default(),
connection_string: connection_string.into(),
}
}
<span class="doccomment">/// Create a new instance of [`RedisSessionStore`] using the default configuration.</span>
<span class="doccomment">/// It takes as input the only required input to create a new instance of [`RedisSessionStore`] - a</span>
<span class="doccomment">/// connection string for Redis.</span>
<span class="kw">pub</span> <span class="kw">async</span> <span class="kw">fn</span> <span class="ident">new</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span><span class="op">&gt;</span>(
<span class="ident">connection_string</span>: <span class="ident">S</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">RedisSessionStore</span>, <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="ident"><span class="self">Self</span>::builder</span>(<span class="ident">connection_string</span>).<span class="ident">build</span>().<span class="kw">await</span>
}
<span class="doccomment">/// Create a new instance of [`RedisSessionStore`] using the default configuration.
/// It takes as input the only required input to create a new instance of [`RedisSessionStore`] - a
/// connection string for Redis.
</span><span class="kw">pub async fn </span>new&lt;S: Into&lt;String&gt;&gt;(
connection_string: S,
) -&gt; <span class="prelude-ty">Result</span>&lt;RedisSessionStore, anyhow::Error&gt; {
<span class="self">Self</span>::builder(connection_string).build().<span class="kw">await
</span>}
}
<span class="doccomment">/// A fluent builder to construct a [`RedisSessionStore`] instance with custom configuration</span>
<span class="doccomment">/// parameters.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`RedisSessionStore`]: crate::storage::RedisSessionStore</span>
<span class="attribute">#[<span class="ident">cfg_attr</span>(<span class="ident">docsrs</span>, <span class="ident">doc</span>(<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;redis-rs-session&quot;</span>)))]</span>
<span class="attribute">#[<span class="ident">must_use</span>]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">RedisSessionStoreBuilder</span> {
<span class="ident">connection_string</span>: <span class="ident">String</span>,
<span class="ident">configuration</span>: <span class="ident">CacheConfiguration</span>,
<span class="doccomment">/// A fluent builder to construct a [`RedisSessionStore`] instance with custom configuration
/// parameters.
///
/// [`RedisSessionStore`]: crate::storage::RedisSessionStore
</span><span class="attribute">#[cfg_attr(docsrs, doc(cfg(feature = <span class="string">&quot;redis-rs-session&quot;</span>)))]
#[must_use]
</span><span class="kw">pub struct </span>RedisSessionStoreBuilder {
connection_string: String,
configuration: CacheConfiguration,
}
<span class="kw">impl</span> <span class="ident">RedisSessionStoreBuilder</span> {
<span class="doccomment">/// Set a custom cache key generation strategy, expecting a session key as input.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">cache_keygen</span><span class="op">&lt;</span><span class="ident">F</span><span class="op">&gt;</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">keygen</span>: <span class="ident">F</span>) -&gt; <span class="self">Self</span>
<span class="kw">where</span>
<span class="ident">F</span>: <span class="ident">Fn</span>(<span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="ident">String</span> <span class="op">+</span> <span class="lifetime">&#39;static</span> <span class="op">+</span> <span class="ident">Send</span> <span class="op">+</span> <span class="ident">Sync</span>,
<span class="kw">impl </span>RedisSessionStoreBuilder {
<span class="doccomment">/// Set a custom cache key generation strategy, expecting a session key as input.
</span><span class="kw">pub fn </span>cache_keygen&lt;F&gt;(<span class="kw-2">mut </span><span class="self">self</span>, keygen: F) -&gt; <span class="self">Self
</span><span class="kw">where
</span>F: Fn(<span class="kw-2">&amp;</span>str) -&gt; String + <span class="lifetime">&#39;static </span>+ Send + Sync,
{
<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cache_keygen</span> <span class="op">=</span> <span class="ident">Arc::new</span>(<span class="ident">keygen</span>);
<span class="self">self</span>
}
<span class="self">self</span>.configuration.cache_keygen = Arc::new(keygen);
<span class="self">self
</span>}
<span class="doccomment">/// Finalise the builder and return a [`RedisActorSessionStore`] instance.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`RedisActorSessionStore`]: crate::storage::RedisActorSessionStore</span>
<span class="kw">pub</span> <span class="kw">async</span> <span class="kw">fn</span> <span class="ident">build</span>(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">RedisSessionStore</span>, <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">client</span> <span class="op">=</span> <span class="ident">ConnectionManager::new</span>(<span class="ident">redis::Client::open</span>(<span class="self">self</span>.<span class="ident">connection_string</span>)<span class="question-mark">?</span>).<span class="kw">await</span><span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(<span class="ident">RedisSessionStore</span> {
<span class="ident">configuration</span>: <span class="self">self</span>.<span class="ident">configuration</span>,
<span class="ident">client</span>,
<span class="doccomment">/// Finalise the builder and return a [`RedisActorSessionStore`] instance.
///
/// [`RedisActorSessionStore`]: crate::storage::RedisActorSessionStore
</span><span class="kw">pub async fn </span>build(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RedisSessionStore, anyhow::Error&gt; {
<span class="kw">let </span>client = ConnectionManager::new(redis::Client::open(<span class="self">self</span>.connection_string)<span class="question-mark">?</span>).<span class="kw">await</span><span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(RedisSessionStore {
configuration: <span class="self">self</span>.configuration,
client,
})
}
}
<span class="attribute">#[<span class="ident">async_trait::async_trait</span>(<span class="question-mark">?</span><span class="ident">Send</span>)]</span>
<span class="kw">impl</span> <span class="ident">SessionStore</span> <span class="kw">for</span> <span class="ident">RedisSessionStore</span> {
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">load</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">session_key</span>: <span class="kw-2">&amp;</span><span class="ident">SessionKey</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">SessionState</span><span class="op">&gt;</span>, <span class="ident">LoadError</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">cache_key</span> <span class="op">=</span> (<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cache_keygen</span>)(<span class="ident">session_key</span>.<span class="ident">as_ref</span>());
<span class="attribute">#[async_trait::async_trait(<span class="question-mark">?</span>Send)]
</span><span class="kw">impl </span>SessionStore <span class="kw">for </span>RedisSessionStore {
<span class="kw">async fn </span>load(<span class="kw-2">&amp;</span><span class="self">self</span>, session_key: <span class="kw-2">&amp;</span>SessionKey) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;SessionState&gt;, LoadError&gt; {
<span class="kw">let </span>cache_key = (<span class="self">self</span>.configuration.cache_keygen)(session_key.as_ref());
<span class="kw">let</span> <span class="ident">value</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span> <span class="op">=</span> <span class="self">self</span>
.<span class="ident">execute_command</span>(<span class="ident">redis::cmd</span>(<span class="string">&quot;GET&quot;</span>).<span class="ident">arg</span>(<span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span><span class="ident">cache_key</span>]))
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">LoadError::Other</span>)<span class="question-mark">?</span>;
<span class="kw">let </span>value: <span class="prelude-ty">Option</span>&lt;String&gt; = <span class="self">self
</span>.execute_command(redis::cmd(<span class="string">&quot;GET&quot;</span>).arg(<span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span>cache_key]))
.<span class="kw">await
</span>.map_err(Into::into)
.map_err(LoadError::Other)<span class="question-mark">?</span>;
<span class="kw">match</span> <span class="ident">value</span> {
<span class="prelude-val">None</span> =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>),
<span class="prelude-val">Some</span>(<span class="ident">value</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">serde_json::from_str</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>)
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">LoadError::Deserialization</span>)<span class="question-mark">?</span>),
<span class="kw">match </span>value {
<span class="prelude-val">None </span>=&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>),
<span class="prelude-val">Some</span>(value) =&gt; <span class="prelude-val">Ok</span>(serde_json::from_str(<span class="kw-2">&amp;</span>value)
.map_err(Into::into)
.map_err(LoadError::Deserialization)<span class="question-mark">?</span>),
}
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">save</span>(
<span class="kw">async fn </span>save(
<span class="kw-2">&amp;</span><span class="self">self</span>,
<span class="ident">session_state</span>: <span class="ident">SessionState</span>,
<span class="ident">ttl</span>: <span class="kw-2">&amp;</span><span class="ident">Duration</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">SessionKey</span>, <span class="ident">SaveError</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">body</span> <span class="op">=</span> <span class="ident">serde_json::to_string</span>(<span class="kw-2">&amp;</span><span class="ident">session_state</span>)
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">SaveError::Serialization</span>)<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">generate_session_key</span>();
<span class="kw">let</span> <span class="ident">cache_key</span> <span class="op">=</span> (<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cache_keygen</span>)(<span class="ident">session_key</span>.<span class="ident">as_ref</span>());
session_state: SessionState,
ttl: <span class="kw-2">&amp;</span>Duration,
) -&gt; <span class="prelude-ty">Result</span>&lt;SessionKey, SaveError&gt; {
<span class="kw">let </span>body = serde_json::to_string(<span class="kw-2">&amp;</span>session_state)
.map_err(Into::into)
.map_err(SaveError::Serialization)<span class="question-mark">?</span>;
<span class="kw">let </span>session_key = generate_session_key();
<span class="kw">let </span>cache_key = (<span class="self">self</span>.configuration.cache_keygen)(session_key.as_ref());
<span class="self">self</span>.<span class="ident">execute_command</span>(<span class="ident">redis::cmd</span>(<span class="string">&quot;SET&quot;</span>).<span class="ident">arg</span>(<span class="kw-2">&amp;</span>[
<span class="kw-2">&amp;</span><span class="ident">cache_key</span>,
<span class="kw-2">&amp;</span><span class="ident">body</span>,
<span class="string">&quot;NX&quot;</span>, <span class="comment">// NX: only set the key if it does not already exist</span>
<span class="string">&quot;EX&quot;</span>, <span class="comment">// EX: set expiry</span>
<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">&quot;{}&quot;</span>, <span class="ident">ttl</span>.<span class="ident">whole_seconds</span>()),
<span class="self">self</span>.execute_command(redis::cmd(<span class="string">&quot;SET&quot;</span>).arg(<span class="kw-2">&amp;</span>[
<span class="kw-2">&amp;</span>cache_key,
<span class="kw-2">&amp;</span>body,
<span class="string">&quot;NX&quot;</span>, <span class="comment">// NX: only set the key if it does not already exist
</span><span class="string">&quot;EX&quot;</span>, <span class="comment">// EX: set expiry
</span><span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">&quot;{}&quot;</span>, ttl.whole_seconds()),
]))
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">SaveError::Other</span>)<span class="question-mark">?</span>;
.<span class="kw">await
</span>.map_err(Into::into)
.map_err(SaveError::Other)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(<span class="ident">session_key</span>)
<span class="prelude-val">Ok</span>(session_key)
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">update</span>(
<span class="kw">async fn </span>update(
<span class="kw-2">&amp;</span><span class="self">self</span>,
<span class="ident">session_key</span>: <span class="ident">SessionKey</span>,
<span class="ident">session_state</span>: <span class="ident">SessionState</span>,
<span class="ident">ttl</span>: <span class="kw-2">&amp;</span><span class="ident">Duration</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">SessionKey</span>, <span class="ident">UpdateError</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">body</span> <span class="op">=</span> <span class="ident">serde_json::to_string</span>(<span class="kw-2">&amp;</span><span class="ident">session_state</span>)
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">UpdateError::Serialization</span>)<span class="question-mark">?</span>;
session_key: SessionKey,
session_state: SessionState,
ttl: <span class="kw-2">&amp;</span>Duration,
) -&gt; <span class="prelude-ty">Result</span>&lt;SessionKey, UpdateError&gt; {
<span class="kw">let </span>body = serde_json::to_string(<span class="kw-2">&amp;</span>session_state)
.map_err(Into::into)
.map_err(UpdateError::Serialization)<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">cache_key</span> <span class="op">=</span> (<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cache_keygen</span>)(<span class="ident">session_key</span>.<span class="ident">as_ref</span>());
<span class="kw">let </span>cache_key = (<span class="self">self</span>.configuration.cache_keygen)(session_key.as_ref());
<span class="kw">let</span> <span class="ident">v</span>: <span class="ident">redis::Value</span> <span class="op">=</span> <span class="self">self</span>
.<span class="ident">execute_command</span>(<span class="ident">redis::cmd</span>(<span class="string">&quot;SET&quot;</span>).<span class="ident">arg</span>(<span class="kw-2">&amp;</span>[
<span class="kw-2">&amp;</span><span class="ident">cache_key</span>,
<span class="kw-2">&amp;</span><span class="ident">body</span>,
<span class="string">&quot;XX&quot;</span>, <span class="comment">// XX: Only set the key if it already exist.</span>
<span class="string">&quot;EX&quot;</span>, <span class="comment">// EX: set expiry</span>
<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">&quot;{}&quot;</span>, <span class="ident">ttl</span>.<span class="ident">whole_seconds</span>()),
<span class="kw">let </span>v: redis::Value = <span class="self">self
</span>.execute_command(redis::cmd(<span class="string">&quot;SET&quot;</span>).arg(<span class="kw-2">&amp;</span>[
<span class="kw-2">&amp;</span>cache_key,
<span class="kw-2">&amp;</span>body,
<span class="string">&quot;XX&quot;</span>, <span class="comment">// XX: Only set the key if it already exist.
</span><span class="string">&quot;EX&quot;</span>, <span class="comment">// EX: set expiry
</span><span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">&quot;{}&quot;</span>, ttl.whole_seconds()),
]))
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">UpdateError::Other</span>)<span class="question-mark">?</span>;
.<span class="kw">await
</span>.map_err(Into::into)
.map_err(UpdateError::Other)<span class="question-mark">?</span>;
<span class="kw">match</span> <span class="ident">v</span> {
<span class="ident">Value::Nil</span> =&gt; {
<span class="comment">// The SET operation was not performed because the XX condition was not verified.</span>
<span class="comment">// This can happen if the session state expired between the load operation and the</span>
<span class="comment">// update operation. Unlucky, to say the least. We fall back to the `save` routine</span>
<span class="comment">// to ensure that the new key is unique.</span>
<span class="self">self</span>.<span class="ident">save</span>(<span class="ident">session_state</span>, <span class="ident">ttl</span>)
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="op">|</span><span class="ident">err</span><span class="op">|</span> <span class="kw">match</span> <span class="ident">err</span> {
<span class="ident">SaveError::Serialization</span>(<span class="ident">err</span>) =&gt; <span class="ident">UpdateError::Serialization</span>(<span class="ident">err</span>),
<span class="ident">SaveError::Other</span>(<span class="ident">err</span>) =&gt; <span class="ident">UpdateError::Other</span>(<span class="ident">err</span>),
<span class="kw">match </span>v {
Value::Nil =&gt; {
<span class="comment">// The SET operation was not performed because the XX condition was not verified.
// This can happen if the session state expired between the load operation and the
// update operation. Unlucky, to say the least. We fall back to the `save` routine
// to ensure that the new key is unique.
</span><span class="self">self</span>.save(session_state, ttl)
.<span class="kw">await
</span>.map_err(|err| <span class="kw">match </span>err {
SaveError::Serialization(err) =&gt; UpdateError::Serialization(err),
SaveError::Other(err) =&gt; UpdateError::Other(err),
})
}
<span class="ident">Value::Int</span>(<span class="kw">_</span>) <span class="op">|</span> <span class="ident">Value::Okay</span> <span class="op">|</span> <span class="ident">Value::Status</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">session_key</span>),
<span class="ident">val</span> =&gt; <span class="prelude-val">Err</span>(<span class="ident">UpdateError::Other</span>(<span class="macro">anyhow::anyhow!</span>(
Value::Int(<span class="kw">_</span>) | Value::Okay | Value::Status(<span class="kw">_</span>) =&gt; <span class="prelude-val">Ok</span>(session_key),
val =&gt; <span class="prelude-val">Err</span>(UpdateError::Other(<span class="macro">anyhow::anyhow!</span>(
<span class="string">&quot;Failed to update session state. {:?}&quot;</span>,
<span class="ident">val</span>
val
))),
}
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">update_ttl</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">session_key</span>: <span class="kw-2">&amp;</span><span class="ident">SessionKey</span>, <span class="ident">ttl</span>: <span class="kw-2">&amp;</span><span class="ident">Duration</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">cache_key</span> <span class="op">=</span> (<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cache_keygen</span>)(<span class="ident">session_key</span>.<span class="ident">as_ref</span>());
<span class="kw">async fn </span>update_ttl(<span class="kw-2">&amp;</span><span class="self">self</span>, session_key: <span class="kw-2">&amp;</span>SessionKey, ttl: <span class="kw-2">&amp;</span>Duration) -&gt; <span class="prelude-ty">Result</span>&lt;(), Error&gt; {
<span class="kw">let </span>cache_key = (<span class="self">self</span>.configuration.cache_keygen)(session_key.as_ref());
<span class="self">self</span>.<span class="ident">client</span>
.<span class="ident">clone</span>()
.<span class="ident">expire</span>(
<span class="kw-2">&amp;</span><span class="ident">cache_key</span>,
<span class="ident">ttl</span>.<span class="ident">whole_seconds</span>().<span class="ident">try_into</span>().<span class="ident">context</span>(
<span class="self">self</span>.client
.clone()
.expire(
<span class="kw-2">&amp;</span>cache_key,
ttl.whole_seconds().try_into().context(
<span class="string">&quot;Failed to convert the state TTL into the number of whole seconds remaining&quot;</span>,
)<span class="question-mark">?</span>,
)
@@ -587,49 +587,49 @@
<span class="prelude-val">Ok</span>(())
}
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">delete</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">session_key</span>: <span class="kw-2">&amp;</span><span class="ident">SessionKey</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">anyhow::Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">cache_key</span> <span class="op">=</span> (<span class="self">self</span>.<span class="ident">configuration</span>.<span class="ident">cache_keygen</span>)(<span class="ident">session_key</span>.<span class="ident">as_ref</span>());
<span class="self">self</span>.<span class="ident">execute_command</span>(<span class="ident">redis::cmd</span>(<span class="string">&quot;DEL&quot;</span>).<span class="ident">arg</span>(<span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span><span class="ident">cache_key</span>]))
.<span class="kw">await</span>
.<span class="ident">map_err</span>(<span class="ident">Into::into</span>)
.<span class="ident">map_err</span>(<span class="ident">UpdateError::Other</span>)<span class="question-mark">?</span>;
<span class="kw">async fn </span>delete(<span class="kw-2">&amp;</span><span class="self">self</span>, session_key: <span class="kw-2">&amp;</span>SessionKey) -&gt; <span class="prelude-ty">Result</span>&lt;(), anyhow::Error&gt; {
<span class="kw">let </span>cache_key = (<span class="self">self</span>.configuration.cache_keygen)(session_key.as_ref());
<span class="self">self</span>.execute_command(redis::cmd(<span class="string">&quot;DEL&quot;</span>).arg(<span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span>cache_key]))
.<span class="kw">await
</span>.map_err(Into::into)
.map_err(UpdateError::Other)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(())
}
}
<span class="kw">impl</span> <span class="ident">RedisSessionStore</span> {
<span class="doccomment">/// Execute Redis command and retry once in certain cases.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// `ConnectionManager` automatically reconnects when it encounters an error talking to Redis.</span>
<span class="doccomment">/// The request that bumped into the error, though, fails.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// This is generally OK, but there is an unpleasant edge case: Redis client timeouts. The</span>
<span class="doccomment">/// server is configured to drop connections who have been active longer than a pre-determined</span>
<span class="doccomment">/// threshold. `redis-rs` does not proactively detect that the connection has been dropped - you</span>
<span class="doccomment">/// only find out when you try to use it.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// This helper method catches this case (`.is_connection_dropped`) to execute a retry. The</span>
<span class="doccomment">/// retry will be executed on a fresh connection, therefore it is likely to succeed (or fail for</span>
<span class="doccomment">/// a different more meaningful reason).</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">execute_command</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">FromRedisValue</span><span class="op">&gt;</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">cmd</span>: <span class="kw-2">&amp;mut</span> <span class="ident">Cmd</span>) -&gt; <span class="ident">RedisResult</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">can_retry</span> <span class="op">=</span> <span class="bool-val">true</span>;
<span class="kw">impl </span>RedisSessionStore {
<span class="doccomment">/// Execute Redis command and retry once in certain cases.
///
/// `ConnectionManager` automatically reconnects when it encounters an error talking to Redis.
/// The request that bumped into the error, though, fails.
///
/// This is generally OK, but there is an unpleasant edge case: Redis client timeouts. The
/// server is configured to drop connections who have been active longer than a pre-determined
/// threshold. `redis-rs` does not proactively detect that the connection has been dropped - you
/// only find out when you try to use it.
///
/// This helper method catches this case (`.is_connection_dropped`) to execute a retry. The
/// retry will be executed on a fresh connection, therefore it is likely to succeed (or fail for
/// a different more meaningful reason).
</span><span class="kw">async fn </span>execute_command&lt;T: FromRedisValue&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, cmd: <span class="kw-2">&amp;mut </span>Cmd) -&gt; RedisResult&lt;T&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>can_retry = <span class="bool-val">true</span>;
<span class="kw">loop</span> {
<span class="kw">match</span> <span class="ident">cmd</span>.<span class="ident">query_async</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>.<span class="ident">client</span>.<span class="ident">clone</span>()).<span class="kw">await</span> {
<span class="prelude-val">Ok</span>(<span class="ident">value</span>) =&gt; <span class="kw">return</span> <span class="prelude-val">Ok</span>(<span class="ident">value</span>),
<span class="prelude-val">Err</span>(<span class="ident">err</span>) =&gt; {
<span class="kw">if</span> <span class="ident">can_retry</span> <span class="op">&amp;&amp;</span> <span class="ident">err</span>.<span class="ident">is_connection_dropped</span>() {
<span class="kw">loop </span>{
<span class="kw">match </span>cmd.query_async(<span class="kw-2">&amp;mut </span><span class="self">self</span>.client.clone()).<span class="kw">await </span>{
<span class="prelude-val">Ok</span>(value) =&gt; <span class="kw">return </span><span class="prelude-val">Ok</span>(value),
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="kw">if </span>can_retry &amp;&amp; err.is_connection_dropped() {
<span class="macro">tracing::debug!</span>(
<span class="string">&quot;Connection dropped while trying to talk to Redis. Retrying.&quot;</span>
);
<span class="string">&quot;Connection dropped while trying to talk to Redis. Retrying.&quot;
</span>);
<span class="comment">// Retry at most once</span>
<span class="ident">can_retry</span> <span class="op">=</span> <span class="bool-val">false</span>;
<span class="comment">// Retry at most once
</span>can_retry = <span class="bool-val">false</span>;
<span class="kw">continue</span>;
} <span class="kw">else</span> {
<span class="kw">return</span> <span class="prelude-val">Err</span>(<span class="ident">err</span>);
} <span class="kw">else </span>{
<span class="kw">return </span><span class="prelude-val">Err</span>(err);
}
}
}
@@ -637,62 +637,62 @@
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="ident">std::collections::HashMap</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::collections::HashMap;
<span class="kw">use</span> <span class="ident">actix_web::cookie::time</span>;
<span class="kw">use</span> <span class="ident">redis::AsyncCommands</span>;
<span class="kw">use </span>actix_web::cookie::time;
<span class="kw">use </span>redis::AsyncCommands;
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::test_helpers::acceptance_test_suite</span>;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use </span><span class="kw">crate</span>::test_helpers::acceptance_test_suite;
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">redis_store</span>() -&gt; <span class="ident">RedisSessionStore</span> {
<span class="ident">RedisSessionStore::new</span>(<span class="string">&quot;redis://127.0.0.1:6379&quot;</span>)
.<span class="kw">await</span>
.<span class="ident">unwrap</span>()
<span class="kw">async fn </span>redis_store() -&gt; RedisSessionStore {
RedisSessionStore::new(<span class="string">&quot;redis://127.0.0.1:6379&quot;</span>)
.<span class="kw">await
</span>.unwrap()
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_session_workflow</span>() {
<span class="kw">let</span> <span class="ident">redis_store</span> <span class="op">=</span> <span class="ident">redis_store</span>().<span class="kw">await</span>;
<span class="ident">acceptance_test_suite</span>(<span class="kw">move</span> <span class="op">|</span><span class="op">|</span> <span class="ident">redis_store</span>.<span class="ident">clone</span>(), <span class="bool-val">true</span>).<span class="kw">await</span>;
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_session_workflow() {
<span class="kw">let </span>redis_store = redis_store().<span class="kw">await</span>;
acceptance_test_suite(<span class="kw">move </span>|| redis_store.clone(), <span class="bool-val">true</span>).<span class="kw">await</span>;
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">loading_a_missing_session_returns_none</span>() {
<span class="kw">let</span> <span class="ident">store</span> <span class="op">=</span> <span class="ident">redis_store</span>().<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">generate_session_key</span>();
<span class="macro">assert!</span>(<span class="ident">store</span>.<span class="ident">load</span>(<span class="kw-2">&amp;</span><span class="ident">session_key</span>).<span class="kw">await</span>.<span class="ident">unwrap</span>().<span class="ident">is_none</span>());
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>loading_a_missing_session_returns_none() {
<span class="kw">let </span>store = redis_store().<span class="kw">await</span>;
<span class="kw">let </span>session_key = generate_session_key();
<span class="macro">assert!</span>(store.load(<span class="kw-2">&amp;</span>session_key).<span class="kw">await</span>.unwrap().is_none());
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">loading_an_invalid_session_state_returns_deserialization_error</span>() {
<span class="kw">let</span> <span class="ident">store</span> <span class="op">=</span> <span class="ident">redis_store</span>().<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">generate_session_key</span>();
<span class="ident">store</span>
.<span class="ident">client</span>
.<span class="ident">clone</span>()
.<span class="ident">set</span>::<span class="op">&lt;</span><span class="kw">_</span>, <span class="kw">_</span>, ()<span class="op">&gt;</span>(<span class="ident">session_key</span>.<span class="ident">as_ref</span>(), <span class="string">&quot;random-thing-which-is-not-json&quot;</span>)
.<span class="kw">await</span>
.<span class="ident">unwrap</span>();
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>loading_an_invalid_session_state_returns_deserialization_error() {
<span class="kw">let </span>store = redis_store().<span class="kw">await</span>;
<span class="kw">let </span>session_key = generate_session_key();
store
.client
.clone()
.set::&lt;<span class="kw">_</span>, <span class="kw">_</span>, ()&gt;(session_key.as_ref(), <span class="string">&quot;random-thing-which-is-not-json&quot;</span>)
.<span class="kw">await
</span>.unwrap();
<span class="macro">assert!</span>(<span class="macro">matches!</span>(
<span class="ident">store</span>.<span class="ident">load</span>(<span class="kw-2">&amp;</span><span class="ident">session_key</span>).<span class="kw">await</span>.<span class="ident">unwrap_err</span>(),
<span class="ident">LoadError::Deserialization</span>(<span class="kw">_</span>),
store.load(<span class="kw-2">&amp;</span>session_key).<span class="kw">await</span>.unwrap_err(),
LoadError::Deserialization(<span class="kw">_</span>),
));
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">updating_of_an_expired_state_is_handled_gracefully</span>() {
<span class="kw">let</span> <span class="ident">store</span> <span class="op">=</span> <span class="ident">redis_store</span>().<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">session_key</span> <span class="op">=</span> <span class="ident">generate_session_key</span>();
<span class="kw">let</span> <span class="ident">initial_session_key</span> <span class="op">=</span> <span class="ident">session_key</span>.<span class="ident">as_ref</span>().<span class="ident">to_owned</span>();
<span class="kw">let</span> <span class="ident">updated_session_key</span> <span class="op">=</span> <span class="ident">store</span>
.<span class="ident">update</span>(<span class="ident">session_key</span>, <span class="ident">HashMap::new</span>(), <span class="kw-2">&amp;</span><span class="ident">time::Duration::seconds</span>(<span class="number">1</span>))
.<span class="kw">await</span>
.<span class="ident">unwrap</span>();
<span class="macro">assert_ne!</span>(<span class="ident">initial_session_key</span>, <span class="ident">updated_session_key</span>.<span class="ident">as_ref</span>());
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>updating_of_an_expired_state_is_handled_gracefully() {
<span class="kw">let </span>store = redis_store().<span class="kw">await</span>;
<span class="kw">let </span>session_key = generate_session_key();
<span class="kw">let </span>initial_session_key = session_key.as_ref().to_owned();
<span class="kw">let </span>updated_session_key = store
.update(session_key, HashMap::new(), <span class="kw-2">&amp;</span>time::Duration::seconds(<span class="number">1</span>))
.<span class="kw">await
</span>.unwrap();
<span class="macro">assert_ne!</span>(initial_session_key, updated_session_key.as_ref());
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -58,63 +58,63 @@
<span id="56">56</span>
<span id="57">57</span>
<span id="58">58</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::convert::TryFrom</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::convert::TryFrom;
<span class="kw">use</span> <span class="ident">derive_more</span>::{<span class="ident">Display</span>, <span class="ident">From</span>};
<span class="kw">use </span>derive_more::{Display, From};
<span class="doccomment">/// A session key, the string stored in a client-side cookie to associate a user with its session</span>
<span class="doccomment">/// state on the backend.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Validation</span>
<span class="doccomment">/// Session keys are stored as cookies, therefore they cannot be arbitrary long. Session keys are</span>
<span class="doccomment">/// required to be smaller than 4064 bytes.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ```rust</span>
<span class="doccomment">/// # use std::convert::TryInto;</span>
<span class="doccomment">/// use actix_session::storage::SessionKey;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// let key: String = std::iter::repeat(&#39;a&#39;).take(4065).collect();</span>
<span class="doccomment">/// let session_key: Result&lt;SessionKey, _&gt; = key.try_into();</span>
<span class="doccomment">/// assert!(session_key.is_err());</span>
<span class="doccomment">/// ```</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">SessionKey</span>(<span class="ident">String</span>);
<span class="doccomment">/// A session key, the string stored in a client-side cookie to associate a user with its session
/// state on the backend.
///
/// # Validation
/// Session keys are stored as cookies, therefore they cannot be arbitrary long. Session keys are
/// required to be smaller than 4064 bytes.
///
/// ```rust
/// # use std::convert::TryInto;
/// use actix_session::storage::SessionKey;
///
/// let key: String = std::iter::repeat(&#39;a&#39;).take(4065).collect();
/// let session_key: Result&lt;SessionKey, _&gt; = key.try_into();
/// assert!(session_key.is_err());
/// ```
</span><span class="attribute">#[derive(Debug, PartialEq, Eq)]
</span><span class="kw">pub struct </span>SessionKey(String);
<span class="kw">impl</span> <span class="ident">TryFrom</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">SessionKey</span> {
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">InvalidSessionKeyError</span>;
<span class="kw">impl </span>TryFrom&lt;String&gt; <span class="kw">for </span>SessionKey {
<span class="kw">type </span>Error = InvalidSessionKeyError;
<span class="kw">fn</span> <span class="ident">try_from</span>(<span class="ident">val</span>: <span class="ident">String</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span> {
<span class="kw">if</span> <span class="ident">val</span>.<span class="ident">len</span>() <span class="op">&gt;</span> <span class="number">4064</span> {
<span class="kw">return</span> <span class="prelude-val">Err</span>(<span class="macro">anyhow::anyhow!</span>(
<span class="string">&quot;The session key is bigger than 4064 bytes, the upper limit on cookie content.&quot;</span>
)
.<span class="ident">into</span>());
<span class="kw">fn </span>try_from(val: String) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, <span class="self">Self</span>::Error&gt; {
<span class="kw">if </span>val.len() &gt; <span class="number">4064 </span>{
<span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">anyhow::anyhow!</span>(
<span class="string">&quot;The session key is bigger than 4064 bytes, the upper limit on cookie content.&quot;
</span>)
.into());
}
<span class="prelude-val">Ok</span>(<span class="ident">SessionKey</span>(<span class="ident">val</span>))
<span class="prelude-val">Ok</span>(SessionKey(val))
}
}
<span class="kw">impl</span> <span class="ident">AsRef</span><span class="op">&lt;</span><span class="ident">str</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">SessionKey</span> {
<span class="kw">fn</span> <span class="ident">as_ref</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="ident">str</span> {
<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0</span>
}
<span class="kw">impl </span>AsRef&lt;str&gt; <span class="kw">for </span>SessionKey {
<span class="kw">fn </span>as_ref(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0
</span>}
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">SessionKey</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">String</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">key</span>: <span class="ident">SessionKey</span>) -&gt; <span class="self">Self</span> {
<span class="ident">key</span>.<span class="number">0</span>
}
<span class="kw">impl </span>From&lt;SessionKey&gt; <span class="kw">for </span>String {
<span class="kw">fn </span>from(key: SessionKey) -&gt; <span class="self">Self </span>{
key.<span class="number">0
</span>}
}
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Display</span>, <span class="ident">From</span>)]</span>
<span class="attribute">#[<span class="ident">display</span>(<span class="ident">fmt</span> <span class="op">=</span> <span class="string">&quot;The provided string is not a valid session key&quot;</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">InvalidSessionKeyError</span>(<span class="ident">anyhow::Error</span>);
<span class="attribute">#[derive(Debug, Display, From)]
#[display(fmt = <span class="string">&quot;The provided string is not a valid session key&quot;</span>)]
</span><span class="kw">pub struct </span>InvalidSessionKeyError(anyhow::Error);
<span class="kw">impl</span> <span class="ident">std::error::Error</span> <span class="kw">for</span> <span class="ident">InvalidSessionKeyError</span> {
<span class="kw">fn</span> <span class="ident">source</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="kw-2">&amp;</span>(<span class="kw">dyn</span> <span class="ident">std::error::Error</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>)<span class="op">&gt;</span> {
<span class="prelude-val">Some</span>(<span class="self">self</span>.<span class="number">0</span>.<span class="ident">as_ref</span>())
<span class="kw">impl </span>std::error::Error <span class="kw">for </span>InvalidSessionKeyError {
<span class="kw">fn </span>source(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>(<span class="kw">dyn </span>std::error::Error + <span class="lifetime">&#39;static</span>)&gt; {
<span class="prelude-val">Some</span>(<span class="self">self</span>.<span class="number">0</span>.as_ref())
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -19,24 +19,24 @@
<span id="17">17</span>
<span id="18">18</span>
<span id="19">19</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::convert::TryInto</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::convert::TryInto;
<span class="kw">use</span> <span class="ident">rand</span>::{<span class="ident">distributions::Alphanumeric</span>, <span class="ident">rngs::OsRng</span>, <span class="ident">Rng</span> <span class="kw">as</span> <span class="kw">_</span>};
<span class="kw">use </span>rand::{distributions::Alphanumeric, rngs::OsRng, Rng <span class="kw">as _</span>};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::storage::SessionKey</span>;
<span class="kw">use </span><span class="kw">crate</span>::storage::SessionKey;
<span class="doccomment">/// Session key generation routine that follows [OWASP recommendations].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [OWASP recommendations]: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#session-id-entropy</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> <span class="ident">generate_session_key</span>() -&gt; <span class="ident">SessionKey</span> {
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">std::iter::repeat</span>(())
.<span class="ident">map</span>(<span class="op">|</span>()<span class="op">|</span> <span class="ident">OsRng</span>.<span class="ident">sample</span>(<span class="ident">Alphanumeric</span>))
.<span class="ident">take</span>(<span class="number">64</span>)
.<span class="ident">collect</span>::<span class="op">&lt;</span><span class="ident">Vec</span><span class="op">&lt;</span><span class="kw">_</span><span class="op">&gt;</span><span class="op">&gt;</span>();
<span class="doccomment">/// Session key generation routine that follows [OWASP recommendations].
///
/// [OWASP recommendations]: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#session-id-entropy
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>generate_session_key() -&gt; SessionKey {
<span class="kw">let </span>value = std::iter::repeat(())
.map(|()| OsRng.sample(Alphanumeric))
.take(<span class="number">64</span>)
.collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;();
<span class="comment">// These unwraps will never panic because pre-conditions are always verified</span>
<span class="comment">// (i.e. length and character set)</span>
<span class="ident">String::from_utf8</span>(<span class="ident">value</span>).<span class="ident">unwrap</span>().<span class="ident">try_into</span>().<span class="ident">unwrap</span>()
<span class="comment">// These unwraps will never panic because pre-conditions are always verified
// (i.e. length and character set)
</span>String::from_utf8(value).unwrap().try_into().unwrap()
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -138,143 +138,143 @@
<span id="136">136</span>
<span id="137">137</span>
<span id="138">138</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">env::VarError</span>, <span class="ident">io</span>, <span class="ident">num::ParseIntError</span>, <span class="ident">path::PathBuf</span>, <span class="ident">str::ParseBoolError</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{env::VarError, io, num::ParseIntError, path::PathBuf, str::ParseBoolError};
<span class="kw">use</span> <span class="ident">toml::de::Error</span> <span class="kw">as</span> <span class="ident">TomlError</span>;
<span class="kw">use </span>toml::de::Error <span class="kw">as </span>TomlError;
<span class="doccomment">/// Errors that can be returned from methods in this crate.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">Error</span> {
<span class="doccomment">/// Environment variable does not exists or is invalid.</span>
<span class="ident">EnvVarError</span>(<span class="ident">VarError</span>),
<span class="doccomment">/// Errors that can be returned from methods in this crate.
</span><span class="attribute">#[derive(Debug, Clone)]
</span><span class="kw">pub enum </span>Error {
<span class="doccomment">/// Environment variable does not exists or is invalid.
</span>EnvVarError(VarError),
<span class="doccomment">/// File already exists on disk.</span>
<span class="ident">FileExists</span>(<span class="ident">PathBuf</span>),
<span class="doccomment">/// File already exists on disk.
</span>FileExists(PathBuf),
<span class="doccomment">/// Invalid value.</span>
<span class="attribute">#[<span class="ident">allow</span>(<span class="ident">missing_docs</span>)]</span>
<span class="ident">InvalidValue</span> {
<span class="ident">expected</span>: <span class="kw-2">&amp;</span><span class="lifetime">&#39;static</span> <span class="ident">str</span>,
<span class="ident">got</span>: <span class="ident">String</span>,
<span class="ident">file</span>: <span class="kw-2">&amp;</span><span class="lifetime">&#39;static</span> <span class="ident">str</span>,
<span class="ident">line</span>: <span class="ident">u32</span>,
<span class="ident">column</span>: <span class="ident">u32</span>,
<span class="doccomment">/// Invalid value.
</span><span class="attribute">#[allow(missing_docs)]
</span>InvalidValue {
expected: <span class="kw-2">&amp;</span><span class="lifetime">&#39;static </span>str,
got: String,
file: <span class="kw-2">&amp;</span><span class="lifetime">&#39;static </span>str,
line: u32,
column: u32,
},
<span class="doccomment">/// I/O error.</span>
<span class="ident">IoError</span>(<span class="ident">ioe::IoError</span>),
<span class="doccomment">/// I/O error.
</span>IoError(ioe::IoError),
<span class="doccomment">/// Value is not a boolean.</span>
<span class="ident">ParseBoolError</span>(<span class="ident">ParseBoolError</span>),
<span class="doccomment">/// Value is not a boolean.
</span>ParseBoolError(ParseBoolError),
<span class="doccomment">/// Value is not an integer.</span>
<span class="ident">ParseIntError</span>(<span class="ident">ParseIntError</span>),
<span class="doccomment">/// Value is not an integer.
</span>ParseIntError(ParseIntError),
<span class="doccomment">/// Value is not an address.</span>
<span class="ident">ParseAddressError</span>(<span class="ident">String</span>),
<span class="doccomment">/// Value is not an address.
</span>ParseAddressError(String),
<span class="doccomment">/// Error deserializing as TOML.</span>
<span class="ident">TomlError</span>(<span class="ident">TomlError</span>),
<span class="doccomment">/// Error deserializing as TOML.
</span>TomlError(TomlError),
}
<span class="macro">macro_rules!</span> <span class="ident">InvalidValue</span> {
(<span class="ident">expected</span>: <span class="macro-nonterminal">$</span><span class="macro-nonterminal">expected</span>:<span class="ident">expr</span>, <span class="ident">got</span>: <span class="macro-nonterminal">$</span><span class="macro-nonterminal">got</span>:<span class="ident">expr</span>,) =&gt; {
<span class="ident"><span class="kw">crate</span>::Error::InvalidValue</span> {
<span class="ident">expected</span>: <span class="macro-nonterminal">$</span><span class="macro-nonterminal">expected</span>,
<span class="ident">got</span>: <span class="macro-nonterminal">$</span><span class="macro-nonterminal">got</span>.<span class="ident">to_string</span>(),
<span class="ident">file</span>: <span class="macro">file!</span>(),
<span class="ident">line</span>: <span class="macro">line!</span>(),
<span class="ident">column</span>: <span class="macro">column!</span>(),
<span class="macro">macro_rules! </span>InvalidValue {
(expected: <span class="macro-nonterminal">$expected</span>:expr, got: <span class="macro-nonterminal">$got</span>:expr,) =&gt; {
<span class="kw">crate</span>::Error::InvalidValue {
expected: <span class="macro-nonterminal">$expected</span>,
got: <span class="macro-nonterminal">$got</span>.to_string(),
file: <span class="macro">file!</span>(),
line: <span class="macro">line!</span>(),
column: <span class="macro">column!</span>(),
}
};
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">io::Error</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Error</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">err</span>: <span class="ident">io::Error</span>) -&gt; <span class="self">Self</span> {
<span class="ident"><span class="self">Self</span>::IoError</span>(<span class="ident">ioe::IoError::from</span>(<span class="ident">err</span>))
<span class="kw">impl </span>From&lt;io::Error&gt; <span class="kw">for </span>Error {
<span class="kw">fn </span>from(err: io::Error) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::IoError(ioe::IoError::from(err))
}
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">ioe::IoError</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Error</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">err</span>: <span class="ident">ioe::IoError</span>) -&gt; <span class="self">Self</span> {
<span class="ident"><span class="self">Self</span>::IoError</span>(<span class="ident">err</span>)
<span class="kw">impl </span>From&lt;ioe::IoError&gt; <span class="kw">for </span>Error {
<span class="kw">fn </span>from(err: ioe::IoError) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::IoError(err)
}
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">ParseBoolError</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Error</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">err</span>: <span class="ident">ParseBoolError</span>) -&gt; <span class="self">Self</span> {
<span class="ident"><span class="self">Self</span>::ParseBoolError</span>(<span class="ident">err</span>)
<span class="kw">impl </span>From&lt;ParseBoolError&gt; <span class="kw">for </span>Error {
<span class="kw">fn </span>from(err: ParseBoolError) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::ParseBoolError(err)
}
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">ParseIntError</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Error</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">err</span>: <span class="ident">ParseIntError</span>) -&gt; <span class="self">Self</span> {
<span class="ident"><span class="self">Self</span>::ParseIntError</span>(<span class="ident">err</span>)
<span class="kw">impl </span>From&lt;ParseIntError&gt; <span class="kw">for </span>Error {
<span class="kw">fn </span>from(err: ParseIntError) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::ParseIntError(err)
}
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">TomlError</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Error</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">err</span>: <span class="ident">TomlError</span>) -&gt; <span class="self">Self</span> {
<span class="ident"><span class="self">Self</span>::TomlError</span>(<span class="ident">err</span>)
<span class="kw">impl </span>From&lt;TomlError&gt; <span class="kw">for </span>Error {
<span class="kw">fn </span>from(err: TomlError) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::TomlError(err)
}
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">VarError</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Error</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">err</span>: <span class="ident">VarError</span>) -&gt; <span class="self">Self</span> {
<span class="ident"><span class="self">Self</span>::EnvVarError</span>(<span class="ident">err</span>)
<span class="kw">impl </span>From&lt;VarError&gt; <span class="kw">for </span>Error {
<span class="kw">fn </span>from(err: VarError) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::EnvVarError(err)
}
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">Error</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">io::Error</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">err</span>: <span class="ident">Error</span>) -&gt; <span class="self">Self</span> {
<span class="kw">match</span> <span class="ident">err</span> {
<span class="ident">Error::EnvVarError</span>(<span class="ident">var_error</span>) =&gt; {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="macro">format!</span>(<span class="string">&quot;Env var error: {}&quot;</span>, <span class="ident">var_error</span>);
<span class="ident">io::Error::new</span>(<span class="ident">io::ErrorKind::InvalidInput</span>, <span class="ident">msg</span>)
<span class="kw">impl </span>From&lt;Error&gt; <span class="kw">for </span>io::Error {
<span class="kw">fn </span>from(err: Error) -&gt; <span class="self">Self </span>{
<span class="kw">match </span>err {
Error::EnvVarError(var_error) =&gt; {
<span class="kw">let </span>msg = <span class="macro">format!</span>(<span class="string">&quot;Env var error: {}&quot;</span>, var_error);
io::Error::new(io::ErrorKind::InvalidInput, msg)
}
<span class="ident">Error::FileExists</span>(<span class="ident">path_buf</span>) =&gt; {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="macro">format!</span>(<span class="string">&quot;File exists: {}&quot;</span>, <span class="ident">path_buf</span>.<span class="ident">display</span>());
<span class="ident">io::Error::new</span>(<span class="ident">io::ErrorKind::AlreadyExists</span>, <span class="ident">msg</span>)
Error::FileExists(path_buf) =&gt; {
<span class="kw">let </span>msg = <span class="macro">format!</span>(<span class="string">&quot;File exists: {}&quot;</span>, path_buf.display());
io::Error::new(io::ErrorKind::AlreadyExists, msg)
}
<span class="ident">Error::InvalidValue</span> {
<span class="ident">expected</span>,
<span class="kw-2">ref</span> <span class="ident">got</span>,
<span class="ident">file</span>,
<span class="ident">line</span>,
<span class="ident">column</span>,
Error::InvalidValue {
expected,
<span class="kw-2">ref </span>got,
file,
line,
column,
} =&gt; {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="macro">format!</span>(
<span class="kw">let </span>msg = <span class="macro">format!</span>(
<span class="string">&quot;Expected {}, got {} (@ {}:{}:{})&quot;</span>,
<span class="ident">expected</span>, <span class="ident">got</span>, <span class="ident">file</span>, <span class="ident">line</span>, <span class="ident">column</span>
expected, got, file, line, column
);
<span class="ident">io::Error::new</span>(<span class="ident">io::ErrorKind::InvalidInput</span>, <span class="ident">msg</span>)
io::Error::new(io::ErrorKind::InvalidInput, msg)
}
<span class="ident">Error::IoError</span>(<span class="ident">io_error</span>) =&gt; <span class="ident">io_error</span>.<span class="ident">into</span>(),
Error::IoError(io_error) =&gt; io_error.into(),
<span class="ident">Error::ParseBoolError</span>(<span class="ident">parse_bool_error</span>) =&gt; {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="macro">format!</span>(<span class="string">&quot;Failed to parse boolean: {}&quot;</span>, <span class="ident">parse_bool_error</span>);
<span class="ident">io::Error::new</span>(<span class="ident">io::ErrorKind::InvalidInput</span>, <span class="ident">msg</span>)
Error::ParseBoolError(parse_bool_error) =&gt; {
<span class="kw">let </span>msg = <span class="macro">format!</span>(<span class="string">&quot;Failed to parse boolean: {}&quot;</span>, parse_bool_error);
io::Error::new(io::ErrorKind::InvalidInput, msg)
}
<span class="ident">Error::ParseIntError</span>(<span class="ident">parse_int_error</span>) =&gt; {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="macro">format!</span>(<span class="string">&quot;Failed to parse integer: {}&quot;</span>, <span class="ident">parse_int_error</span>);
<span class="ident">io::Error::new</span>(<span class="ident">io::ErrorKind::InvalidInput</span>, <span class="ident">msg</span>)
Error::ParseIntError(parse_int_error) =&gt; {
<span class="kw">let </span>msg = <span class="macro">format!</span>(<span class="string">&quot;Failed to parse integer: {}&quot;</span>, parse_int_error);
io::Error::new(io::ErrorKind::InvalidInput, msg)
}
<span class="ident">Error::ParseAddressError</span>(<span class="ident">string</span>) =&gt; {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="macro">format!</span>(<span class="string">&quot;Failed to parse address: {}&quot;</span>, <span class="ident">string</span>);
<span class="ident">io::Error::new</span>(<span class="ident">io::ErrorKind::InvalidInput</span>, <span class="ident">msg</span>)
Error::ParseAddressError(string) =&gt; {
<span class="kw">let </span>msg = <span class="macro">format!</span>(<span class="string">&quot;Failed to parse address: {}&quot;</span>, string);
io::Error::new(io::ErrorKind::InvalidInput, msg)
}
<span class="ident">Error::TomlError</span>(<span class="ident">toml_error</span>) =&gt; {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="macro">format!</span>(<span class="string">&quot;TOML error: {}&quot;</span>, <span class="ident">toml_error</span>);
<span class="ident">io::Error::new</span>(<span class="ident">io::ErrorKind::InvalidInput</span>, <span class="ident">msg</span>)
Error::TomlError(toml_error) =&gt; {
<span class="kw">let </span>msg = <span class="macro">format!</span>(<span class="string">&quot;TOML error: {}&quot;</span>, toml_error);
io::Error::new(io::ErrorKind::InvalidInput, msg)
}
}
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

File diff suppressed because it is too large Load Diff

View File

@@ -40,45 +40,45 @@
<span id="38">38</span>
<span id="39">39</span>
<span id="40">40</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">path::PathBuf</span>, <span class="ident">str::FromStr</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{path::PathBuf, str::FromStr};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::Error</span>;
<span class="kw">use </span><span class="kw">crate</span>::Error;
<span class="doccomment">/// A specialized `FromStr` trait that returns [`AtError`] errors</span>
<span class="kw">pub</span> <span class="kw">trait</span> <span class="ident">Parse</span>: <span class="ident">Sized</span> {
<span class="doccomment">/// Parse `Self` from `string`.</span>
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">Error</span><span class="op">&gt;</span>;
<span class="doccomment">/// A specialized `FromStr` trait that returns [`AtError`] errors
</span><span class="kw">pub trait </span>Parse: Sized {
<span class="doccomment">/// Parse `Self` from `string`.
</span><span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, Error&gt;;
}
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="ident">bool</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="ident"><span class="self">Self</span>::from_str</span>(<span class="ident">string</span>).<span class="ident">map_err</span>(<span class="ident">Error::from</span>)
<span class="kw">impl </span>Parse <span class="kw">for </span>bool {
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, Error&gt; {
<span class="self">Self</span>::from_str(string).map_err(Error::from)
}
}
<span class="macro">macro_rules!</span> <span class="ident">impl_parse_for_int_type</span> {
($(<span class="macro-nonterminal">$</span><span class="macro-nonterminal">int_type</span>:<span class="ident">ty</span>),<span class="op">+</span> $(,)<span class="question-mark">?</span>) =&gt; {
<span class="macro">macro_rules! </span>impl_parse_for_int_type {
($(<span class="macro-nonterminal">$int_type</span>:ty),+ $(,)<span class="question-mark">?</span>) =&gt; {
$(
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="macro-nonterminal">$</span><span class="macro-nonterminal">int_type</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="ident"><span class="self">Self</span>::from_str</span>(<span class="ident">string</span>).<span class="ident">map_err</span>(<span class="ident">Error::from</span>)
<span class="kw">impl </span>Parse <span class="kw">for </span><span class="macro-nonterminal">$int_type </span>{
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, Error&gt; {
<span class="self">Self</span>::from_str(string).map_err(Error::from)
}
}
)<span class="op">+</span>
)+
}
}
<span class="macro">impl_parse_for_int_type!</span>[<span class="ident">i8</span>, <span class="ident">i16</span>, <span class="ident">i32</span>, <span class="ident">i64</span>, <span class="ident">i128</span>, <span class="ident">u8</span>, <span class="ident">u16</span>, <span class="ident">u32</span>, <span class="ident">u64</span>, <span class="ident">u128</span>];
<span class="macro">impl_parse_for_int_type!</span>[i8, i16, i32, i64, i128, u8, u16, u32, u64, u128];
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="ident">String</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="prelude-val">Ok</span>(<span class="ident">string</span>.<span class="ident">to_string</span>())
<span class="kw">impl </span>Parse <span class="kw">for </span>String {
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, Error&gt; {
<span class="prelude-val">Ok</span>(string.to_string())
}
}
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="ident">PathBuf</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="prelude-val">Ok</span>(<span class="ident">PathBuf::from</span>(<span class="ident">string</span>))
<span class="kw">impl </span>Parse <span class="kw">for </span>PathBuf {
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, Error&gt; {
<span class="prelude-val">Ok</span>(PathBuf::from(string))
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -93,14 +93,14 @@
<span id="91">91</span>
<span id="92">92</span>
<span id="93">93</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">once_cell::sync::Lazy</span>;
<span class="kw">use</span> <span class="ident">regex::Regex</span>;
<span class="kw">use</span> <span class="ident">serde::Deserialize</span>;
</pre><pre class="rust"><code><span class="kw">use </span>once_cell::sync::Lazy;
<span class="kw">use </span>regex::Regex;
<span class="kw">use </span>serde::Deserialize;
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">Error</span>, <span class="ident">Parse</span>};
<span class="kw">use crate</span>::{Error, Parse};
<span class="kw">static</span> <span class="ident">ADDR_REGEX</span>: <span class="ident">Lazy</span><span class="op">&lt;</span><span class="ident">Regex</span><span class="op">&gt;</span> <span class="op">=</span> <span class="ident">Lazy::new</span>(<span class="op">|</span><span class="op">|</span> {
<span class="ident">Regex::new</span>(
<span class="kw">static </span>ADDR_REGEX: Lazy&lt;Regex&gt; = Lazy::new(|| {
Regex::new(
<span class="string">r#&quot;(?x)
\[ # opening square bracket
(\s)* # optional whitespace
@@ -112,11 +112,11 @@
\] # closing square bracket
&quot;#</span>,
)
.<span class="ident">expect</span>(<span class="string">&quot;Failed to compile regex: ADDR_REGEX&quot;</span>)
.expect(<span class="string">&quot;Failed to compile regex: ADDR_REGEX&quot;</span>)
});
<span class="kw">static</span> <span class="ident">ADDR_LIST_REGEX</span>: <span class="ident">Lazy</span><span class="op">&lt;</span><span class="ident">Regex</span><span class="op">&gt;</span> <span class="op">=</span> <span class="ident">Lazy::new</span>(<span class="op">|</span><span class="op">|</span> {
<span class="ident">Regex::new</span>(
<span class="kw">static </span>ADDR_LIST_REGEX: Lazy&lt;Regex&gt; = Lazy::new(|| {
Regex::new(
<span class="string">r#&quot;(?x)
\[ # opening square bracket (list)
(\s)* # optional whitespace
@@ -129,62 +129,62 @@
\] # closing square bracket (list)
&quot;#</span>,
)
.<span class="ident">expect</span>(<span class="string">&quot;Failed to compile regex: ADDRS_REGEX&quot;</span>)
.expect(<span class="string">&quot;Failed to compile regex: ADDRS_REGEX&quot;</span>)
});
<span class="doccomment">/// A host/port pair for the server to bind to.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">Hash</span>, <span class="ident">Deserialize</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Address</span> {
<span class="doccomment">/// Host part of address.</span>
<span class="kw">pub</span> <span class="ident">host</span>: <span class="ident">String</span>,
<span class="doccomment">/// A host/port pair for the server to bind to.
</span><span class="attribute">#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
</span><span class="kw">pub struct </span>Address {
<span class="doccomment">/// Host part of address.
</span><span class="kw">pub </span>host: String,
<span class="doccomment">/// Port part of address.</span>
<span class="kw">pub</span> <span class="ident">port</span>: <span class="ident">u16</span>,
<span class="doccomment">/// Port part of address.
</span><span class="kw">pub </span>port: u16,
}
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="ident">Address</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">items</span> <span class="op">=</span> <span class="ident">string</span>
.<span class="ident">trim</span>()
.<span class="ident">trim_start_matches</span>(<span class="string">&#39;[&#39;</span>)
.<span class="ident">trim_end_matches</span>(<span class="string">&#39;]&#39;</span>)
.<span class="ident">split</span>(<span class="string">&#39;,&#39;</span>);
<span class="kw">impl </span>Parse <span class="kw">for </span>Address {
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, Error&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>items = string
.trim()
.trim_start_matches(<span class="string">&#39;[&#39;</span>)
.trim_end_matches(<span class="string">&#39;]&#39;</span>)
.split(<span class="string">&#39;,&#39;</span>);
<span class="kw">let</span> <span class="ident">parse_error</span> <span class="op">=</span> <span class="op">|</span><span class="op">|</span> <span class="ident">Error::ParseAddressError</span>(<span class="ident">string</span>.<span class="ident">to_string</span>());
<span class="kw">let </span>parse_error = || Error::ParseAddressError(string.to_string());
<span class="kw">if</span> <span class="op">!</span><span class="ident">ADDR_REGEX</span>.<span class="ident">is_match</span>(<span class="ident">string</span>) {
<span class="kw">return</span> <span class="prelude-val">Err</span>(<span class="ident">parse_error</span>());
<span class="kw">if </span>!ADDR_REGEX.is_match(string) {
<span class="kw">return </span><span class="prelude-val">Err</span>(parse_error());
}
<span class="prelude-val">Ok</span>(<span class="self">Self</span> {
<span class="ident">host</span>: <span class="ident">items</span>.<span class="ident">next</span>().<span class="ident">ok_or_else</span>(<span class="ident">parse_error</span>)<span class="question-mark">?</span>.<span class="ident">trim</span>().<span class="ident">to_string</span>(),
<span class="ident">port</span>: <span class="ident">items</span>.<span class="ident">next</span>().<span class="ident">ok_or_else</span>(<span class="ident">parse_error</span>)<span class="question-mark">?</span>.<span class="ident">trim</span>().<span class="ident">parse</span>()<span class="question-mark">?</span>,
<span class="prelude-val">Ok</span>(<span class="self">Self </span>{
host: items.next().ok_or_else(parse_error)<span class="question-mark">?</span>.trim().to_string(),
port: items.next().ok_or_else(parse_error)<span class="question-mark">?</span>.trim().parse()<span class="question-mark">?</span>,
})
}
}
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="ident">Vec</span><span class="op">&lt;</span><span class="ident">Address</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">parse_error</span> <span class="op">=</span> <span class="op">|</span><span class="op">|</span> <span class="ident">Error::ParseAddressError</span>(<span class="ident">string</span>.<span class="ident">to_string</span>());
<span class="kw">impl </span>Parse <span class="kw">for </span>Vec&lt;Address&gt; {
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, Error&gt; {
<span class="kw">let </span>parse_error = || Error::ParseAddressError(string.to_string());
<span class="kw">if</span> <span class="op">!</span><span class="ident">ADDR_LIST_REGEX</span>.<span class="ident">is_match</span>(<span class="ident">string</span>) {
<span class="kw">return</span> <span class="prelude-val">Err</span>(<span class="ident">parse_error</span>());
<span class="kw">if </span>!ADDR_LIST_REGEX.is_match(string) {
<span class="kw">return </span><span class="prelude-val">Err</span>(parse_error());
}
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">addrs</span> <span class="op">=</span> <span class="macro">vec!</span>[];
<span class="kw">let </span><span class="kw-2">mut </span>addrs = <span class="macro">vec!</span>[];
<span class="kw">for</span> <span class="ident">list_caps</span> <span class="kw">in</span> <span class="ident">ADDR_LIST_REGEX</span>.<span class="ident">captures_iter</span>(<span class="ident">string</span>) {
<span class="kw">let</span> <span class="ident">elements</span> <span class="op">=</span> <span class="kw-2">&amp;</span><span class="ident">list_caps</span>[<span class="string">&quot;elements&quot;</span>].<span class="ident">trim</span>();
<span class="kw">for</span> <span class="ident">elt_caps</span> <span class="kw">in</span> <span class="ident">ADDR_REGEX</span>.<span class="ident">captures_iter</span>(<span class="ident">elements</span>) {
<span class="ident">addrs</span>.<span class="ident">push</span>(<span class="ident">Address</span> {
<span class="ident">host</span>: <span class="ident">elt_caps</span>[<span class="string">&quot;host&quot;</span>].<span class="ident">to_string</span>(),
<span class="ident">port</span>: <span class="ident">elt_caps</span>[<span class="string">&quot;port&quot;</span>].<span class="ident">parse</span>()<span class="question-mark">?</span>,
<span class="kw">for </span>list_caps <span class="kw">in </span>ADDR_LIST_REGEX.captures_iter(string) {
<span class="kw">let </span>elements = <span class="kw-2">&amp;</span>list_caps[<span class="string">&quot;elements&quot;</span>].trim();
<span class="kw">for </span>elt_caps <span class="kw">in </span>ADDR_REGEX.captures_iter(elements) {
addrs.push(Address {
host: elt_caps[<span class="string">&quot;host&quot;</span>].to_string(),
port: elt_caps[<span class="string">&quot;port&quot;</span>].parse()<span class="question-mark">?</span>,
});
}
}
<span class="prelude-val">Ok</span>(<span class="ident">addrs</span>)
<span class="prelude-val">Ok</span>(addrs)
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -70,75 +70,75 @@
<span id="68">68</span>
<span id="69">69</span>
<span id="70">70</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::fmt</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::fmt;
<span class="kw">use</span> <span class="ident">serde::de</span>;
<span class="kw">use </span>serde::de;
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">AsResult</span>, <span class="ident">Error</span>, <span class="ident">Parse</span>};
<span class="kw">use crate</span>::{AsResult, Error, Parse};
<span class="doccomment">/// The maximum number of pending connections.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// This refers to the number of clients that can be waiting to be served. Exceeding this number</span>
<span class="doccomment">/// results in the client getting an error when attempting to connect. It should only affect servers</span>
<span class="doccomment">/// under significant load.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Generally set in the 642048 range. The default value is 2048. Takes a string value: Either</span>
<span class="doccomment">/// &quot;default&quot;, or an integer N &gt; 0 e.g. &quot;6&quot;.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">Hash</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">Backlog</span> {
<span class="doccomment">/// The default number of connections. See struct docs.</span>
<span class="ident">Default</span>,
<span class="doccomment">/// The maximum number of pending connections.
///
/// This refers to the number of clients that can be waiting to be served. Exceeding this number
/// results in the client getting an error when attempting to connect. It should only affect servers
/// under significant load.
///
/// Generally set in the 642048 range. The default value is 2048. Takes a string value: Either
/// &quot;default&quot;, or an integer N &gt; 0 e.g. &quot;6&quot;.
</span><span class="attribute">#[derive(Debug, Clone, PartialEq, Eq, Hash)]
</span><span class="kw">pub enum </span>Backlog {
<span class="doccomment">/// The default number of connections. See struct docs.
</span>Default,
<span class="doccomment">/// A specific number of connections.</span>
<span class="ident">Manual</span>(<span class="ident">usize</span>),
<span class="doccomment">/// A specific number of connections.
</span>Manual(usize),
}
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="ident">Backlog</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="ident">AsResult</span><span class="op">&lt;</span><span class="self">Self</span><span class="op">&gt;</span> {
<span class="kw">match</span> <span class="ident">string</span> {
<span class="string">&quot;default&quot;</span> =&gt; <span class="prelude-val">Ok</span>(<span class="ident">Backlog::Default</span>),
<span class="ident">string</span> =&gt; <span class="kw">match</span> <span class="ident">string</span>.<span class="ident">parse</span>::<span class="op">&lt;</span><span class="ident">usize</span><span class="op">&gt;</span>() {
<span class="prelude-val">Ok</span>(<span class="ident">val</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">Backlog::Manual</span>(<span class="ident">val</span>)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(<span class="macro">InvalidValue!</span> {
<span class="ident">expected</span>: <span class="string">&quot;an integer &gt; 0&quot;</span>,
<span class="ident">got</span>: <span class="ident">string</span>,
<span class="kw">impl </span>Parse <span class="kw">for </span>Backlog {
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; AsResult&lt;<span class="self">Self</span>&gt; {
<span class="kw">match </span>string {
<span class="string">&quot;default&quot; </span>=&gt; <span class="prelude-val">Ok</span>(Backlog::Default),
string =&gt; <span class="kw">match </span>string.parse::&lt;usize&gt;() {
<span class="prelude-val">Ok</span>(val) =&gt; <span class="prelude-val">Ok</span>(Backlog::Manual(val)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(<span class="macro">InvalidValue! </span>{
expected: <span class="string">&quot;an integer &gt; 0&quot;</span>,
got: string,
}),
},
}
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="ident">de::Deserialize</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Backlog</span> {
<span class="kw">fn</span> <span class="ident">deserialize</span><span class="op">&lt;</span><span class="ident">D</span><span class="op">&gt;</span>(<span class="ident">deserializer</span>: <span class="ident">D</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">D::Error</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">D</span>: <span class="ident">de::Deserializer</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span>,
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;de</span>&gt; de::Deserialize&lt;<span class="lifetime">&#39;de</span>&gt; <span class="kw">for </span>Backlog {
<span class="kw">fn </span>deserialize&lt;D&gt;(deserializer: D) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, D::Error&gt;
<span class="kw">where
</span>D: de::Deserializer&lt;<span class="lifetime">&#39;de</span>&gt;,
{
<span class="kw">struct</span> <span class="ident">BacklogVisitor</span>;
<span class="kw">struct </span>BacklogVisitor;
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="ident">de::Visitor</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">BacklogVisitor</span> {
<span class="kw">type</span> <span class="ident">Value</span> <span class="op">=</span> <span class="ident">Backlog</span>;
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;de</span>&gt; de::Visitor&lt;<span class="lifetime">&#39;de</span>&gt; <span class="kw">for </span>BacklogVisitor {
<span class="kw">type </span>Value = Backlog;
<span class="kw">fn</span> <span class="ident">expecting</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="string">&quot;Either \&quot;default\&quot; or a string containing an integer &gt; 0&quot;</span>;
<span class="ident">f</span>.<span class="ident">write_str</span>(<span class="ident">msg</span>)
<span class="kw">fn </span>expecting(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
<span class="kw">let </span>msg = <span class="string">&quot;Either \&quot;default\&quot; or a string containing an integer &gt; 0&quot;</span>;
f.write_str(msg)
}
<span class="kw">fn</span> <span class="ident">visit_str</span><span class="op">&lt;</span><span class="ident">E</span><span class="op">&gt;</span>(<span class="self">self</span>, <span class="ident">value</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Value</span>, <span class="ident">E</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">E</span>: <span class="ident">de::Error</span>,
<span class="kw">fn </span>visit_str&lt;E&gt;(<span class="self">self</span>, value: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Value, E&gt;
<span class="kw">where
</span>E: de::Error,
{
<span class="kw">match</span> <span class="ident">Backlog::parse</span>(<span class="ident">value</span>) {
<span class="prelude-val">Ok</span>(<span class="ident">backlog</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">backlog</span>),
<span class="prelude-val">Err</span>(<span class="ident">Error::InvalidValue</span> { <span class="ident">expected</span>, <span class="ident">got</span>, .. }) =&gt; <span class="prelude-val">Err</span>(
<span class="ident">de::Error::invalid_value</span>(<span class="ident">de::Unexpected::Str</span>(<span class="kw-2">&amp;</span><span class="ident">got</span>), <span class="kw-2">&amp;</span><span class="ident">expected</span>),
<span class="kw">match </span>Backlog::parse(value) {
<span class="prelude-val">Ok</span>(backlog) =&gt; <span class="prelude-val">Ok</span>(backlog),
<span class="prelude-val">Err</span>(Error::InvalidValue { expected, got, .. }) =&gt; <span class="prelude-val">Err</span>(
de::Error::invalid_value(de::Unexpected::Str(<span class="kw-2">&amp;</span>got), <span class="kw-2">&amp;</span>expected),
),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="macro">unreachable!</span>(),
}
}
}
<span class="ident">deserializer</span>.<span class="ident">deserialize_string</span>(<span class="ident">BacklogVisitor</span>)
deserializer.deserialize_string(BacklogVisitor)
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -95,100 +95,100 @@
<span id="93">93</span>
<span id="94">94</span>
<span id="95">95</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::fmt</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::fmt;
<span class="kw">use</span> <span class="ident">once_cell::sync::Lazy</span>;
<span class="kw">use</span> <span class="ident">regex::Regex</span>;
<span class="kw">use</span> <span class="ident">serde::de</span>;
<span class="kw">use </span>once_cell::sync::Lazy;
<span class="kw">use </span>regex::Regex;
<span class="kw">use </span>serde::de;
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">AsResult</span>, <span class="ident">Error</span>, <span class="ident">Parse</span>};
<span class="kw">use crate</span>::{AsResult, Error, Parse};
<span class="doccomment">/// The server keep-alive preference.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// By default keep alive is set to 5 seconds. Takes a string value: Either &quot;default&quot;, &quot;disabled&quot;,</span>
<span class="doccomment">/// &quot;os&quot;, or a string of the format &quot;N seconds&quot; where N is an integer &gt; 0 e.g. &quot;6 seconds&quot;.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">Hash</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">KeepAlive</span> {
<span class="doccomment">/// The default keep-alive as defined by Actix Web.</span>
<span class="ident">Default</span>,
<span class="doccomment">/// The server keep-alive preference.
///
/// By default keep alive is set to 5 seconds. Takes a string value: Either &quot;default&quot;, &quot;disabled&quot;,
/// &quot;os&quot;, or a string of the format &quot;N seconds&quot; where N is an integer &gt; 0 e.g. &quot;6 seconds&quot;.
</span><span class="attribute">#[derive(Debug, Clone, PartialEq, Eq, Hash)]
</span><span class="kw">pub enum </span>KeepAlive {
<span class="doccomment">/// The default keep-alive as defined by Actix Web.
</span>Default,
<span class="doccomment">/// Disable keep-alive.</span>
<span class="ident">Disabled</span>,
<span class="doccomment">/// Disable keep-alive.
</span>Disabled,
<span class="doccomment">/// Let the OS determine keep-alive duration.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Note: this is usually quite long.</span>
<span class="ident">Os</span>,
<span class="doccomment">/// Let the OS determine keep-alive duration.
///
/// Note: this is usually quite long.
</span>Os,
<span class="doccomment">/// A specific keep-alive duration (in seconds).</span>
<span class="ident">Seconds</span>(<span class="ident">usize</span>),
<span class="doccomment">/// A specific keep-alive duration (in seconds).
</span>Seconds(usize),
}
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="ident">KeepAlive</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="ident">AsResult</span><span class="op">&lt;</span><span class="self">Self</span><span class="op">&gt;</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">static</span> <span class="ident">FMT</span>: <span class="ident">Lazy</span><span class="op">&lt;</span><span class="ident">Regex</span><span class="op">&gt;</span> <span class="op">=</span>
<span class="ident">Lazy::new</span>(<span class="op">|</span><span class="op">|</span> <span class="ident">Regex::new</span>(<span class="string">r&quot;^\d+ seconds$&quot;</span>).<span class="ident">expect</span>(<span class="string">&quot;Failed to compile regex: FMT&quot;</span>));
<span class="kw">impl </span>Parse <span class="kw">for </span>KeepAlive {
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; AsResult&lt;<span class="self">Self</span>&gt; {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">static </span>FMT: Lazy&lt;Regex&gt; =
Lazy::new(|| Regex::new(<span class="string">r&quot;^\d+ seconds$&quot;</span>).expect(<span class="string">&quot;Failed to compile regex: FMT&quot;</span>));
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">static</span> <span class="ident">DIGITS</span>: <span class="ident">Lazy</span><span class="op">&lt;</span><span class="ident">Regex</span><span class="op">&gt;</span> <span class="op">=</span>
<span class="ident">Lazy::new</span>(<span class="op">|</span><span class="op">|</span> <span class="ident">Regex::new</span>(<span class="string">r&quot;^\d+&quot;</span>).<span class="ident">expect</span>(<span class="string">&quot;Failed to compile regex: FMT&quot;</span>));
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">static </span>DIGITS: Lazy&lt;Regex&gt; =
Lazy::new(|| Regex::new(<span class="string">r&quot;^\d+&quot;</span>).expect(<span class="string">&quot;Failed to compile regex: FMT&quot;</span>));
<span class="macro">macro_rules!</span> <span class="ident">invalid_value</span> {
(<span class="macro-nonterminal">$</span><span class="macro-nonterminal">got</span>:<span class="ident">expr</span>) =&gt; {
<span class="prelude-val">Err</span>(<span class="macro">InvalidValue!</span> {
<span class="ident">expected</span>: <span class="string">&quot;a string of the format \&quot;N seconds\&quot; where N is an integer &gt; 0&quot;</span>,
<span class="ident">got</span>: <span class="macro-nonterminal">$</span><span class="macro-nonterminal">got</span>,
<span class="macro">macro_rules! </span>invalid_value {
(<span class="macro-nonterminal">$got</span>:expr) =&gt; {
<span class="prelude-val">Err</span>(<span class="macro">InvalidValue! </span>{
expected: <span class="string">&quot;a string of the format \&quot;N seconds\&quot; where N is an integer &gt; 0&quot;</span>,
got: <span class="macro-nonterminal">$got</span>,
})
};
}
<span class="kw">let</span> <span class="ident">digits_in</span> <span class="op">=</span> <span class="op">|</span><span class="ident">m</span>: <span class="ident">regex::Match</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span><span class="op">|</span> <span class="kw-2">&amp;</span><span class="ident">string</span>[<span class="ident">m</span>.<span class="ident">start</span>()..<span class="ident">m</span>.<span class="ident">end</span>()];
<span class="kw">match</span> <span class="ident">string</span> {
<span class="string">&quot;default&quot;</span> =&gt; <span class="prelude-val">Ok</span>(<span class="ident">KeepAlive::Default</span>),
<span class="string">&quot;disabled&quot;</span> =&gt; <span class="prelude-val">Ok</span>(<span class="ident">KeepAlive::Disabled</span>),
<span class="string">&quot;OS&quot;</span> <span class="op">|</span> <span class="string">&quot;os&quot;</span> =&gt; <span class="prelude-val">Ok</span>(<span class="ident">KeepAlive::Os</span>),
<span class="ident">string</span> <span class="kw">if</span> <span class="op">!</span><span class="ident">FMT</span>.<span class="ident">is_match</span>(<span class="ident">string</span>) =&gt; <span class="macro">invalid_value!</span>(<span class="ident">string</span>),
<span class="ident">string</span> =&gt; <span class="kw">match</span> <span class="ident">DIGITS</span>.<span class="ident">find</span>(<span class="ident">string</span>) {
<span class="prelude-val">None</span> =&gt; <span class="macro">invalid_value!</span>(<span class="ident">string</span>),
<span class="prelude-val">Some</span>(<span class="ident">mat</span>) =&gt; <span class="kw">match</span> <span class="ident">digits_in</span>(<span class="ident">mat</span>).<span class="ident">parse</span>() {
<span class="prelude-val">Ok</span>(<span class="ident">val</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">KeepAlive::Seconds</span>(<span class="ident">val</span>)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="macro">invalid_value!</span>(<span class="ident">string</span>),
<span class="kw">let </span>digits_in = |m: regex::Match&lt;<span class="lifetime">&#39;_</span>&gt;| <span class="kw-2">&amp;</span>string[m.start()..m.end()];
<span class="kw">match </span>string {
<span class="string">&quot;default&quot; </span>=&gt; <span class="prelude-val">Ok</span>(KeepAlive::Default),
<span class="string">&quot;disabled&quot; </span>=&gt; <span class="prelude-val">Ok</span>(KeepAlive::Disabled),
<span class="string">&quot;OS&quot; </span>| <span class="string">&quot;os&quot; </span>=&gt; <span class="prelude-val">Ok</span>(KeepAlive::Os),
string <span class="kw">if </span>!FMT.is_match(string) =&gt; <span class="macro">invalid_value!</span>(string),
string =&gt; <span class="kw">match </span>DIGITS.find(string) {
<span class="prelude-val">None </span>=&gt; <span class="macro">invalid_value!</span>(string),
<span class="prelude-val">Some</span>(mat) =&gt; <span class="kw">match </span>digits_in(mat).parse() {
<span class="prelude-val">Ok</span>(val) =&gt; <span class="prelude-val">Ok</span>(KeepAlive::Seconds(val)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="macro">invalid_value!</span>(string),
},
},
}
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="ident">de::Deserialize</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">KeepAlive</span> {
<span class="kw">fn</span> <span class="ident">deserialize</span><span class="op">&lt;</span><span class="ident">D</span><span class="op">&gt;</span>(<span class="ident">deserializer</span>: <span class="ident">D</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">D::Error</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">D</span>: <span class="ident">de::Deserializer</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span>,
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;de</span>&gt; de::Deserialize&lt;<span class="lifetime">&#39;de</span>&gt; <span class="kw">for </span>KeepAlive {
<span class="kw">fn </span>deserialize&lt;D&gt;(deserializer: D) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, D::Error&gt;
<span class="kw">where
</span>D: de::Deserializer&lt;<span class="lifetime">&#39;de</span>&gt;,
{
<span class="kw">struct</span> <span class="ident">KeepAliveVisitor</span>;
<span class="kw">struct </span>KeepAliveVisitor;
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="ident">de::Visitor</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">KeepAliveVisitor</span> {
<span class="kw">type</span> <span class="ident">Value</span> <span class="op">=</span> <span class="ident">KeepAlive</span>;
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;de</span>&gt; de::Visitor&lt;<span class="lifetime">&#39;de</span>&gt; <span class="kw">for </span>KeepAliveVisitor {
<span class="kw">type </span>Value = KeepAlive;
<span class="kw">fn</span> <span class="ident">expecting</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="string">&quot;Either \&quot;default\&quot;, \&quot;disabled\&quot;, \&quot;os\&quot;, or a string of the format \&quot;N seconds\&quot; where N is an integer &gt; 0&quot;</span>;
<span class="ident">f</span>.<span class="ident">write_str</span>(<span class="ident">msg</span>)
<span class="kw">fn </span>expecting(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
<span class="kw">let </span>msg = <span class="string">&quot;Either \&quot;default\&quot;, \&quot;disabled\&quot;, \&quot;os\&quot;, or a string of the format \&quot;N seconds\&quot; where N is an integer &gt; 0&quot;</span>;
f.write_str(msg)
}
<span class="kw">fn</span> <span class="ident">visit_str</span><span class="op">&lt;</span><span class="ident">E</span><span class="op">&gt;</span>(<span class="self">self</span>, <span class="ident">value</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Value</span>, <span class="ident">E</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">E</span>: <span class="ident">de::Error</span>,
<span class="kw">fn </span>visit_str&lt;E&gt;(<span class="self">self</span>, value: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Value, E&gt;
<span class="kw">where
</span>E: de::Error,
{
<span class="kw">match</span> <span class="ident">KeepAlive::parse</span>(<span class="ident">value</span>) {
<span class="prelude-val">Ok</span>(<span class="ident">keep_alive</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">keep_alive</span>),
<span class="prelude-val">Err</span>(<span class="ident">Error::InvalidValue</span> { <span class="ident">expected</span>, <span class="ident">got</span>, .. }) =&gt; <span class="prelude-val">Err</span>(
<span class="ident">de::Error::invalid_value</span>(<span class="ident">de::Unexpected::Str</span>(<span class="kw-2">&amp;</span><span class="ident">got</span>), <span class="kw-2">&amp;</span><span class="ident">expected</span>),
<span class="kw">match </span>KeepAlive::parse(value) {
<span class="prelude-val">Ok</span>(keep_alive) =&gt; <span class="prelude-val">Ok</span>(keep_alive),
<span class="prelude-val">Err</span>(Error::InvalidValue { expected, got, .. }) =&gt; <span class="prelude-val">Err</span>(
de::Error::invalid_value(de::Unexpected::Str(<span class="kw-2">&amp;</span>got), <span class="kw-2">&amp;</span>expected),
),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="macro">unreachable!</span>(),
}
}
}
<span class="ident">deserializer</span>.<span class="ident">deserialize_string</span>(<span class="ident">KeepAliveVisitor</span>)
deserializer.deserialize_string(KeepAliveVisitor)
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -67,72 +67,72 @@
<span id="65">65</span>
<span id="66">66</span>
<span id="67">67</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::fmt</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::fmt;
<span class="kw">use</span> <span class="ident">serde::de</span>;
<span class="kw">use </span>serde::de;
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">AsResult</span>, <span class="ident">Error</span>, <span class="ident">Parse</span>};
<span class="kw">use crate</span>::{AsResult, Error, Parse};
<span class="doccomment">/// The maximum per-worker concurrent TLS connection limit.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// All listeners will stop accepting connections when this limit is reached. It can be used to</span>
<span class="doccomment">/// limit the global TLS CPU usage. By default max connections is set to a 256. Takes a string</span>
<span class="doccomment">/// value: Either &quot;default&quot;, or an integer N &gt; 0 e.g. &quot;6&quot;.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">Hash</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">MaxConnectionRate</span> {
<span class="doccomment">/// The default connection limit. See struct docs.</span>
<span class="ident">Default</span>,
<span class="doccomment">/// The maximum per-worker concurrent TLS connection limit.
///
/// All listeners will stop accepting connections when this limit is reached. It can be used to
/// limit the global TLS CPU usage. By default max connections is set to a 256. Takes a string
/// value: Either &quot;default&quot;, or an integer N &gt; 0 e.g. &quot;6&quot;.
</span><span class="attribute">#[derive(Debug, Clone, PartialEq, Eq, Hash)]
</span><span class="kw">pub enum </span>MaxConnectionRate {
<span class="doccomment">/// The default connection limit. See struct docs.
</span>Default,
<span class="doccomment">/// A specific connection limit.</span>
<span class="ident">Manual</span>(<span class="ident">usize</span>),
<span class="doccomment">/// A specific connection limit.
</span>Manual(usize),
}
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="ident">MaxConnectionRate</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="ident">AsResult</span><span class="op">&lt;</span><span class="self">Self</span><span class="op">&gt;</span> {
<span class="kw">match</span> <span class="ident">string</span> {
<span class="string">&quot;default&quot;</span> =&gt; <span class="prelude-val">Ok</span>(<span class="ident">MaxConnectionRate::Default</span>),
<span class="ident">string</span> =&gt; <span class="kw">match</span> <span class="ident">string</span>.<span class="ident">parse</span>::<span class="op">&lt;</span><span class="ident">usize</span><span class="op">&gt;</span>() {
<span class="prelude-val">Ok</span>(<span class="ident">val</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">MaxConnectionRate::Manual</span>(<span class="ident">val</span>)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(<span class="macro">InvalidValue!</span> {
<span class="ident">expected</span>: <span class="string">&quot;an integer &gt; 0&quot;</span>,
<span class="ident">got</span>: <span class="ident">string</span>,
<span class="kw">impl </span>Parse <span class="kw">for </span>MaxConnectionRate {
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; AsResult&lt;<span class="self">Self</span>&gt; {
<span class="kw">match </span>string {
<span class="string">&quot;default&quot; </span>=&gt; <span class="prelude-val">Ok</span>(MaxConnectionRate::Default),
string =&gt; <span class="kw">match </span>string.parse::&lt;usize&gt;() {
<span class="prelude-val">Ok</span>(val) =&gt; <span class="prelude-val">Ok</span>(MaxConnectionRate::Manual(val)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(<span class="macro">InvalidValue! </span>{
expected: <span class="string">&quot;an integer &gt; 0&quot;</span>,
got: string,
}),
},
}
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="ident">de::Deserialize</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">MaxConnectionRate</span> {
<span class="kw">fn</span> <span class="ident">deserialize</span><span class="op">&lt;</span><span class="ident">D</span><span class="op">&gt;</span>(<span class="ident">deserializer</span>: <span class="ident">D</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">D::Error</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">D</span>: <span class="ident">de::Deserializer</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span>,
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;de</span>&gt; de::Deserialize&lt;<span class="lifetime">&#39;de</span>&gt; <span class="kw">for </span>MaxConnectionRate {
<span class="kw">fn </span>deserialize&lt;D&gt;(deserializer: D) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, D::Error&gt;
<span class="kw">where
</span>D: de::Deserializer&lt;<span class="lifetime">&#39;de</span>&gt;,
{
<span class="kw">struct</span> <span class="ident">MaxConnectionRateVisitor</span>;
<span class="kw">struct </span>MaxConnectionRateVisitor;
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="ident">de::Visitor</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">MaxConnectionRateVisitor</span> {
<span class="kw">type</span> <span class="ident">Value</span> <span class="op">=</span> <span class="ident">MaxConnectionRate</span>;
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;de</span>&gt; de::Visitor&lt;<span class="lifetime">&#39;de</span>&gt; <span class="kw">for </span>MaxConnectionRateVisitor {
<span class="kw">type </span>Value = MaxConnectionRate;
<span class="kw">fn</span> <span class="ident">expecting</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="string">&quot;Either \&quot;default\&quot; or a string containing an integer &gt; 0&quot;</span>;
<span class="ident">f</span>.<span class="ident">write_str</span>(<span class="ident">msg</span>)
<span class="kw">fn </span>expecting(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
<span class="kw">let </span>msg = <span class="string">&quot;Either \&quot;default\&quot; or a string containing an integer &gt; 0&quot;</span>;
f.write_str(msg)
}
<span class="kw">fn</span> <span class="ident">visit_str</span><span class="op">&lt;</span><span class="ident">E</span><span class="op">&gt;</span>(<span class="self">self</span>, <span class="ident">value</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Value</span>, <span class="ident">E</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">E</span>: <span class="ident">de::Error</span>,
<span class="kw">fn </span>visit_str&lt;E&gt;(<span class="self">self</span>, value: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Value, E&gt;
<span class="kw">where
</span>E: de::Error,
{
<span class="kw">match</span> <span class="ident">MaxConnectionRate::parse</span>(<span class="ident">value</span>) {
<span class="prelude-val">Ok</span>(<span class="ident">max_connection_rate</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">max_connection_rate</span>),
<span class="prelude-val">Err</span>(<span class="ident">Error::InvalidValue</span> { <span class="ident">expected</span>, <span class="ident">got</span>, .. }) =&gt; <span class="prelude-val">Err</span>(
<span class="ident">de::Error::invalid_value</span>(<span class="ident">de::Unexpected::Str</span>(<span class="kw-2">&amp;</span><span class="ident">got</span>), <span class="kw-2">&amp;</span><span class="ident">expected</span>),
<span class="kw">match </span>MaxConnectionRate::parse(value) {
<span class="prelude-val">Ok</span>(max_connection_rate) =&gt; <span class="prelude-val">Ok</span>(max_connection_rate),
<span class="prelude-val">Err</span>(Error::InvalidValue { expected, got, .. }) =&gt; <span class="prelude-val">Err</span>(
de::Error::invalid_value(de::Unexpected::Str(<span class="kw-2">&amp;</span>got), <span class="kw-2">&amp;</span>expected),
),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="macro">unreachable!</span>(),
}
}
}
<span class="ident">deserializer</span>.<span class="ident">deserialize_string</span>(<span class="ident">MaxConnectionRateVisitor</span>)
deserializer.deserialize_string(MaxConnectionRateVisitor)
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -67,72 +67,72 @@
<span id="65">65</span>
<span id="66">66</span>
<span id="67">67</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::fmt</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::fmt;
<span class="kw">use</span> <span class="ident">serde::de</span>;
<span class="kw">use </span>serde::de;
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">AsResult</span>, <span class="ident">Error</span>, <span class="ident">Parse</span>};
<span class="kw">use crate</span>::{AsResult, Error, Parse};
<span class="doccomment">/// The maximum per-worker number of concurrent connections.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// All socket listeners will stop accepting connections when this limit is reached for each worker.</span>
<span class="doccomment">/// By default max connections is set to a 25k. Takes a string value: Either &quot;default&quot;, or an</span>
<span class="doccomment">/// integer N &gt; 0 e.g. &quot;6&quot;.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">Hash</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">MaxConnections</span> {
<span class="doccomment">/// The default number of connections. See struct docs.</span>
<span class="ident">Default</span>,
<span class="doccomment">/// The maximum per-worker number of concurrent connections.
///
/// All socket listeners will stop accepting connections when this limit is reached for each worker.
/// By default max connections is set to a 25k. Takes a string value: Either &quot;default&quot;, or an
/// integer N &gt; 0 e.g. &quot;6&quot;.
</span><span class="attribute">#[derive(Debug, Clone, PartialEq, Eq, Hash)]
</span><span class="kw">pub enum </span>MaxConnections {
<span class="doccomment">/// The default number of connections. See struct docs.
</span>Default,
<span class="doccomment">/// A specific number of connections.</span>
<span class="ident">Manual</span>(<span class="ident">usize</span>),
<span class="doccomment">/// A specific number of connections.
</span>Manual(usize),
}
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="ident">MaxConnections</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="ident">AsResult</span><span class="op">&lt;</span><span class="self">Self</span><span class="op">&gt;</span> {
<span class="kw">match</span> <span class="ident">string</span> {
<span class="string">&quot;default&quot;</span> =&gt; <span class="prelude-val">Ok</span>(<span class="ident">MaxConnections::Default</span>),
<span class="ident">string</span> =&gt; <span class="kw">match</span> <span class="ident">string</span>.<span class="ident">parse</span>::<span class="op">&lt;</span><span class="ident">usize</span><span class="op">&gt;</span>() {
<span class="prelude-val">Ok</span>(<span class="ident">val</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">MaxConnections::Manual</span>(<span class="ident">val</span>)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(<span class="macro">InvalidValue!</span> {
<span class="ident">expected</span>: <span class="string">&quot;an integer &gt; 0&quot;</span>,
<span class="ident">got</span>: <span class="ident">string</span>,
<span class="kw">impl </span>Parse <span class="kw">for </span>MaxConnections {
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; AsResult&lt;<span class="self">Self</span>&gt; {
<span class="kw">match </span>string {
<span class="string">&quot;default&quot; </span>=&gt; <span class="prelude-val">Ok</span>(MaxConnections::Default),
string =&gt; <span class="kw">match </span>string.parse::&lt;usize&gt;() {
<span class="prelude-val">Ok</span>(val) =&gt; <span class="prelude-val">Ok</span>(MaxConnections::Manual(val)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(<span class="macro">InvalidValue! </span>{
expected: <span class="string">&quot;an integer &gt; 0&quot;</span>,
got: string,
}),
},
}
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="ident">de::Deserialize</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">MaxConnections</span> {
<span class="kw">fn</span> <span class="ident">deserialize</span><span class="op">&lt;</span><span class="ident">D</span><span class="op">&gt;</span>(<span class="ident">deserializer</span>: <span class="ident">D</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">D::Error</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">D</span>: <span class="ident">de::Deserializer</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span>,
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;de</span>&gt; de::Deserialize&lt;<span class="lifetime">&#39;de</span>&gt; <span class="kw">for </span>MaxConnections {
<span class="kw">fn </span>deserialize&lt;D&gt;(deserializer: D) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, D::Error&gt;
<span class="kw">where
</span>D: de::Deserializer&lt;<span class="lifetime">&#39;de</span>&gt;,
{
<span class="kw">struct</span> <span class="ident">MaxConnectionsVisitor</span>;
<span class="kw">struct </span>MaxConnectionsVisitor;
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="ident">de::Visitor</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">MaxConnectionsVisitor</span> {
<span class="kw">type</span> <span class="ident">Value</span> <span class="op">=</span> <span class="ident">MaxConnections</span>;
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;de</span>&gt; de::Visitor&lt;<span class="lifetime">&#39;de</span>&gt; <span class="kw">for </span>MaxConnectionsVisitor {
<span class="kw">type </span>Value = MaxConnections;
<span class="kw">fn</span> <span class="ident">expecting</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="string">&quot;Either \&quot;default\&quot; or a string containing an integer &gt; 0&quot;</span>;
<span class="ident">f</span>.<span class="ident">write_str</span>(<span class="ident">msg</span>)
<span class="kw">fn </span>expecting(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
<span class="kw">let </span>msg = <span class="string">&quot;Either \&quot;default\&quot; or a string containing an integer &gt; 0&quot;</span>;
f.write_str(msg)
}
<span class="kw">fn</span> <span class="ident">visit_str</span><span class="op">&lt;</span><span class="ident">E</span><span class="op">&gt;</span>(<span class="self">self</span>, <span class="ident">value</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Value</span>, <span class="ident">E</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">E</span>: <span class="ident">de::Error</span>,
<span class="kw">fn </span>visit_str&lt;E&gt;(<span class="self">self</span>, value: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Value, E&gt;
<span class="kw">where
</span>E: de::Error,
{
<span class="kw">match</span> <span class="ident">MaxConnections::parse</span>(<span class="ident">value</span>) {
<span class="prelude-val">Ok</span>(<span class="ident">max_connections</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">max_connections</span>),
<span class="prelude-val">Err</span>(<span class="ident">Error::InvalidValue</span> { <span class="ident">expected</span>, <span class="ident">got</span>, .. }) =&gt; <span class="prelude-val">Err</span>(
<span class="ident">de::Error::invalid_value</span>(<span class="ident">de::Unexpected::Str</span>(<span class="kw-2">&amp;</span><span class="ident">got</span>), <span class="kw-2">&amp;</span><span class="ident">expected</span>),
<span class="kw">match </span>MaxConnections::parse(value) {
<span class="prelude-val">Ok</span>(max_connections) =&gt; <span class="prelude-val">Ok</span>(max_connections),
<span class="prelude-val">Err</span>(Error::InvalidValue { expected, got, .. }) =&gt; <span class="prelude-val">Err</span>(
de::Error::invalid_value(de::Unexpected::Str(<span class="kw-2">&amp;</span>got), <span class="kw-2">&amp;</span>expected),
),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="macro">unreachable!</span>(),
}
}
}
<span class="ident">deserializer</span>.<span class="ident">deserialize_string</span>(<span class="ident">MaxConnectionsVisitor</span>)
deserializer.deserialize_string(MaxConnectionsVisitor)
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -65,70 +65,70 @@
<span id="63">63</span>
<span id="64">64</span>
<span id="65">65</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">serde::Deserialize</span>;
</pre><pre class="rust"><code><span class="kw">use </span>serde::Deserialize;
<span class="kw">mod</span> <span class="ident">address</span>;
<span class="kw">mod</span> <span class="ident">backlog</span>;
<span class="kw">mod</span> <span class="ident">keep_alive</span>;
<span class="kw">mod</span> <span class="ident">max_connection_rate</span>;
<span class="kw">mod</span> <span class="ident">max_connections</span>;
<span class="kw">mod</span> <span class="ident">mode</span>;
<span class="kw">mod</span> <span class="ident">num_workers</span>;
<span class="kw">mod</span> <span class="ident">timeout</span>;
<span class="kw">mod</span> <span class="ident">tls</span>;
<span class="kw">mod </span>address;
<span class="kw">mod </span>backlog;
<span class="kw">mod </span>keep_alive;
<span class="kw">mod </span>max_connection_rate;
<span class="kw">mod </span>max_connections;
<span class="kw">mod </span>mode;
<span class="kw">mod </span>num_workers;
<span class="kw">mod </span>timeout;
<span class="kw">mod </span>tls;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::address::Address</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::backlog::Backlog</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::keep_alive::KeepAlive</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::max_connection_rate::MaxConnectionRate</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::max_connections::MaxConnections</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::mode::Mode</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::num_workers::NumWorkers</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::timeout::Timeout</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::tls::Tls</span>;
<span class="kw">pub use </span><span class="self">self</span>::address::Address;
<span class="kw">pub use </span><span class="self">self</span>::backlog::Backlog;
<span class="kw">pub use </span><span class="self">self</span>::keep_alive::KeepAlive;
<span class="kw">pub use </span><span class="self">self</span>::max_connection_rate::MaxConnectionRate;
<span class="kw">pub use </span><span class="self">self</span>::max_connections::MaxConnections;
<span class="kw">pub use </span><span class="self">self</span>::mode::Mode;
<span class="kw">pub use </span><span class="self">self</span>::num_workers::NumWorkers;
<span class="kw">pub use </span><span class="self">self</span>::timeout::Timeout;
<span class="kw">pub use </span><span class="self">self</span>::tls::Tls;
<span class="doccomment">/// Settings types for Actix Web.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">Hash</span>, <span class="ident">Deserialize</span>)]</span>
<span class="attribute">#[<span class="ident">serde</span>(<span class="ident">rename_all</span> <span class="op">=</span> <span class="string">&quot;kebab-case&quot;</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">ActixSettings</span> {
<span class="doccomment">/// List of addresses for the server to bind to.</span>
<span class="kw">pub</span> <span class="ident">hosts</span>: <span class="ident">Vec</span><span class="op">&lt;</span><span class="ident">Address</span><span class="op">&gt;</span>,
<span class="doccomment">/// Settings types for Actix Web.
</span><span class="attribute">#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
#[serde(rename_all = <span class="string">&quot;kebab-case&quot;</span>)]
</span><span class="kw">pub struct </span>ActixSettings {
<span class="doccomment">/// List of addresses for the server to bind to.
</span><span class="kw">pub </span>hosts: Vec&lt;Address&gt;,
<span class="doccomment">/// Marker of intended deployment environment.</span>
<span class="kw">pub</span> <span class="ident">mode</span>: <span class="ident">Mode</span>,
<span class="doccomment">/// Marker of intended deployment environment.
</span><span class="kw">pub </span>mode: Mode,
<span class="doccomment">/// True if the [`Compress`](actix_web::middleware::Compress) middleware should be enabled.</span>
<span class="kw">pub</span> <span class="ident">enable_compression</span>: <span class="ident">bool</span>,
<span class="doccomment">/// True if the [`Compress`](actix_web::middleware::Compress) middleware should be enabled.
</span><span class="kw">pub </span>enable_compression: bool,
<span class="doccomment">/// True if the [`Logger`](actix_web::middleware::Logger) middleware should be enabled.</span>
<span class="kw">pub</span> <span class="ident">enable_log</span>: <span class="ident">bool</span>,
<span class="doccomment">/// True if the [`Logger`](actix_web::middleware::Logger) middleware should be enabled.
</span><span class="kw">pub </span>enable_log: bool,
<span class="doccomment">/// The number of workers that the server should start.</span>
<span class="kw">pub</span> <span class="ident">num_workers</span>: <span class="ident">NumWorkers</span>,
<span class="doccomment">/// The number of workers that the server should start.
</span><span class="kw">pub </span>num_workers: NumWorkers,
<span class="doccomment">/// The maximum number of pending connections.</span>
<span class="kw">pub</span> <span class="ident">backlog</span>: <span class="ident">Backlog</span>,
<span class="doccomment">/// The maximum number of pending connections.
</span><span class="kw">pub </span>backlog: Backlog,
<span class="doccomment">/// The per-worker maximum number of concurrent connections.</span>
<span class="kw">pub</span> <span class="ident">max_connections</span>: <span class="ident">MaxConnections</span>,
<span class="doccomment">/// The per-worker maximum number of concurrent connections.
</span><span class="kw">pub </span>max_connections: MaxConnections,
<span class="doccomment">/// The per-worker maximum concurrent TLS connection limit.</span>
<span class="kw">pub</span> <span class="ident">max_connection_rate</span>: <span class="ident">MaxConnectionRate</span>,
<span class="doccomment">/// The per-worker maximum concurrent TLS connection limit.
</span><span class="kw">pub </span>max_connection_rate: MaxConnectionRate,
<span class="doccomment">/// Server keep-alive preference.</span>
<span class="kw">pub</span> <span class="ident">keep_alive</span>: <span class="ident">KeepAlive</span>,
<span class="doccomment">/// Server keep-alive preference.
</span><span class="kw">pub </span>keep_alive: KeepAlive,
<span class="doccomment">/// Timeout duration for reading client request header.</span>
<span class="kw">pub</span> <span class="ident">client_timeout</span>: <span class="ident">Timeout</span>,
<span class="doccomment">/// Timeout duration for reading client request header.
</span><span class="kw">pub </span>client_timeout: Timeout,
<span class="doccomment">/// Timeout duration for connection shutdown.</span>
<span class="kw">pub</span> <span class="ident">client_shutdown</span>: <span class="ident">Timeout</span>,
<span class="doccomment">/// Timeout duration for connection shutdown.
</span><span class="kw">pub </span>client_shutdown: Timeout,
<span class="doccomment">/// Timeout duration for graceful worker shutdown.</span>
<span class="kw">pub</span> <span class="ident">shutdown_timeout</span>: <span class="ident">Timeout</span>,
<span class="doccomment">/// Timeout duration for graceful worker shutdown.
</span><span class="kw">pub </span>shutdown_timeout: Timeout,
<span class="doccomment">/// TLS (HTTPS) configuration.</span>
<span class="kw">pub</span> <span class="ident">tls</span>: <span class="ident">Tls</span>,
<span class="doccomment">/// TLS (HTTPS) configuration.
</span><span class="kw">pub </span>tls: Tls,
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -27,32 +27,32 @@
<span id="25">25</span>
<span id="26">26</span>
<span id="27">27</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">serde::Deserialize</span>;
</pre><pre class="rust"><code><span class="kw">use </span>serde::Deserialize;
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">AsResult</span>, <span class="ident">Parse</span>};
<span class="kw">use crate</span>::{AsResult, Parse};
<span class="doccomment">/// Marker of intended deployment environment.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">Hash</span>, <span class="ident">Deserialize</span>)]</span>
<span class="attribute">#[<span class="ident">serde</span>(<span class="ident">rename_all</span> <span class="op">=</span> <span class="string">&quot;lowercase&quot;</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">Mode</span> {
<span class="doccomment">/// Marks development environment.</span>
<span class="ident">Development</span>,
<span class="doccomment">/// Marker of intended deployment environment.
</span><span class="attribute">#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
#[serde(rename_all = <span class="string">&quot;lowercase&quot;</span>)]
</span><span class="kw">pub enum </span>Mode {
<span class="doccomment">/// Marks development environment.
</span>Development,
<span class="doccomment">/// Marks production environment.</span>
<span class="ident">Production</span>,
<span class="doccomment">/// Marks production environment.
</span>Production,
}
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="ident">Mode</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="ident">AsResult</span><span class="op">&lt;</span><span class="self">Self</span><span class="op">&gt;</span> {
<span class="kw">match</span> <span class="ident">string</span> {
<span class="string">&quot;development&quot;</span> =&gt; <span class="prelude-val">Ok</span>(<span class="ident"><span class="self">Self</span>::Development</span>),
<span class="string">&quot;production&quot;</span> =&gt; <span class="prelude-val">Ok</span>(<span class="ident"><span class="self">Self</span>::Production</span>),
<span class="kw">_</span> =&gt; <span class="prelude-val">Err</span>(<span class="macro">InvalidValue!</span> {
<span class="ident">expected</span>: <span class="string">&quot;\&quot;development\&quot; | \&quot;production\&quot;.&quot;</span>,
<span class="ident">got</span>: <span class="ident">string</span>,
<span class="kw">impl </span>Parse <span class="kw">for </span>Mode {
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; AsResult&lt;<span class="self">Self</span>&gt; {
<span class="kw">match </span>string {
<span class="string">&quot;development&quot; </span>=&gt; <span class="prelude-val">Ok</span>(<span class="self">Self</span>::Development),
<span class="string">&quot;production&quot; </span>=&gt; <span class="prelude-val">Ok</span>(<span class="self">Self</span>::Production),
<span class="kw">_ </span>=&gt; <span class="prelude-val">Err</span>(<span class="macro">InvalidValue! </span>{
expected: <span class="string">&quot;\&quot;development\&quot; | \&quot;production\&quot;.&quot;</span>,
got: string,
}),
}
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -66,71 +66,71 @@
<span id="64">64</span>
<span id="65">65</span>
<span id="66">66</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::fmt</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::fmt;
<span class="kw">use</span> <span class="ident">serde::de</span>;
<span class="kw">use </span>serde::de;
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">AsResult</span>, <span class="ident">Error</span>, <span class="ident">Parse</span>};
<span class="kw">use crate</span>::{AsResult, Error, Parse};
<span class="doccomment">/// The number of workers that the server should start.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// By default the number of available logical cpu cores is used. Takes a string value: Either</span>
<span class="doccomment">/// &quot;default&quot;, or an integer N &gt; 0 e.g. &quot;6&quot;.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">Hash</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">NumWorkers</span> {
<span class="doccomment">/// The default number of workers. See struct docs.</span>
<span class="ident">Default</span>,
<span class="doccomment">/// The number of workers that the server should start.
///
/// By default the number of available logical cpu cores is used. Takes a string value: Either
/// &quot;default&quot;, or an integer N &gt; 0 e.g. &quot;6&quot;.
</span><span class="attribute">#[derive(Debug, Clone, PartialEq, Eq, Hash)]
</span><span class="kw">pub enum </span>NumWorkers {
<span class="doccomment">/// The default number of workers. See struct docs.
</span>Default,
<span class="doccomment">/// A specific number of workers.</span>
<span class="ident">Manual</span>(<span class="ident">usize</span>),
<span class="doccomment">/// A specific number of workers.
</span>Manual(usize),
}
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="ident">NumWorkers</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="ident">AsResult</span><span class="op">&lt;</span><span class="self">Self</span><span class="op">&gt;</span> {
<span class="kw">match</span> <span class="ident">string</span> {
<span class="string">&quot;default&quot;</span> =&gt; <span class="prelude-val">Ok</span>(<span class="ident">NumWorkers::Default</span>),
<span class="ident">string</span> =&gt; <span class="kw">match</span> <span class="ident">string</span>.<span class="ident">parse</span>::<span class="op">&lt;</span><span class="ident">usize</span><span class="op">&gt;</span>() {
<span class="prelude-val">Ok</span>(<span class="ident">val</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">NumWorkers::Manual</span>(<span class="ident">val</span>)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(<span class="macro">InvalidValue!</span> {
<span class="ident">expected</span>: <span class="string">&quot;a positive integer&quot;</span>,
<span class="ident">got</span>: <span class="ident">string</span>,
<span class="kw">impl </span>Parse <span class="kw">for </span>NumWorkers {
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; AsResult&lt;<span class="self">Self</span>&gt; {
<span class="kw">match </span>string {
<span class="string">&quot;default&quot; </span>=&gt; <span class="prelude-val">Ok</span>(NumWorkers::Default),
string =&gt; <span class="kw">match </span>string.parse::&lt;usize&gt;() {
<span class="prelude-val">Ok</span>(val) =&gt; <span class="prelude-val">Ok</span>(NumWorkers::Manual(val)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(<span class="macro">InvalidValue! </span>{
expected: <span class="string">&quot;a positive integer&quot;</span>,
got: string,
}),
},
}
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="ident">de::Deserialize</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">NumWorkers</span> {
<span class="kw">fn</span> <span class="ident">deserialize</span><span class="op">&lt;</span><span class="ident">D</span><span class="op">&gt;</span>(<span class="ident">deserializer</span>: <span class="ident">D</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">D::Error</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">D</span>: <span class="ident">de::Deserializer</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span>,
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;de</span>&gt; de::Deserialize&lt;<span class="lifetime">&#39;de</span>&gt; <span class="kw">for </span>NumWorkers {
<span class="kw">fn </span>deserialize&lt;D&gt;(deserializer: D) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, D::Error&gt;
<span class="kw">where
</span>D: de::Deserializer&lt;<span class="lifetime">&#39;de</span>&gt;,
{
<span class="kw">struct</span> <span class="ident">NumWorkersVisitor</span>;
<span class="kw">struct </span>NumWorkersVisitor;
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="ident">de::Visitor</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">NumWorkersVisitor</span> {
<span class="kw">type</span> <span class="ident">Value</span> <span class="op">=</span> <span class="ident">NumWorkers</span>;
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;de</span>&gt; de::Visitor&lt;<span class="lifetime">&#39;de</span>&gt; <span class="kw">for </span>NumWorkersVisitor {
<span class="kw">type </span>Value = NumWorkers;
<span class="kw">fn</span> <span class="ident">expecting</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="string">&quot;Either \&quot;default\&quot; or a string containing an integer &gt; 0&quot;</span>;
<span class="ident">f</span>.<span class="ident">write_str</span>(<span class="ident">msg</span>)
<span class="kw">fn </span>expecting(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
<span class="kw">let </span>msg = <span class="string">&quot;Either \&quot;default\&quot; or a string containing an integer &gt; 0&quot;</span>;
f.write_str(msg)
}
<span class="kw">fn</span> <span class="ident">visit_str</span><span class="op">&lt;</span><span class="ident">E</span><span class="op">&gt;</span>(<span class="self">self</span>, <span class="ident">value</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Value</span>, <span class="ident">E</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">E</span>: <span class="ident">de::Error</span>,
<span class="kw">fn </span>visit_str&lt;E&gt;(<span class="self">self</span>, value: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Value, E&gt;
<span class="kw">where
</span>E: de::Error,
{
<span class="kw">match</span> <span class="ident">NumWorkers::parse</span>(<span class="ident">value</span>) {
<span class="prelude-val">Ok</span>(<span class="ident">num_workers</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">num_workers</span>),
<span class="prelude-val">Err</span>(<span class="ident">Error::InvalidValue</span> { <span class="ident">expected</span>, <span class="ident">got</span>, .. }) =&gt; <span class="prelude-val">Err</span>(
<span class="ident">de::Error::invalid_value</span>(<span class="ident">de::Unexpected::Str</span>(<span class="kw-2">&amp;</span><span class="ident">got</span>), <span class="kw-2">&amp;</span><span class="ident">expected</span>),
<span class="kw">match </span>NumWorkers::parse(value) {
<span class="prelude-val">Ok</span>(num_workers) =&gt; <span class="prelude-val">Ok</span>(num_workers),
<span class="prelude-val">Err</span>(Error::InvalidValue { expected, got, .. }) =&gt; <span class="prelude-val">Err</span>(
de::Error::invalid_value(de::Unexpected::Str(<span class="kw-2">&amp;</span>got), <span class="kw-2">&amp;</span>expected),
),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="macro">unreachable!</span>(),
}
}
}
<span class="ident">deserializer</span>.<span class="ident">deserialize_string</span>(<span class="ident">NumWorkersVisitor</span>)
deserializer.deserialize_string(NumWorkersVisitor)
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -98,65 +98,65 @@
<span id="96">96</span>
<span id="97">97</span>
<span id="98">98</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::fmt</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::fmt;
<span class="kw">use</span> <span class="ident">once_cell::sync::Lazy</span>;
<span class="kw">use</span> <span class="ident">regex::Regex</span>;
<span class="kw">use</span> <span class="ident">serde::de</span>;
<span class="kw">use </span>once_cell::sync::Lazy;
<span class="kw">use </span>regex::Regex;
<span class="kw">use </span>serde::de;
<span class="kw">use</span> <span class="kw">crate</span>::{<span class="ident">AsResult</span>, <span class="ident">Error</span>, <span class="ident">Parse</span>};
<span class="kw">use crate</span>::{AsResult, Error, Parse};
<span class="doccomment">/// A timeout duration in milliseconds or seconds.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">Hash</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">Timeout</span> {
<span class="doccomment">/// The default timeout. Depends on context.</span>
<span class="ident">Default</span>,
<span class="doccomment">/// A timeout duration in milliseconds or seconds.
</span><span class="attribute">#[derive(Debug, Clone, PartialEq, Eq, Hash)]
</span><span class="kw">pub enum </span>Timeout {
<span class="doccomment">/// The default timeout. Depends on context.
</span>Default,
<span class="doccomment">/// Timeout in milliseconds.</span>
<span class="ident">Milliseconds</span>(<span class="ident">usize</span>),
<span class="doccomment">/// Timeout in milliseconds.
</span>Milliseconds(usize),
<span class="doccomment">/// Timeout in seconds.</span>
<span class="ident">Seconds</span>(<span class="ident">usize</span>),
<span class="doccomment">/// Timeout in seconds.
</span>Seconds(usize),
}
<span class="kw">impl</span> <span class="ident">Parse</span> <span class="kw">for</span> <span class="ident">Timeout</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">string</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="ident">AsResult</span><span class="op">&lt;</span><span class="self">Self</span><span class="op">&gt;</span> {
<span class="kw">pub</span> <span class="kw">static</span> <span class="ident">FMT</span>: <span class="ident">Lazy</span><span class="op">&lt;</span><span class="ident">Regex</span><span class="op">&gt;</span> <span class="op">=</span> <span class="ident">Lazy::new</span>(<span class="op">|</span><span class="op">|</span> {
<span class="ident">Regex::new</span>(<span class="string">r&quot;^\d+ (milliseconds|seconds)$&quot;</span>).<span class="ident">expect</span>(<span class="string">&quot;Failed to compile regex: FMT&quot;</span>)
<span class="kw">impl </span>Parse <span class="kw">for </span>Timeout {
<span class="kw">fn </span>parse(string: <span class="kw-2">&amp;</span>str) -&gt; AsResult&lt;<span class="self">Self</span>&gt; {
<span class="kw">pub static </span>FMT: Lazy&lt;Regex&gt; = Lazy::new(|| {
Regex::new(<span class="string">r&quot;^\d+ (milliseconds|seconds)$&quot;</span>).expect(<span class="string">&quot;Failed to compile regex: FMT&quot;</span>)
});
<span class="kw">pub</span> <span class="kw">static</span> <span class="ident">DIGITS</span>: <span class="ident">Lazy</span><span class="op">&lt;</span><span class="ident">Regex</span><span class="op">&gt;</span> <span class="op">=</span>
<span class="ident">Lazy::new</span>(<span class="op">|</span><span class="op">|</span> <span class="ident">Regex::new</span>(<span class="string">r&quot;^\d+&quot;</span>).<span class="ident">expect</span>(<span class="string">&quot;Failed to compile regex: DIGITS&quot;</span>));
<span class="kw">pub static </span>DIGITS: Lazy&lt;Regex&gt; =
Lazy::new(|| Regex::new(<span class="string">r&quot;^\d+&quot;</span>).expect(<span class="string">&quot;Failed to compile regex: DIGITS&quot;</span>));
<span class="kw">pub</span> <span class="kw">static</span> <span class="ident">UNIT</span>: <span class="ident">Lazy</span><span class="op">&lt;</span><span class="ident">Regex</span><span class="op">&gt;</span> <span class="op">=</span> <span class="ident">Lazy::new</span>(<span class="op">|</span><span class="op">|</span> {
<span class="ident">Regex::new</span>(<span class="string">r&quot;(milliseconds|seconds)$&quot;</span>).<span class="ident">expect</span>(<span class="string">&quot;Failed to compile regex: UNIT&quot;</span>)
<span class="kw">pub static </span>UNIT: Lazy&lt;Regex&gt; = Lazy::new(|| {
Regex::new(<span class="string">r&quot;(milliseconds|seconds)$&quot;</span>).expect(<span class="string">&quot;Failed to compile regex: UNIT&quot;</span>)
});
<span class="macro">macro_rules!</span> <span class="ident">invalid_value</span> {
(<span class="macro-nonterminal">$</span><span class="macro-nonterminal">got</span>:<span class="ident">expr</span>) =&gt; {
<span class="prelude-val">Err</span>(<span class="macro">InvalidValue!</span> {
<span class="ident">expected</span>: <span class="string">&quot;a string of the format \&quot;N seconds\&quot; or \&quot;N milliseconds\&quot; where N is an integer &gt; 0&quot;</span>,
<span class="ident">got</span>: <span class="macro-nonterminal">$</span><span class="macro-nonterminal">got</span>,
<span class="macro">macro_rules! </span>invalid_value {
(<span class="macro-nonterminal">$got</span>:expr) =&gt; {
<span class="prelude-val">Err</span>(<span class="macro">InvalidValue! </span>{
expected: <span class="string">&quot;a string of the format \&quot;N seconds\&quot; or \&quot;N milliseconds\&quot; where N is an integer &gt; 0&quot;</span>,
got: <span class="macro-nonterminal">$got</span>,
})
}
}
<span class="kw">match</span> <span class="ident">string</span> {
<span class="string">&quot;default&quot;</span> =&gt; <span class="prelude-val">Ok</span>(<span class="ident">Timeout::Default</span>),
<span class="kw">match </span>string {
<span class="string">&quot;default&quot; </span>=&gt; <span class="prelude-val">Ok</span>(Timeout::Default),
<span class="ident">string</span> <span class="kw">if</span> <span class="op">!</span><span class="ident">FMT</span>.<span class="ident">is_match</span>(<span class="ident">string</span>) =&gt; <span class="macro">invalid_value!</span>(<span class="ident">string</span>),
string <span class="kw">if </span>!FMT.is_match(string) =&gt; <span class="macro">invalid_value!</span>(string),
<span class="ident">string</span> =&gt; <span class="kw">match</span> (<span class="ident">DIGITS</span>.<span class="ident">find</span>(<span class="ident">string</span>), <span class="ident">UNIT</span>.<span class="ident">find</span>(<span class="ident">string</span>)) {
(<span class="prelude-val">None</span>, <span class="kw">_</span>) <span class="op">|</span> (<span class="kw">_</span>, <span class="prelude-val">None</span>) =&gt; <span class="macro">invalid_value!</span>(<span class="ident">string</span>),
string =&gt; <span class="kw">match </span>(DIGITS.find(string), UNIT.find(string)) {
(<span class="prelude-val">None</span>, <span class="kw">_</span>) | (<span class="kw">_</span>, <span class="prelude-val">None</span>) =&gt; <span class="macro">invalid_value!</span>(string),
(<span class="prelude-val">Some</span>(<span class="ident">digits</span>), <span class="prelude-val">Some</span>(<span class="ident">unit</span>)) =&gt; {
<span class="kw">let</span> <span class="ident">digits</span> <span class="op">=</span> <span class="kw-2">&amp;</span><span class="ident">string</span>[<span class="ident">digits</span>.<span class="ident">range</span>()];
<span class="kw">let</span> <span class="ident">unit</span> <span class="op">=</span> <span class="kw-2">&amp;</span><span class="ident">string</span>[<span class="ident">unit</span>.<span class="ident">range</span>()];
(<span class="prelude-val">Some</span>(digits), <span class="prelude-val">Some</span>(unit)) =&gt; {
<span class="kw">let </span>digits = <span class="kw-2">&amp;</span>string[digits.range()];
<span class="kw">let </span>unit = <span class="kw-2">&amp;</span>string[unit.range()];
<span class="kw">match</span> (<span class="ident">digits</span>.<span class="ident">parse</span>(), <span class="ident">unit</span>) {
(<span class="prelude-val">Ok</span>(<span class="ident">n</span>), <span class="string">&quot;milliseconds&quot;</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">Timeout::Milliseconds</span>(<span class="ident">n</span>)),
(<span class="prelude-val">Ok</span>(<span class="ident">n</span>), <span class="string">&quot;seconds&quot;</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">Timeout::Seconds</span>(<span class="ident">n</span>)),
<span class="kw">_</span> =&gt; <span class="macro">invalid_value!</span>(<span class="ident">string</span>),
<span class="kw">match </span>(digits.parse(), unit) {
(<span class="prelude-val">Ok</span>(n), <span class="string">&quot;milliseconds&quot;</span>) =&gt; <span class="prelude-val">Ok</span>(Timeout::Milliseconds(n)),
(<span class="prelude-val">Ok</span>(n), <span class="string">&quot;seconds&quot;</span>) =&gt; <span class="prelude-val">Ok</span>(Timeout::Seconds(n)),
<span class="kw">_ </span>=&gt; <span class="macro">invalid_value!</span>(string),
}
}
},
@@ -164,37 +164,37 @@
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="ident">de::Deserialize</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Timeout</span> {
<span class="kw">fn</span> <span class="ident">deserialize</span><span class="op">&lt;</span><span class="ident">D</span><span class="op">&gt;</span>(<span class="ident">deserializer</span>: <span class="ident">D</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">D::Error</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">D</span>: <span class="ident">de::Deserializer</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span>,
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;de</span>&gt; de::Deserialize&lt;<span class="lifetime">&#39;de</span>&gt; <span class="kw">for </span>Timeout {
<span class="kw">fn </span>deserialize&lt;D&gt;(deserializer: D) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, D::Error&gt;
<span class="kw">where
</span>D: de::Deserializer&lt;<span class="lifetime">&#39;de</span>&gt;,
{
<span class="kw">struct</span> <span class="ident">TimeoutVisitor</span>;
<span class="kw">struct </span>TimeoutVisitor;
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="ident">de::Visitor</span><span class="op">&lt;</span><span class="lifetime">&#39;de</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">TimeoutVisitor</span> {
<span class="kw">type</span> <span class="ident">Value</span> <span class="op">=</span> <span class="ident">Timeout</span>;
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;de</span>&gt; de::Visitor&lt;<span class="lifetime">&#39;de</span>&gt; <span class="kw">for </span>TimeoutVisitor {
<span class="kw">type </span>Value = Timeout;
<span class="kw">fn</span> <span class="ident">expecting</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="kw">let</span> <span class="ident">msg</span> <span class="op">=</span> <span class="string">&quot;Either \&quot;default\&quot;, \&quot;disabled\&quot;, \&quot;os\&quot;, or a string of the format \&quot;N seconds\&quot; where N is an integer &gt; 0&quot;</span>;
<span class="ident">f</span>.<span class="ident">write_str</span>(<span class="ident">msg</span>)
<span class="kw">fn </span>expecting(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
<span class="kw">let </span>msg = <span class="string">&quot;Either \&quot;default\&quot;, \&quot;disabled\&quot;, \&quot;os\&quot;, or a string of the format \&quot;N seconds\&quot; where N is an integer &gt; 0&quot;</span>;
f.write_str(msg)
}
<span class="kw">fn</span> <span class="ident">visit_str</span><span class="op">&lt;</span><span class="ident">E</span><span class="op">&gt;</span>(<span class="self">self</span>, <span class="ident">value</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Value</span>, <span class="ident">E</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">E</span>: <span class="ident">de::Error</span>,
<span class="kw">fn </span>visit_str&lt;E&gt;(<span class="self">self</span>, value: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Value, E&gt;
<span class="kw">where
</span>E: de::Error,
{
<span class="kw">match</span> <span class="ident">Timeout::parse</span>(<span class="ident">value</span>) {
<span class="prelude-val">Ok</span>(<span class="ident">num_workers</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">num_workers</span>),
<span class="prelude-val">Err</span>(<span class="ident">Error::InvalidValue</span> { <span class="ident">expected</span>, <span class="ident">got</span>, .. }) =&gt; <span class="prelude-val">Err</span>(
<span class="ident">de::Error::invalid_value</span>(<span class="ident">de::Unexpected::Str</span>(<span class="kw-2">&amp;</span><span class="ident">got</span>), <span class="kw-2">&amp;</span><span class="ident">expected</span>),
<span class="kw">match </span>Timeout::parse(value) {
<span class="prelude-val">Ok</span>(num_workers) =&gt; <span class="prelude-val">Ok</span>(num_workers),
<span class="prelude-val">Err</span>(Error::InvalidValue { expected, got, .. }) =&gt; <span class="prelude-val">Err</span>(
de::Error::invalid_value(de::Unexpected::Str(<span class="kw-2">&amp;</span>got), <span class="kw-2">&amp;</span>expected),
),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="macro">unreachable!</span>(),
}
}
}
<span class="ident">deserializer</span>.<span class="ident">deserialize_string</span>(<span class="ident">TimeoutVisitor</span>)
deserializer.deserialize_string(TimeoutVisitor)
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -18,23 +18,23 @@
<span id="16">16</span>
<span id="17">17</span>
<span id="18">18</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::path::PathBuf</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::path::PathBuf;
<span class="kw">use</span> <span class="ident">serde::Deserialize</span>;
<span class="kw">use </span>serde::Deserialize;
<span class="doccomment">/// TLS (HTTPS) configuration.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">Hash</span>, <span class="ident">Deserialize</span>)]</span>
<span class="attribute">#[<span class="ident">serde</span>(<span class="ident">rename_all</span> <span class="op">=</span> <span class="string">&quot;kebab-case&quot;</span>)]</span>
<span class="attribute">#[<span class="ident">doc</span>(<span class="ident">alias</span> <span class="op">=</span> <span class="string">&quot;ssl&quot;</span>, <span class="ident">alias</span> <span class="op">=</span> <span class="string">&quot;https&quot;</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Tls</span> {
<span class="doccomment">/// Tru if accepting TLS connections should be enabled.</span>
<span class="kw">pub</span> <span class="ident">enabled</span>: <span class="ident">bool</span>,
<span class="doccomment">/// TLS (HTTPS) configuration.
</span><span class="attribute">#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
#[serde(rename_all = <span class="string">&quot;kebab-case&quot;</span>)]
#[doc(alias = <span class="string">&quot;ssl&quot;</span>, alias = <span class="string">&quot;https&quot;</span>)]
</span><span class="kw">pub struct </span>Tls {
<span class="doccomment">/// Tru if accepting TLS connections should be enabled.
</span><span class="kw">pub </span>enabled: bool,
<span class="doccomment">/// Path to certificate `.pem` file.</span>
<span class="kw">pub</span> <span class="ident">certificate</span>: <span class="ident">PathBuf</span>,
<span class="doccomment">/// Path to certificate `.pem` file.
</span><span class="kw">pub </span>certificate: PathBuf,
<span class="doccomment">/// Path to private key `.pem` file.</span>
<span class="kw">pub</span> <span class="ident">private_key</span>: <span class="ident">PathBuf</span>,
<span class="doccomment">/// Path to private key `.pem` file.
</span><span class="kw">pub </span>private_key: PathBuf,
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_settings" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -110,117 +110,117 @@
<span id="110">110</span>
<span id="111">111</span>
<span id="112">112</span>
</pre><pre class="rust"><code><span class="doccomment">//! Extractor for the &quot;Basic&quot; HTTP Authentication Scheme.</span>
</pre><pre class="rust"><code><span class="doccomment">//! Extractor for the &quot;Basic&quot; HTTP Authentication Scheme.
<span class="kw">use</span> <span class="ident">std::borrow::Cow</span>;
</span><span class="kw">use </span>std::borrow::Cow;
<span class="kw">use</span> <span class="ident">actix_utils::future</span>::{<span class="ident">ready</span>, <span class="ident">Ready</span>};
<span class="kw">use</span> <span class="ident">actix_web</span>::{<span class="ident">dev::Payload</span>, <span class="ident">http::header::Header</span>, <span class="ident">FromRequest</span>, <span class="ident">HttpRequest</span>};
<span class="kw">use </span>actix_utils::future::{ready, Ready};
<span class="kw">use </span>actix_web::{dev::Payload, http::header::Header, FromRequest, HttpRequest};
<span class="kw">use</span> <span class="kw">super</span>::{<span class="ident">config::AuthExtractorConfig</span>, <span class="ident">errors::AuthenticationError</span>};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::headers</span>::{
<span class="ident">authorization</span>::{<span class="ident">Authorization</span>, <span class="ident">Basic</span>},
<span class="ident">www_authenticate::basic::Basic</span> <span class="kw">as</span> <span class="ident">Challenge</span>,
<span class="kw">use super</span>::{config::AuthExtractorConfig, errors::AuthenticationError};
<span class="kw">use </span><span class="kw">crate</span>::headers::{
authorization::{Authorization, Basic},
www_authenticate::basic::Basic <span class="kw">as </span>Challenge,
};
<span class="doccomment">/// [`BasicAuth`] extractor configuration used for [`WWW-Authenticate`] header later.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`WWW-Authenticate`]: crate::headers::www_authenticate::WwwAuthenticate</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">Default</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Config</span>(<span class="ident">Challenge</span>);
<span class="doccomment">/// [`BasicAuth`] extractor configuration used for [`WWW-Authenticate`] header later.
///
/// [`WWW-Authenticate`]: crate::headers::www_authenticate::WwwAuthenticate
</span><span class="attribute">#[derive(Debug, Clone, Default)]
</span><span class="kw">pub struct </span>Config(Challenge);
<span class="kw">impl</span> <span class="ident">Config</span> {
<span class="doccomment">/// Set challenge `realm` attribute.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// The &quot;realm&quot; attribute indicates the scope of protection in the manner described in HTTP/1.1</span>
<span class="doccomment">/// [RFC 2617 §1.2](https://tools.ietf.org/html/rfc2617#section-1.2).</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">realm</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">value</span>: <span class="ident">T</span>) -&gt; <span class="ident">Config</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">impl </span>Config {
<span class="doccomment">/// Set challenge `realm` attribute.
///
/// The &quot;realm&quot; attribute indicates the scope of protection in the manner described in HTTP/1.1
/// [RFC 2617 §1.2](https://tools.ietf.org/html/rfc2617#section-1.2).
</span><span class="kw">pub fn </span>realm&lt;T&gt;(<span class="kw-2">mut </span><span class="self">self</span>, value: T) -&gt; Config
<span class="kw">where
</span>T: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
{
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">realm</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">value</span>.<span class="ident">into</span>());
<span class="self">self</span>
<span class="self">self</span>.<span class="number">0</span>.realm = <span class="prelude-val">Some</span>(value.into());
<span class="self">self
</span>}
}
<span class="kw">impl </span>AsRef&lt;Challenge&gt; <span class="kw">for </span>Config {
<span class="kw">fn </span>as_ref(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>Challenge {
<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0
</span>}
}
<span class="kw">impl </span>AuthExtractorConfig <span class="kw">for </span>Config {
<span class="kw">type </span>Inner = Challenge;
<span class="kw">fn </span>into_inner(<span class="self">self</span>) -&gt; <span class="self">Self</span>::Inner {
<span class="self">self</span>.<span class="number">0
</span>}
}
<span class="doccomment">/// Extractor for HTTP Basic auth.
///
/// # Examples
/// ```
/// use actix_web_httpauth::extractors::basic::BasicAuth;
///
/// async fn index(auth: BasicAuth) -&gt; String {
/// format!(&quot;Hello, {}!&quot;, auth.user_id())
/// }
/// ```
///
/// If authentication fails, this extractor fetches the [`Config`] instance from the [app data] in
/// order to properly form the `WWW-Authenticate` response header.
///
/// # Examples
/// ```
/// use actix_web::{web, App};
/// use actix_web_httpauth::extractors::basic::{self, BasicAuth};
///
/// async fn index(auth: BasicAuth) -&gt; String {
/// format!(&quot;Hello, {}!&quot;, auth.user_id())
/// }
///
/// App::new()
/// .app_data(basic::Config::default().realm(&quot;Restricted area&quot;))
/// .service(web::resource(&quot;/index.html&quot;).route(web::get().to(index)));
/// ```
///
/// [app data]: https://docs.rs/actix-web/4/actix_web/struct.App.html#method.app_data
</span><span class="attribute">#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>BasicAuth(Basic);
<span class="kw">impl </span>BasicAuth {
<span class="doccomment">/// Returns client&#39;s user-ID.
</span><span class="kw">pub fn </span>user_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="self">self</span>.<span class="number">0</span>.user_id()
}
<span class="doccomment">/// Returns client&#39;s password.
</span><span class="kw">pub fn </span>password(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt; {
<span class="self">self</span>.<span class="number">0</span>.password()
}
}
<span class="kw">impl</span> <span class="ident">AsRef</span><span class="op">&lt;</span><span class="ident">Challenge</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Config</span> {
<span class="kw">fn</span> <span class="ident">as_ref</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="ident">Challenge</span> {
<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0</span>
}
}
<span class="kw">impl </span>FromRequest <span class="kw">for </span>BasicAuth {
<span class="kw">type </span>Future = Ready&lt;<span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, <span class="self">Self</span>::Error&gt;&gt;;
<span class="kw">type </span>Error = AuthenticationError&lt;Challenge&gt;;
<span class="kw">impl</span> <span class="ident">AuthExtractorConfig</span> <span class="kw">for</span> <span class="ident">Config</span> {
<span class="kw">type</span> <span class="ident">Inner</span> <span class="op">=</span> <span class="ident">Challenge</span>;
<span class="kw">fn </span>from_request(req: <span class="kw-2">&amp;</span>HttpRequest, <span class="kw">_</span>: <span class="kw-2">&amp;mut </span>Payload) -&gt; &lt;<span class="self">Self </span><span class="kw">as </span>FromRequest&gt;::Future {
ready(
Authorization::&lt;Basic&gt;::parse(req)
.map(|auth| BasicAuth(auth.into_scheme()))
.map_err(|err| {
<span class="macro">log::debug!</span>(<span class="string">&quot;`BasicAuth` extract error: {}&quot;</span>, err);
<span class="kw">fn</span> <span class="ident">into_inner</span>(<span class="self">self</span>) -&gt; <span class="ident"><span class="self">Self</span>::Inner</span> {
<span class="self">self</span>.<span class="number">0</span>
}
}
<span class="kw">let </span>challenge = req
.app_data::&lt;Config&gt;()
.map(|config| config.<span class="number">0</span>.clone())
.unwrap_or_default();
<span class="doccomment">/// Extractor for HTTP Basic auth.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_web_httpauth::extractors::basic::BasicAuth;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// async fn index(auth: BasicAuth) -&gt; String {</span>
<span class="doccomment">/// format!(&quot;Hello, {}!&quot;, auth.user_id())</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If authentication fails, this extractor fetches the [`Config`] instance from the [app data] in</span>
<span class="doccomment">/// order to properly form the `WWW-Authenticate` response header.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_web::{web, App};</span>
<span class="doccomment">/// use actix_web_httpauth::extractors::basic::{self, BasicAuth};</span>
<span class="doccomment">///</span>
<span class="doccomment">/// async fn index(auth: BasicAuth) -&gt; String {</span>
<span class="doccomment">/// format!(&quot;Hello, {}!&quot;, auth.user_id())</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// App::new()</span>
<span class="doccomment">/// .app_data(basic::Config::default().realm(&quot;Restricted area&quot;))</span>
<span class="doccomment">/// .service(web::resource(&quot;/index.html&quot;).route(web::get().to(index)));</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [app data]: https://docs.rs/actix-web/4/actix_web/struct.App.html#method.app_data</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">BasicAuth</span>(<span class="ident">Basic</span>);
<span class="kw">impl</span> <span class="ident">BasicAuth</span> {
<span class="doccomment">/// Returns client&#39;s user-ID.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">user_id</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="ident">str</span> {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">user_id</span>()
}
<span class="doccomment">/// Returns client&#39;s password.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">password</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="kw-2">&amp;</span><span class="ident">str</span><span class="op">&gt;</span> {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">password</span>()
}
}
<span class="kw">impl</span> <span class="ident">FromRequest</span> <span class="kw">for</span> <span class="ident">BasicAuth</span> {
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">Ready</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">AuthenticationError</span><span class="op">&lt;</span><span class="ident">Challenge</span><span class="op">&gt;</span>;
<span class="kw">fn</span> <span class="ident">from_request</span>(<span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">HttpRequest</span>, <span class="kw">_</span>: <span class="kw-2">&amp;mut</span> <span class="ident">Payload</span>) -&gt; <span class="op">&lt;</span><span class="self">Self</span> <span class="kw">as</span> <span class="ident">FromRequest</span><span class="op">&gt;</span><span class="ident">::Future</span> {
<span class="ident">ready</span>(
<span class="ident">Authorization</span>::<span class="op">&lt;</span><span class="ident">Basic</span><span class="op">&gt;</span><span class="ident">::parse</span>(<span class="ident">req</span>)
.<span class="ident">map</span>(<span class="op">|</span><span class="ident">auth</span><span class="op">|</span> <span class="ident">BasicAuth</span>(<span class="ident">auth</span>.<span class="ident">into_scheme</span>()))
.<span class="ident">map_err</span>(<span class="op">|</span><span class="ident">err</span><span class="op">|</span> {
<span class="macro">log::debug!</span>(<span class="string">&quot;`BasicAuth` extract error: {}&quot;</span>, <span class="ident">err</span>);
<span class="kw">let</span> <span class="ident">challenge</span> <span class="op">=</span> <span class="ident">req</span>
.<span class="ident">app_data</span>::<span class="op">&lt;</span><span class="ident">Config</span><span class="op">&gt;</span>()
.<span class="ident">map</span>(<span class="op">|</span><span class="ident">config</span><span class="op">|</span> <span class="ident">config</span>.<span class="number">0</span>.<span class="ident">clone</span>())
.<span class="ident">unwrap_or_default</span>();
<span class="ident">AuthenticationError::new</span>(<span class="ident">challenge</span>)
AuthenticationError::new(challenge)
}),
)
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -142,149 +142,149 @@
<span id="142">142</span>
<span id="143">143</span>
<span id="144">144</span>
</pre><pre class="rust"><code><span class="doccomment">//! Extractor for the &quot;Bearer&quot; HTTP Authentication Scheme.</span>
</pre><pre class="rust"><code><span class="doccomment">//! Extractor for the &quot;Bearer&quot; HTTP Authentication Scheme.
<span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">borrow::Cow</span>, <span class="ident">default::Default</span>};
</span><span class="kw">use </span>std::{borrow::Cow, default::Default};
<span class="kw">use</span> <span class="ident">actix_utils::future</span>::{<span class="ident">ready</span>, <span class="ident">Ready</span>};
<span class="kw">use</span> <span class="ident">actix_web</span>::{<span class="ident">dev::Payload</span>, <span class="ident">http::header::Header</span>, <span class="ident">FromRequest</span>, <span class="ident">HttpRequest</span>};
<span class="kw">use </span>actix_utils::future::{ready, Ready};
<span class="kw">use </span>actix_web::{dev::Payload, http::header::Header, FromRequest, HttpRequest};
<span class="kw">use</span> <span class="kw">super</span>::{<span class="ident">config::AuthExtractorConfig</span>, <span class="ident">errors::AuthenticationError</span>};
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::headers::www_authenticate::bearer::Error</span>;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::headers</span>::{<span class="ident">authorization</span>, <span class="ident">www_authenticate::bearer</span>};
<span class="kw">use super</span>::{config::AuthExtractorConfig, errors::AuthenticationError};
<span class="kw">pub use </span><span class="kw">crate</span>::headers::www_authenticate::bearer::Error;
<span class="kw">use </span><span class="kw">crate</span>::headers::{authorization, www_authenticate::bearer};
<span class="doccomment">/// [`BearerAuth`] extractor configuration.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">Default</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Config</span>(<span class="ident">bearer::Bearer</span>);
<span class="doccomment">/// [`BearerAuth`] extractor configuration.
</span><span class="attribute">#[derive(Debug, Clone, Default)]
</span><span class="kw">pub struct </span>Config(bearer::Bearer);
<span class="kw">impl</span> <span class="ident">Config</span> {
<span class="doccomment">/// Set challenge `scope` attribute.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// The `&quot;scope&quot;` attribute is a space-delimited list of case-sensitive</span>
<span class="doccomment">/// scope values indicating the required scope of the access token for</span>
<span class="doccomment">/// accessing the requested resource.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">scope</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">value</span>: <span class="ident">T</span>) -&gt; <span class="ident">Config</span> {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">scope</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">value</span>.<span class="ident">into</span>());
<span class="self">self</span>
}
<span class="kw">impl </span>Config {
<span class="doccomment">/// Set challenge `scope` attribute.
///
/// The `&quot;scope&quot;` attribute is a space-delimited list of case-sensitive
/// scope values indicating the required scope of the access token for
/// accessing the requested resource.
</span><span class="kw">pub fn </span>scope&lt;T: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;&gt;(<span class="kw-2">mut </span><span class="self">self</span>, value: T) -&gt; Config {
<span class="self">self</span>.<span class="number">0</span>.scope = <span class="prelude-val">Some</span>(value.into());
<span class="self">self
</span>}
<span class="doccomment">/// Set challenge `realm` attribute.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// The &quot;realm&quot; attribute indicates the scope of protection in the manner</span>
<span class="doccomment">/// described in HTTP/1.1 [RFC 2617](https://tools.ietf.org/html/rfc2617#section-1.2).</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">realm</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">value</span>: <span class="ident">T</span>) -&gt; <span class="ident">Config</span> {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">realm</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">value</span>.<span class="ident">into</span>());
<span class="self">self</span>
<span class="doccomment">/// Set challenge `realm` attribute.
///
/// The &quot;realm&quot; attribute indicates the scope of protection in the manner
/// described in HTTP/1.1 [RFC 2617](https://tools.ietf.org/html/rfc2617#section-1.2).
</span><span class="kw">pub fn </span>realm&lt;T: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;&gt;(<span class="kw-2">mut </span><span class="self">self</span>, value: T) -&gt; Config {
<span class="self">self</span>.<span class="number">0</span>.realm = <span class="prelude-val">Some</span>(value.into());
<span class="self">self
</span>}
}
<span class="kw">impl </span>AsRef&lt;bearer::Bearer&gt; <span class="kw">for </span>Config {
<span class="kw">fn </span>as_ref(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>bearer::Bearer {
<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0
</span>}
}
<span class="kw">impl </span>AuthExtractorConfig <span class="kw">for </span>Config {
<span class="kw">type </span>Inner = bearer::Bearer;
<span class="kw">fn </span>into_inner(<span class="self">self</span>) -&gt; <span class="self">Self</span>::Inner {
<span class="self">self</span>.<span class="number">0
</span>}
}
<span class="doccomment">/// Extractor for HTTP Bearer auth
///
/// # Examples
/// ```
/// use actix_web_httpauth::extractors::bearer::BearerAuth;
///
/// async fn index(auth: BearerAuth) -&gt; String {
/// format!(&quot;Hello, user with token {}!&quot;, auth.token())
/// }
/// ```
///
/// If authentication fails, this extractor fetches the [`Config`] instance
/// from the [app data] in order to properly form the `WWW-Authenticate`
/// response header.
///
/// # Examples
/// ```
/// use actix_web::{web, App};
/// use actix_web_httpauth::extractors::bearer::{self, BearerAuth};
///
/// async fn index(auth: BearerAuth) -&gt; String {
/// format!(&quot;Hello, {}!&quot;, auth.token())
/// }
///
/// App::new()
/// .app_data(
/// bearer::Config::default()
/// .realm(&quot;Restricted area&quot;)
/// .scope(&quot;email photo&quot;),
/// )
/// .service(web::resource(&quot;/index.html&quot;).route(web::get().to(index)));
/// ```
</span><span class="attribute">#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>BearerAuth(authorization::Bearer);
<span class="kw">impl </span>BearerAuth {
<span class="doccomment">/// Returns bearer token provided by client.
</span><span class="kw">pub fn </span>token(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="self">self</span>.<span class="number">0</span>.token()
}
}
<span class="kw">impl</span> <span class="ident">AsRef</span><span class="op">&lt;</span><span class="ident">bearer::Bearer</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Config</span> {
<span class="kw">fn</span> <span class="ident">as_ref</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="ident">bearer::Bearer</span> {
<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0</span>
}
}
<span class="kw">impl </span>FromRequest <span class="kw">for </span>BearerAuth {
<span class="kw">type </span>Future = Ready&lt;<span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, <span class="self">Self</span>::Error&gt;&gt;;
<span class="kw">type </span>Error = AuthenticationError&lt;bearer::Bearer&gt;;
<span class="kw">impl</span> <span class="ident">AuthExtractorConfig</span> <span class="kw">for</span> <span class="ident">Config</span> {
<span class="kw">type</span> <span class="ident">Inner</span> <span class="op">=</span> <span class="ident">bearer::Bearer</span>;
<span class="kw">fn </span>from_request(req: <span class="kw-2">&amp;</span>HttpRequest, _payload: <span class="kw-2">&amp;mut </span>Payload) -&gt; &lt;<span class="self">Self </span><span class="kw">as </span>FromRequest&gt;::Future {
ready(
authorization::Authorization::&lt;authorization::Bearer&gt;::parse(req)
.map(|auth| BearerAuth(auth.into_scheme()))
.map_err(|<span class="kw">_</span>| {
<span class="kw">let </span>bearer = req
.app_data::&lt;Config&gt;()
.map(|config| config.<span class="number">0</span>.clone())
.unwrap_or_else(Default::default);
<span class="kw">fn</span> <span class="ident">into_inner</span>(<span class="self">self</span>) -&gt; <span class="ident"><span class="self">Self</span>::Inner</span> {
<span class="self">self</span>.<span class="number">0</span>
}
}
<span class="doccomment">/// Extractor for HTTP Bearer auth</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_web_httpauth::extractors::bearer::BearerAuth;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// async fn index(auth: BearerAuth) -&gt; String {</span>
<span class="doccomment">/// format!(&quot;Hello, user with token {}!&quot;, auth.token())</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If authentication fails, this extractor fetches the [`Config`] instance</span>
<span class="doccomment">/// from the [app data] in order to properly form the `WWW-Authenticate`</span>
<span class="doccomment">/// response header.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_web::{web, App};</span>
<span class="doccomment">/// use actix_web_httpauth::extractors::bearer::{self, BearerAuth};</span>
<span class="doccomment">///</span>
<span class="doccomment">/// async fn index(auth: BearerAuth) -&gt; String {</span>
<span class="doccomment">/// format!(&quot;Hello, {}!&quot;, auth.token())</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// App::new()</span>
<span class="doccomment">/// .app_data(</span>
<span class="doccomment">/// bearer::Config::default()</span>
<span class="doccomment">/// .realm(&quot;Restricted area&quot;)</span>
<span class="doccomment">/// .scope(&quot;email photo&quot;),</span>
<span class="doccomment">/// )</span>
<span class="doccomment">/// .service(web::resource(&quot;/index.html&quot;).route(web::get().to(index)));</span>
<span class="doccomment">/// ```</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">BearerAuth</span>(<span class="ident">authorization::Bearer</span>);
<span class="kw">impl</span> <span class="ident">BearerAuth</span> {
<span class="doccomment">/// Returns bearer token provided by client.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">token</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="ident">str</span> {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">token</span>()
}
}
<span class="kw">impl</span> <span class="ident">FromRequest</span> <span class="kw">for</span> <span class="ident">BearerAuth</span> {
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">Ready</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">AuthenticationError</span><span class="op">&lt;</span><span class="ident">bearer::Bearer</span><span class="op">&gt;</span>;
<span class="kw">fn</span> <span class="ident">from_request</span>(<span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">HttpRequest</span>, <span class="ident">_payload</span>: <span class="kw-2">&amp;mut</span> <span class="ident">Payload</span>) -&gt; <span class="op">&lt;</span><span class="self">Self</span> <span class="kw">as</span> <span class="ident">FromRequest</span><span class="op">&gt;</span><span class="ident">::Future</span> {
<span class="ident">ready</span>(
<span class="ident">authorization::Authorization</span>::<span class="op">&lt;</span><span class="ident">authorization::Bearer</span><span class="op">&gt;</span><span class="ident">::parse</span>(<span class="ident">req</span>)
.<span class="ident">map</span>(<span class="op">|</span><span class="ident">auth</span><span class="op">|</span> <span class="ident">BearerAuth</span>(<span class="ident">auth</span>.<span class="ident">into_scheme</span>()))
.<span class="ident">map_err</span>(<span class="op">|</span><span class="kw">_</span><span class="op">|</span> {
<span class="kw">let</span> <span class="ident">bearer</span> <span class="op">=</span> <span class="ident">req</span>
.<span class="ident">app_data</span>::<span class="op">&lt;</span><span class="ident">Config</span><span class="op">&gt;</span>()
.<span class="ident">map</span>(<span class="op">|</span><span class="ident">config</span><span class="op">|</span> <span class="ident">config</span>.<span class="number">0</span>.<span class="ident">clone</span>())
.<span class="ident">unwrap_or_else</span>(<span class="ident">Default::default</span>);
<span class="ident">AuthenticationError::new</span>(<span class="ident">bearer</span>)
AuthenticationError::new(bearer)
}),
)
}
}
<span class="doccomment">/// Extended error customization for HTTP `Bearer` auth.</span>
<span class="kw">impl</span> <span class="ident">AuthenticationError</span><span class="op">&lt;</span><span class="ident">bearer::Bearer</span><span class="op">&gt;</span> {
<span class="doccomment">/// Attach `Error` to the current Authentication error.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Error status code will be changed to the one provided by the `kind`</span>
<span class="doccomment">/// Error.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">with_error</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">kind</span>: <span class="ident">Error</span>) -&gt; <span class="self">Self</span> {
<span class="kw-2">*</span><span class="self">self</span>.<span class="ident">status_code_mut</span>() <span class="op">=</span> <span class="ident">kind</span>.<span class="ident">status_code</span>();
<span class="self">self</span>.<span class="ident">challenge_mut</span>().<span class="ident">error</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">kind</span>);
<span class="self">self</span>
}
<span class="doccomment">/// Extended error customization for HTTP `Bearer` auth.
</span><span class="kw">impl </span>AuthenticationError&lt;bearer::Bearer&gt; {
<span class="doccomment">/// Attach `Error` to the current Authentication error.
///
/// Error status code will be changed to the one provided by the `kind`
/// Error.
</span><span class="kw">pub fn </span>with_error(<span class="kw-2">mut </span><span class="self">self</span>, kind: Error) -&gt; <span class="self">Self </span>{
<span class="kw-2">*</span><span class="self">self</span>.status_code_mut() = kind.status_code();
<span class="self">self</span>.challenge_mut().error = <span class="prelude-val">Some</span>(kind);
<span class="self">self
</span>}
<span class="doccomment">/// Attach error description to the current Authentication error.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">with_error_description</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">desc</span>: <span class="ident">T</span>) -&gt; <span class="self">Self</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="doccomment">/// Attach error description to the current Authentication error.
</span><span class="kw">pub fn </span>with_error_description&lt;T&gt;(<span class="kw-2">mut </span><span class="self">self</span>, desc: T) -&gt; <span class="self">Self
</span><span class="kw">where
</span>T: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
{
<span class="self">self</span>.<span class="ident">challenge_mut</span>().<span class="ident">error_description</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">desc</span>.<span class="ident">into</span>());
<span class="self">self</span>
}
<span class="self">self</span>.challenge_mut().error_description = <span class="prelude-val">Some</span>(desc.into());
<span class="self">self
</span>}
<span class="doccomment">/// Attach error URI to the current Authentication error.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// It is up to implementor to provide properly formed absolute URI.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">with_error_uri</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">uri</span>: <span class="ident">T</span>) -&gt; <span class="self">Self</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="doccomment">/// Attach error URI to the current Authentication error.
///
/// It is up to implementor to provide properly formed absolute URI.
</span><span class="kw">pub fn </span>with_error_uri&lt;T&gt;(<span class="kw-2">mut </span><span class="self">self</span>, uri: T) -&gt; <span class="self">Self
</span><span class="kw">where
</span>T: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
{
<span class="self">self</span>.<span class="ident">challenge_mut</span>().<span class="ident">error_uri</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">uri</span>.<span class="ident">into</span>());
<span class="self">self</span>
}
<span class="self">self</span>.challenge_mut().error_uri = <span class="prelude-val">Some</span>(uri.into());
<span class="self">self
</span>}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -19,26 +19,26 @@
<span id="19">19</span>
<span id="20">20</span>
<span id="21">21</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident"><span class="kw">super</span>::AuthenticationError</span>;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::headers::www_authenticate::Challenge</span>;
</pre><pre class="rust"><code><span class="kw">use </span><span class="kw">super</span>::AuthenticationError;
<span class="kw">use </span><span class="kw">crate</span>::headers::www_authenticate::Challenge;
<span class="doccomment">/// Trait implemented for types that provides configuration for the authentication</span>
<span class="doccomment">/// [extractors](super::AuthExtractor).</span>
<span class="kw">pub</span> <span class="kw">trait</span> <span class="ident">AuthExtractorConfig</span> {
<span class="doccomment">/// Associated challenge type.</span>
<span class="kw">type</span> <span class="ident">Inner</span>: <span class="ident">Challenge</span>;
<span class="doccomment">/// Trait implemented for types that provides configuration for the authentication
/// [extractors](super::AuthExtractor).
</span><span class="kw">pub trait </span>AuthExtractorConfig {
<span class="doccomment">/// Associated challenge type.
</span><span class="kw">type </span>Inner: Challenge;
<span class="doccomment">/// Convert the config instance into a HTTP challenge.</span>
<span class="kw">fn</span> <span class="ident">into_inner</span>(<span class="self">self</span>) -&gt; <span class="ident"><span class="self">Self</span>::Inner</span>;
<span class="doccomment">/// Convert the config instance into a HTTP challenge.
</span><span class="kw">fn </span>into_inner(<span class="self">self</span>) -&gt; <span class="self">Self</span>::Inner;
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">AuthenticationError</span><span class="op">&lt;</span><span class="op">&lt;</span><span class="ident">T</span> <span class="kw">as</span> <span class="ident">AuthExtractorConfig</span><span class="op">&gt;</span><span class="ident">::Inner</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">AuthExtractorConfig</span>,
<span class="kw">impl</span>&lt;T&gt; From&lt;T&gt; <span class="kw">for </span>AuthenticationError&lt;&lt;T <span class="kw">as </span>AuthExtractorConfig&gt;::Inner&gt;
<span class="kw">where
</span>T: AuthExtractorConfig,
{
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">config</span>: <span class="ident">T</span>) -&gt; <span class="self">Self</span> {
<span class="ident">AuthenticationError::new</span>(<span class="ident">config</span>.<span class="ident">into_inner</span>())
<span class="kw">fn </span>from(config: T) -&gt; <span class="self">Self </span>{
AuthenticationError::new(config.into_inner())
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -77,84 +77,84 @@
<span id="77">77</span>
<span id="78">78</span>
<span id="79">79</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">error::Error</span>, <span class="ident">fmt</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{error::Error, fmt};
<span class="kw">use</span> <span class="ident">actix_web</span>::{<span class="ident">http::StatusCode</span>, <span class="ident">HttpResponse</span>, <span class="ident">ResponseError</span>};
<span class="kw">use </span>actix_web::{http::StatusCode, HttpResponse, ResponseError};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::headers::www_authenticate</span>::{<span class="ident">Challenge</span>, <span class="ident">WwwAuthenticate</span>};
<span class="kw">use </span><span class="kw">crate</span>::headers::www_authenticate::{Challenge, WwwAuthenticate};
<span class="doccomment">/// Authentication error returned by authentication extractors.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Different extractors may extend `AuthenticationError` implementation in order to provide access</span>
<span class="doccomment">/// inner challenge fields.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">AuthenticationError</span><span class="op">&lt;</span><span class="ident">C</span>: <span class="ident">Challenge</span><span class="op">&gt;</span> {
<span class="ident">challenge</span>: <span class="ident">C</span>,
<span class="ident">status_code</span>: <span class="ident">StatusCode</span>,
<span class="doccomment">/// Authentication error returned by authentication extractors.
///
/// Different extractors may extend `AuthenticationError` implementation in order to provide access
/// inner challenge fields.
</span><span class="attribute">#[derive(Debug)]
</span><span class="kw">pub struct </span>AuthenticationError&lt;C: Challenge&gt; {
challenge: C,
status_code: StatusCode,
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">C</span>: <span class="ident">Challenge</span><span class="op">&gt;</span> <span class="ident">AuthenticationError</span><span class="op">&lt;</span><span class="ident">C</span><span class="op">&gt;</span> {
<span class="doccomment">/// Creates new authentication error from the provided `challenge`.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// By default returned error will resolve into the `HTTP 401` status code.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">new</span>(<span class="ident">challenge</span>: <span class="ident">C</span>) -&gt; <span class="ident">AuthenticationError</span><span class="op">&lt;</span><span class="ident">C</span><span class="op">&gt;</span> {
<span class="ident">AuthenticationError</span> {
<span class="ident">challenge</span>,
<span class="ident">status_code</span>: <span class="ident">StatusCode::UNAUTHORIZED</span>,
<span class="kw">impl</span>&lt;C: Challenge&gt; AuthenticationError&lt;C&gt; {
<span class="doccomment">/// Creates new authentication error from the provided `challenge`.
///
/// By default returned error will resolve into the `HTTP 401` status code.
</span><span class="kw">pub fn </span>new(challenge: C) -&gt; AuthenticationError&lt;C&gt; {
AuthenticationError {
challenge,
status_code: StatusCode::UNAUTHORIZED,
}
}
<span class="doccomment">/// Returns mutable reference to the inner challenge instance.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">challenge_mut</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut</span> <span class="ident">C</span> {
<span class="kw-2">&amp;mut</span> <span class="self">self</span>.<span class="ident">challenge</span>
<span class="doccomment">/// Returns mutable reference to the inner challenge instance.
</span><span class="kw">pub fn </span>challenge_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>C {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.challenge
}
<span class="doccomment">/// Returns mutable reference to the inner status code.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Can be used to override returned status code, but by default this lib tries to stick to the</span>
<span class="doccomment">/// RFC, so it might be unreasonable.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">status_code_mut</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut</span> <span class="ident">StatusCode</span> {
<span class="kw-2">&amp;mut</span> <span class="self">self</span>.<span class="ident">status_code</span>
<span class="doccomment">/// Returns mutable reference to the inner status code.
///
/// Can be used to override returned status code, but by default this lib tries to stick to the
/// RFC, so it might be unreasonable.
</span><span class="kw">pub fn </span>status_code_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>StatusCode {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.status_code
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">C</span>: <span class="ident">Challenge</span><span class="op">&gt;</span> <span class="ident">fmt::Display</span> <span class="kw">for</span> <span class="ident">AuthenticationError</span><span class="op">&lt;</span><span class="ident">C</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="ident">fmt::Display::fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">status_code</span>, <span class="ident">f</span>)
<span class="kw">impl</span>&lt;C: Challenge&gt; fmt::Display <span class="kw">for </span>AuthenticationError&lt;C&gt; {
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
fmt::Display::fmt(<span class="kw-2">&amp;</span><span class="self">self</span>.status_code, f)
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">C</span>: <span class="ident">Challenge</span> <span class="op">+</span> <span class="lifetime">&#39;static</span><span class="op">&gt;</span> <span class="ident">Error</span> <span class="kw">for</span> <span class="ident">AuthenticationError</span><span class="op">&lt;</span><span class="ident">C</span><span class="op">&gt;</span> {}
<span class="kw">impl</span>&lt;C: Challenge + <span class="lifetime">&#39;static</span>&gt; Error <span class="kw">for </span>AuthenticationError&lt;C&gt; {}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">C</span>: <span class="ident">Challenge</span> <span class="op">+</span> <span class="lifetime">&#39;static</span><span class="op">&gt;</span> <span class="ident">ResponseError</span> <span class="kw">for</span> <span class="ident">AuthenticationError</span><span class="op">&lt;</span><span class="ident">C</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">status_code</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">StatusCode</span> {
<span class="self">self</span>.<span class="ident">status_code</span>
<span class="kw">impl</span>&lt;C: Challenge + <span class="lifetime">&#39;static</span>&gt; ResponseError <span class="kw">for </span>AuthenticationError&lt;C&gt; {
<span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
<span class="self">self</span>.status_code
}
<span class="kw">fn</span> <span class="ident">error_response</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">HttpResponse</span> {
<span class="ident">HttpResponse::build</span>(<span class="self">self</span>.<span class="ident">status_code</span>())
.<span class="ident">insert_header</span>(<span class="ident">WwwAuthenticate</span>(<span class="self">self</span>.<span class="ident">challenge</span>.<span class="ident">clone</span>()))
.<span class="ident">finish</span>()
<span class="kw">fn </span>error_response(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; HttpResponse {
HttpResponse::build(<span class="self">self</span>.status_code())
.insert_header(WwwAuthenticate(<span class="self">self</span>.challenge.clone()))
.finish()
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="ident">actix_web::Error</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>actix_web::Error;
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::headers::www_authenticate::basic::Basic</span>;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use </span><span class="kw">crate</span>::headers::www_authenticate::basic::Basic;
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_status_code_is_preserved_across_error_conversions</span>() {
<span class="kw">let</span> <span class="ident">ae</span> <span class="op">=</span> <span class="ident">AuthenticationError::new</span>(<span class="ident">Basic::default</span>());
<span class="kw">let</span> <span class="ident">expected</span> <span class="op">=</span> <span class="ident">ae</span>.<span class="ident">status_code</span>;
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_status_code_is_preserved_across_error_conversions() {
<span class="kw">let </span>ae = AuthenticationError::new(Basic::default());
<span class="kw">let </span>expected = ae.status_code;
<span class="comment">// Converting the AuthenticationError into a ResponseError should preserve the status code.</span>
<span class="kw">let</span> <span class="ident">err</span> <span class="op">=</span> <span class="ident">Error::from</span>(<span class="ident">ae</span>);
<span class="kw">let</span> <span class="ident">res_err</span> <span class="op">=</span> <span class="ident">err</span>.<span class="ident">as_response_error</span>();
<span class="macro">assert_eq!</span>(<span class="ident">expected</span>, <span class="ident">res_err</span>.<span class="ident">status_code</span>());
<span class="comment">// Converting the AuthenticationError into a ResponseError should preserve the status code.
</span><span class="kw">let </span>err = Error::from(ae);
<span class="kw">let </span>res_err = err.as_response_error();
<span class="macro">assert_eq!</span>(expected, res_err.status_code());
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -7,14 +7,14 @@
<span id="7">7</span>
<span id="8">8</span>
<span id="9">9</span>
</pre><pre class="rust"><code><span class="doccomment">//! Type-safe authentication information extractors.</span>
</pre><pre class="rust"><code><span class="doccomment">//! Type-safe authentication information extractors.
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">basic</span>;
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">bearer</span>;
<span class="kw">mod</span> <span class="ident">config</span>;
<span class="kw">mod</span> <span class="ident">errors</span>;
</span><span class="kw">pub mod </span>basic;
<span class="kw">pub mod </span>bearer;
<span class="kw">mod </span>config;
<span class="kw">mod </span>errors;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::config::AuthExtractorConfig</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::errors::AuthenticationError</span>;
<span class="kw">pub use </span><span class="self">self</span>::config::AuthExtractorConfig;
<span class="kw">pub use </span><span class="self">self</span>::errors::AuthenticationError;
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -70,77 +70,77 @@
<span id="70">70</span>
<span id="71">71</span>
<span id="72">72</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">convert::From</span>, <span class="ident">error::Error</span>, <span class="ident">fmt</span>, <span class="ident">str</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{convert::From, error::Error, fmt, str};
<span class="kw">use</span> <span class="ident">actix_web::http::header</span>;
<span class="kw">use </span>actix_web::http::header;
<span class="doccomment">/// Possible errors while parsing `Authorization` header.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Should not be used directly unless you are implementing your own</span>
<span class="doccomment">/// [authentication scheme](super::Scheme).</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">ParseError</span> {
<span class="doccomment">/// Header value is malformed.</span>
<span class="ident">Invalid</span>,
<span class="doccomment">/// Possible errors while parsing `Authorization` header.
///
/// Should not be used directly unless you are implementing your own
/// [authentication scheme](super::Scheme).
</span><span class="attribute">#[derive(Debug)]
</span><span class="kw">pub enum </span>ParseError {
<span class="doccomment">/// Header value is malformed.
</span>Invalid,
<span class="doccomment">/// Authentication scheme is missing.</span>
<span class="ident">MissingScheme</span>,
<span class="doccomment">/// Authentication scheme is missing.
</span>MissingScheme,
<span class="doccomment">/// Required authentication field is missing.</span>
<span class="ident">MissingField</span>(<span class="kw-2">&amp;</span><span class="lifetime">&#39;static</span> <span class="ident">str</span>),
<span class="doccomment">/// Required authentication field is missing.
</span>MissingField(<span class="kw-2">&amp;</span><span class="lifetime">&#39;static </span>str),
<span class="doccomment">/// Unable to convert header into the str.</span>
<span class="ident">ToStrError</span>(<span class="ident">header::ToStrError</span>),
<span class="doccomment">/// Unable to convert header into the str.
</span>ToStrError(header::ToStrError),
<span class="doccomment">/// Malformed base64 string.</span>
<span class="ident">Base64DecodeError</span>(<span class="ident">base64::DecodeError</span>),
<span class="doccomment">/// Malformed base64 string.
</span>Base64DecodeError(base64::DecodeError),
<span class="doccomment">/// Malformed UTF-8 string.</span>
<span class="ident">Utf8Error</span>(<span class="ident">str::Utf8Error</span>),
<span class="doccomment">/// Malformed UTF-8 string.
</span>Utf8Error(str::Utf8Error),
}
<span class="kw">impl</span> <span class="ident">fmt::Display</span> <span class="kw">for</span> <span class="ident">ParseError</span> {
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="kw">match</span> <span class="self">self</span> {
<span class="ident">ParseError::Invalid</span> =&gt; <span class="ident">f</span>.<span class="ident">write_str</span>(<span class="string">&quot;Invalid header value&quot;</span>),
<span class="ident">ParseError::MissingScheme</span> =&gt; <span class="ident">f</span>.<span class="ident">write_str</span>(<span class="string">&quot;Missing authorization scheme&quot;</span>),
<span class="ident">ParseError::MissingField</span>(<span class="ident">field</span>) =&gt; <span class="macro">write!</span>(<span class="ident">f</span>, <span class="string">&quot;Missing header field ({})&quot;</span>, <span class="ident">field</span>),
<span class="ident">ParseError::ToStrError</span>(<span class="ident">err</span>) =&gt; <span class="ident">fmt::Display::fmt</span>(<span class="ident">err</span>, <span class="ident">f</span>),
<span class="ident">ParseError::Base64DecodeError</span>(<span class="ident">err</span>) =&gt; <span class="ident">fmt::Display::fmt</span>(<span class="ident">err</span>, <span class="ident">f</span>),
<span class="ident">ParseError::Utf8Error</span>(<span class="ident">err</span>) =&gt; <span class="ident">fmt::Display::fmt</span>(<span class="ident">err</span>, <span class="ident">f</span>),
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>ParseError {
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
<span class="kw">match </span><span class="self">self </span>{
ParseError::Invalid =&gt; f.write_str(<span class="string">&quot;Invalid header value&quot;</span>),
ParseError::MissingScheme =&gt; f.write_str(<span class="string">&quot;Missing authorization scheme&quot;</span>),
ParseError::MissingField(field) =&gt; <span class="macro">write!</span>(f, <span class="string">&quot;Missing header field ({})&quot;</span>, field),
ParseError::ToStrError(err) =&gt; fmt::Display::fmt(err, f),
ParseError::Base64DecodeError(err) =&gt; fmt::Display::fmt(err, f),
ParseError::Utf8Error(err) =&gt; fmt::Display::fmt(err, f),
}
}
}
<span class="kw">impl</span> <span class="ident">Error</span> <span class="kw">for</span> <span class="ident">ParseError</span> {
<span class="kw">fn</span> <span class="ident">source</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="kw-2">&amp;</span>(<span class="kw">dyn</span> <span class="ident">Error</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>)<span class="op">&gt;</span> {
<span class="kw">match</span> <span class="self">self</span> {
<span class="ident">ParseError::Invalid</span> =&gt; <span class="prelude-val">None</span>,
<span class="ident">ParseError::MissingScheme</span> =&gt; <span class="prelude-val">None</span>,
<span class="ident">ParseError::MissingField</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">None</span>,
<span class="ident">ParseError::ToStrError</span>(<span class="ident">err</span>) =&gt; <span class="prelude-val">Some</span>(<span class="ident">err</span>),
<span class="ident">ParseError::Base64DecodeError</span>(<span class="ident">err</span>) =&gt; <span class="prelude-val">Some</span>(<span class="ident">err</span>),
<span class="ident">ParseError::Utf8Error</span>(<span class="ident">err</span>) =&gt; <span class="prelude-val">Some</span>(<span class="ident">err</span>),
<span class="kw">impl </span>Error <span class="kw">for </span>ParseError {
<span class="kw">fn </span>source(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>(<span class="kw">dyn </span>Error + <span class="lifetime">&#39;static</span>)&gt; {
<span class="kw">match </span><span class="self">self </span>{
ParseError::Invalid =&gt; <span class="prelude-val">None</span>,
ParseError::MissingScheme =&gt; <span class="prelude-val">None</span>,
ParseError::MissingField(<span class="kw">_</span>) =&gt; <span class="prelude-val">None</span>,
ParseError::ToStrError(err) =&gt; <span class="prelude-val">Some</span>(err),
ParseError::Base64DecodeError(err) =&gt; <span class="prelude-val">Some</span>(err),
ParseError::Utf8Error(err) =&gt; <span class="prelude-val">Some</span>(err),
}
}
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">header::ToStrError</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">ParseError</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">err</span>: <span class="ident">header::ToStrError</span>) -&gt; <span class="self">Self</span> {
<span class="ident">ParseError::ToStrError</span>(<span class="ident">err</span>)
<span class="kw">impl </span>From&lt;header::ToStrError&gt; <span class="kw">for </span>ParseError {
<span class="kw">fn </span>from(err: header::ToStrError) -&gt; <span class="self">Self </span>{
ParseError::ToStrError(err)
}
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">base64::DecodeError</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">ParseError</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">err</span>: <span class="ident">base64::DecodeError</span>) -&gt; <span class="self">Self</span> {
<span class="ident">ParseError::Base64DecodeError</span>(<span class="ident">err</span>)
<span class="kw">impl </span>From&lt;base64::DecodeError&gt; <span class="kw">for </span>ParseError {
<span class="kw">fn </span>from(err: base64::DecodeError) -&gt; <span class="self">Self </span>{
ParseError::Base64DecodeError(err)
}
}
<span class="kw">impl</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">str::Utf8Error</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">ParseError</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">err</span>: <span class="ident">str::Utf8Error</span>) -&gt; <span class="self">Self</span> {
<span class="ident">ParseError::Utf8Error</span>(<span class="ident">err</span>)
<span class="kw">impl </span>From&lt;str::Utf8Error&gt; <span class="kw">for </span>ParseError {
<span class="kw">fn </span>from(err: str::Utf8Error) -&gt; <span class="self">Self </span>{
ParseError::Utf8Error(err)
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -82,89 +82,89 @@
<span id="82">82</span>
<span id="83">83</span>
<span id="84">84</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::fmt</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::fmt;
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">error::ParseError</span>,
<span class="ident">http::header</span>::{<span class="ident">Header</span>, <span class="ident">HeaderName</span>, <span class="ident">HeaderValue</span>, <span class="ident">TryIntoHeaderValue</span>, <span class="ident">AUTHORIZATION</span>},
<span class="ident">HttpMessage</span>,
<span class="kw">use </span>actix_web::{
error::ParseError,
http::header::{Header, HeaderName, HeaderValue, TryIntoHeaderValue, AUTHORIZATION},
HttpMessage,
};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::headers::authorization::scheme::Scheme</span>;
<span class="kw">use </span><span class="kw">crate</span>::headers::authorization::scheme::Scheme;
<span class="doccomment">/// `Authorization` header, defined in [RFC 7235](https://tools.ietf.org/html/rfc7235#section-4.2)</span>
<span class="doccomment">///</span>
<span class="doccomment">/// The &quot;Authorization&quot; header field allows a user agent to authenticate itself with an origin</span>
<span class="doccomment">/// server—usually, but not necessarily, after receiving a 401 (Unauthorized) response. Its value</span>
<span class="doccomment">/// consists of credentials containing the authentication information of the user agent for the</span>
<span class="doccomment">/// realm of the resource being requested.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// `Authorization` is generic over an [authentication scheme](Scheme).</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web::{HttpRequest, Result, http::header::Header};</span>
<span class="doccomment">/// # use actix_web_httpauth::headers::authorization::{Authorization, Basic};</span>
<span class="doccomment">/// fn handler(req: HttpRequest) -&gt; Result&lt;String&gt; {</span>
<span class="doccomment">/// let auth = Authorization::&lt;Basic&gt;::parse(&amp;req)?;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Ok(format!(&quot;Hello, {}!&quot;, auth.as_ref().user_id()))</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Default</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">PartialOrd</span>, <span class="ident">Ord</span>, <span class="ident">Hash</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Authorization</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Scheme</span><span class="op">&gt;</span>(<span class="ident">S</span>);
<span class="doccomment">/// `Authorization` header, defined in [RFC 7235](https://tools.ietf.org/html/rfc7235#section-4.2)
///
/// The &quot;Authorization&quot; header field allows a user agent to authenticate itself with an origin
/// server—usually, but not necessarily, after receiving a 401 (Unauthorized) response. Its value
/// consists of credentials containing the authentication information of the user agent for the
/// realm of the resource being requested.
///
/// `Authorization` is generic over an [authentication scheme](Scheme).
///
/// # Examples
/// ```
/// # use actix_web::{HttpRequest, Result, http::header::Header};
/// # use actix_web_httpauth::headers::authorization::{Authorization, Basic};
/// fn handler(req: HttpRequest) -&gt; Result&lt;String&gt; {
/// let auth = Authorization::&lt;Basic&gt;::parse(&amp;req)?;
///
/// Ok(format!(&quot;Hello, {}!&quot;, auth.as_ref().user_id()))
/// }
/// ```
</span><span class="attribute">#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
</span><span class="kw">pub struct </span>Authorization&lt;S: Scheme&gt;(S);
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Scheme</span><span class="op">&gt;</span> <span class="ident">Authorization</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="doccomment">/// Consumes `Authorization` header and returns inner [`Scheme`] implementation.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">into_scheme</span>(<span class="self">self</span>) -&gt; <span class="ident">S</span> {
<span class="self">self</span>.<span class="number">0</span>
<span class="kw">impl</span>&lt;S: Scheme&gt; Authorization&lt;S&gt; {
<span class="doccomment">/// Consumes `Authorization` header and returns inner [`Scheme`] implementation.
</span><span class="kw">pub fn </span>into_scheme(<span class="self">self</span>) -&gt; S {
<span class="self">self</span>.<span class="number">0
</span>}
}
<span class="kw">impl</span>&lt;S: Scheme&gt; From&lt;S&gt; <span class="kw">for </span>Authorization&lt;S&gt; {
<span class="kw">fn </span>from(scheme: S) -&gt; Authorization&lt;S&gt; {
Authorization(scheme)
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Scheme</span><span class="op">&gt;</span> <span class="ident">From</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Authorization</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">from</span>(<span class="ident">scheme</span>: <span class="ident">S</span>) -&gt; <span class="ident">Authorization</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="ident">Authorization</span>(<span class="ident">scheme</span>)
<span class="kw">impl</span>&lt;S: Scheme&gt; AsRef&lt;S&gt; <span class="kw">for </span>Authorization&lt;S&gt; {
<span class="kw">fn </span>as_ref(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>S {
<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0
</span>}
}
<span class="kw">impl</span>&lt;S: Scheme&gt; AsMut&lt;S&gt; <span class="kw">for </span>Authorization&lt;S&gt; {
<span class="kw">fn </span>as_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>S {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.<span class="number">0
</span>}
}
<span class="kw">impl</span>&lt;S: Scheme&gt; fmt::Display <span class="kw">for </span>Authorization&lt;S&gt; {
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
fmt::Display::fmt(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0</span>, f)
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Scheme</span><span class="op">&gt;</span> <span class="ident">AsRef</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Authorization</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">as_ref</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="ident">S</span> {
<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0</span>
<span class="kw">impl</span>&lt;S: Scheme&gt; Header <span class="kw">for </span>Authorization&lt;S&gt; {
<span class="attribute">#[inline]
</span><span class="kw">fn </span>name() -&gt; HeaderName {
AUTHORIZATION
}
<span class="kw">fn </span>parse&lt;T: HttpMessage&gt;(msg: <span class="kw-2">&amp;</span>T) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, ParseError&gt; {
<span class="kw">let </span>header = msg.headers().get(<span class="self">Self</span>::name()).ok_or(ParseError::Header)<span class="question-mark">?</span>;
<span class="kw">let </span>scheme = S::parse(header).map_err(|<span class="kw">_</span>| ParseError::Header)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(Authorization(scheme))
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Scheme</span><span class="op">&gt;</span> <span class="ident">AsMut</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">Authorization</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">as_mut</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut</span> <span class="ident">S</span> {
<span class="kw-2">&amp;mut</span> <span class="self">self</span>.<span class="number">0</span>
}
}
<span class="kw">impl</span>&lt;S: Scheme&gt; TryIntoHeaderValue <span class="kw">for </span>Authorization&lt;S&gt; {
<span class="kw">type </span>Error = &lt;S <span class="kw">as </span>TryIntoHeaderValue&gt;::Error;
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Scheme</span><span class="op">&gt;</span> <span class="ident">fmt::Display</span> <span class="kw">for</span> <span class="ident">Authorization</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="ident">fmt::Display::fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0</span>, <span class="ident">f</span>)
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Scheme</span><span class="op">&gt;</span> <span class="ident">Header</span> <span class="kw">for</span> <span class="ident">Authorization</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="attribute">#[<span class="ident">inline</span>]</span>
<span class="kw">fn</span> <span class="ident">name</span>() -&gt; <span class="ident">HeaderName</span> {
<span class="ident">AUTHORIZATION</span>
}
<span class="kw">fn</span> <span class="ident">parse</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">HttpMessage</span><span class="op">&gt;</span>(<span class="ident">msg</span>: <span class="kw-2">&amp;</span><span class="ident">T</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">ParseError</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">header</span> <span class="op">=</span> <span class="ident">msg</span>.<span class="ident">headers</span>().<span class="ident">get</span>(<span class="ident"><span class="self">Self</span>::name</span>()).<span class="ident">ok_or</span>(<span class="ident">ParseError::Header</span>)<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">S::parse</span>(<span class="ident">header</span>).<span class="ident">map_err</span>(<span class="op">|</span><span class="kw">_</span><span class="op">|</span> <span class="ident">ParseError::Header</span>)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(<span class="ident">Authorization</span>(<span class="ident">scheme</span>))
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>: <span class="ident">Scheme</span><span class="op">&gt;</span> <span class="ident">TryIntoHeaderValue</span> <span class="kw">for</span> <span class="ident">Authorization</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span> {
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="op">&lt;</span><span class="ident">S</span> <span class="kw">as</span> <span class="ident">TryIntoHeaderValue</span><span class="op">&gt;</span><span class="ident">::Error</span>;
<span class="kw">fn</span> <span class="ident">try_into_value</span>(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HeaderValue</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span> {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">try_into_value</span>()
<span class="kw">fn </span>try_into_value(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;HeaderValue, <span class="self">Self</span>::Error&gt; {
<span class="self">self</span>.<span class="number">0</span>.try_into_value()
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -7,14 +7,14 @@
<span id="7">7</span>
<span id="8">8</span>
<span id="9">9</span>
</pre><pre class="rust"><code><span class="doccomment">//! `Authorization` header and various auth schemes.</span>
</pre><pre class="rust"><code><span class="doccomment">//! `Authorization` header and various auth schemes.
<span class="kw">mod</span> <span class="ident">errors</span>;
<span class="kw">mod</span> <span class="ident">header</span>;
<span class="kw">mod</span> <span class="ident">scheme</span>;
</span><span class="kw">mod </span>errors;
<span class="kw">mod </span>header;
<span class="kw">mod </span>scheme;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::errors::ParseError</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::header::Authorization</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::scheme</span>::{<span class="ident">basic::Basic</span>, <span class="ident">bearer::Bearer</span>, <span class="ident">Scheme</span>};
<span class="kw">pub use </span><span class="self">self</span>::errors::ParseError;
<span class="kw">pub use </span><span class="self">self</span>::header::Authorization;
<span class="kw">pub use </span><span class="self">self</span>::scheme::{basic::Basic, bearer::Bearer, Scheme};
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -193,200 +193,200 @@
<span id="193">193</span>
<span id="194">194</span>
<span id="195">195</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">borrow::Cow</span>, <span class="ident">fmt</span>, <span class="ident">str</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{borrow::Cow, fmt, str};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">http::header</span>::{<span class="ident">HeaderValue</span>, <span class="ident">InvalidHeaderValue</span>, <span class="ident">TryIntoHeaderValue</span>},
<span class="ident">web</span>::{<span class="ident">BufMut</span>, <span class="ident">BytesMut</span>},
<span class="kw">use </span>actix_web::{
http::header::{HeaderValue, InvalidHeaderValue, TryIntoHeaderValue},
web::{BufMut, BytesMut},
};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::headers::authorization</span>::{<span class="ident">errors::ParseError</span>, <span class="ident">Scheme</span>};
<span class="kw">use </span><span class="kw">crate</span>::headers::authorization::{errors::ParseError, Scheme};
<span class="doccomment">/// Credentials for `Basic` authentication scheme, defined in [RFC 7617](https://tools.ietf.org/html/rfc7617)</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">PartialOrd</span>, <span class="ident">Ord</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Basic</span> {
<span class="ident">user_id</span>: <span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span>,
<span class="ident">password</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="doccomment">/// Credentials for `Basic` authentication scheme, defined in [RFC 7617](https://tools.ietf.org/html/rfc7617)
</span><span class="attribute">#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
</span><span class="kw">pub struct </span>Basic {
user_id: Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;,
password: <span class="prelude-ty">Option</span>&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
}
<span class="kw">impl</span> <span class="ident">Basic</span> {
<span class="doccomment">/// Creates `Basic` credentials with provided `user_id` and optional</span>
<span class="doccomment">/// `password`.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web_httpauth::headers::authorization::Basic;</span>
<span class="doccomment">/// let credentials = Basic::new(&quot;Alladin&quot;, Some(&quot;open sesame&quot;));</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">new</span><span class="op">&lt;</span><span class="ident">U</span>, <span class="ident">P</span><span class="op">&gt;</span>(<span class="ident">user_id</span>: <span class="ident">U</span>, <span class="ident">password</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">P</span><span class="op">&gt;</span>) -&gt; <span class="ident">Basic</span>
<span class="kw">where</span>
<span class="ident">U</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="ident">P</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">impl </span>Basic {
<span class="doccomment">/// Creates `Basic` credentials with provided `user_id` and optional
/// `password`.
///
/// # Examples
/// ```
/// # use actix_web_httpauth::headers::authorization::Basic;
/// let credentials = Basic::new(&quot;Alladin&quot;, Some(&quot;open sesame&quot;));
/// ```
</span><span class="kw">pub fn </span>new&lt;U, P&gt;(user_id: U, password: <span class="prelude-ty">Option</span>&lt;P&gt;) -&gt; Basic
<span class="kw">where
</span>U: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
P: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
{
<span class="ident">Basic</span> {
<span class="ident">user_id</span>: <span class="ident">user_id</span>.<span class="ident">into</span>(),
<span class="ident">password</span>: <span class="ident">password</span>.<span class="ident">map</span>(<span class="ident">Into::into</span>),
Basic {
user_id: user_id.into(),
password: password.map(Into::into),
}
}
<span class="doccomment">/// Returns client&#39;s user-ID.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">user_id</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="ident">str</span> {
<span class="self">self</span>.<span class="ident">user_id</span>.<span class="ident">as_ref</span>()
<span class="doccomment">/// Returns client&#39;s user-ID.
</span><span class="kw">pub fn </span>user_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="self">self</span>.user_id.as_ref()
}
<span class="doccomment">/// Returns client&#39;s password if provided.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">password</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="kw-2">&amp;</span><span class="ident">str</span><span class="op">&gt;</span> {
<span class="self">self</span>.<span class="ident">password</span>.<span class="ident">as_deref</span>()
<span class="doccomment">/// Returns client&#39;s password if provided.
</span><span class="kw">pub fn </span>password(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt; {
<span class="self">self</span>.password.as_deref()
}
}
<span class="kw">impl</span> <span class="ident">Scheme</span> <span class="kw">for</span> <span class="ident">Basic</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">header</span>: <span class="kw-2">&amp;</span><span class="ident">HeaderValue</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">ParseError</span><span class="op">&gt;</span> {
<span class="comment">// &quot;Basic *&quot; length</span>
<span class="kw">if</span> <span class="ident">header</span>.<span class="ident">len</span>() <span class="op">&lt;</span> <span class="number">7</span> {
<span class="kw">return</span> <span class="prelude-val">Err</span>(<span class="ident">ParseError::Invalid</span>);
<span class="kw">impl </span>Scheme <span class="kw">for </span>Basic {
<span class="kw">fn </span>parse(header: <span class="kw-2">&amp;</span>HeaderValue) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, ParseError&gt; {
<span class="comment">// &quot;Basic *&quot; length
</span><span class="kw">if </span>header.len() &lt; <span class="number">7 </span>{
<span class="kw">return </span><span class="prelude-val">Err</span>(ParseError::Invalid);
}
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">parts</span> <span class="op">=</span> <span class="ident">header</span>.<span class="ident">to_str</span>()<span class="question-mark">?</span>.<span class="ident">splitn</span>(<span class="number">2</span>, <span class="string">&#39; &#39;</span>);
<span class="kw">match</span> <span class="ident">parts</span>.<span class="ident">next</span>() {
<span class="prelude-val">Some</span>(<span class="ident">scheme</span>) <span class="kw">if</span> <span class="ident">scheme</span> <span class="op">==</span> <span class="string">&quot;Basic&quot;</span> =&gt; (),
<span class="kw">_</span> =&gt; <span class="kw">return</span> <span class="prelude-val">Err</span>(<span class="ident">ParseError::MissingScheme</span>),
<span class="kw">let </span><span class="kw-2">mut </span>parts = header.to_str()<span class="question-mark">?</span>.splitn(<span class="number">2</span>, <span class="string">&#39; &#39;</span>);
<span class="kw">match </span>parts.next() {
<span class="prelude-val">Some</span>(scheme) <span class="kw">if </span>scheme == <span class="string">&quot;Basic&quot; </span>=&gt; (),
<span class="kw">_ </span>=&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(ParseError::MissingScheme),
}
<span class="kw">let</span> <span class="ident">decoded</span> <span class="op">=</span> <span class="ident">base64::decode</span>(<span class="ident">parts</span>.<span class="ident">next</span>().<span class="ident">ok_or</span>(<span class="ident">ParseError::Invalid</span>)<span class="question-mark">?</span>)<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">credentials</span> <span class="op">=</span> <span class="ident">str::from_utf8</span>(<span class="kw-2">&amp;</span><span class="ident">decoded</span>)<span class="question-mark">?</span>.<span class="ident">splitn</span>(<span class="number">2</span>, <span class="string">&#39;:&#39;</span>);
<span class="kw">let </span>decoded = base64::decode(parts.next().ok_or(ParseError::Invalid)<span class="question-mark">?</span>)<span class="question-mark">?</span>;
<span class="kw">let </span><span class="kw-2">mut </span>credentials = str::from_utf8(<span class="kw-2">&amp;</span>decoded)<span class="question-mark">?</span>.splitn(<span class="number">2</span>, <span class="string">&#39;:&#39;</span>);
<span class="kw">let</span> <span class="ident">user_id</span> <span class="op">=</span> <span class="ident">credentials</span>
.<span class="ident">next</span>()
.<span class="ident">ok_or</span>(<span class="ident">ParseError::MissingField</span>(<span class="string">&quot;user_id&quot;</span>))
.<span class="ident">map</span>(<span class="op">|</span><span class="ident">user_id</span><span class="op">|</span> <span class="ident">user_id</span>.<span class="ident">to_string</span>().<span class="ident">into</span>())<span class="question-mark">?</span>;
<span class="kw">let </span>user_id = credentials
.next()
.ok_or(ParseError::MissingField(<span class="string">&quot;user_id&quot;</span>))
.map(|user_id| user_id.to_string().into())<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">password</span> <span class="op">=</span> <span class="ident">credentials</span>
.<span class="ident">next</span>()
.<span class="ident">ok_or</span>(<span class="ident">ParseError::MissingField</span>(<span class="string">&quot;password&quot;</span>))
.<span class="ident">map</span>(<span class="op">|</span><span class="ident">password</span><span class="op">|</span> {
<span class="kw">if</span> <span class="ident">password</span>.<span class="ident">is_empty</span>() {
<span class="prelude-val">None</span>
} <span class="kw">else</span> {
<span class="prelude-val">Some</span>(<span class="ident">password</span>.<span class="ident">to_string</span>().<span class="ident">into</span>())
<span class="kw">let </span>password = credentials
.next()
.ok_or(ParseError::MissingField(<span class="string">&quot;password&quot;</span>))
.map(|password| {
<span class="kw">if </span>password.is_empty() {
<span class="prelude-val">None
</span>} <span class="kw">else </span>{
<span class="prelude-val">Some</span>(password.to_string().into())
}
})<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(<span class="ident">Basic</span> { <span class="ident">user_id</span>, <span class="ident">password</span> })
<span class="prelude-val">Ok</span>(Basic { user_id, password })
}
}
<span class="kw">impl</span> <span class="ident">fmt::Debug</span> <span class="kw">for</span> <span class="ident">Basic</span> {
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="ident">f</span>.<span class="ident">write_fmt</span>(<span class="macro">format_args!</span>(<span class="string">&quot;Basic {}:******&quot;</span>, <span class="self">self</span>.<span class="ident">user_id</span>))
<span class="kw">impl </span>fmt::Debug <span class="kw">for </span>Basic {
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
f.write_fmt(<span class="macro">format_args!</span>(<span class="string">&quot;Basic {}:******&quot;</span>, <span class="self">self</span>.user_id))
}
}
<span class="kw">impl</span> <span class="ident">fmt::Display</span> <span class="kw">for</span> <span class="ident">Basic</span> {
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="ident">f</span>.<span class="ident">write_fmt</span>(<span class="macro">format_args!</span>(<span class="string">&quot;Basic {}:******&quot;</span>, <span class="self">self</span>.<span class="ident">user_id</span>))
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>Basic {
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
f.write_fmt(<span class="macro">format_args!</span>(<span class="string">&quot;Basic {}:******&quot;</span>, <span class="self">self</span>.user_id))
}
}
<span class="kw">impl</span> <span class="ident">TryIntoHeaderValue</span> <span class="kw">for</span> <span class="ident">Basic</span> {
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">InvalidHeaderValue</span>;
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>Basic {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="kw">fn</span> <span class="ident">try_into_value</span>(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HeaderValue</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">credentials</span> <span class="op">=</span> <span class="ident">BytesMut::with_capacity</span>(
<span class="self">self</span>.<span class="ident">user_id</span>.<span class="ident">len</span>()
<span class="op">+</span> <span class="number">1</span> <span class="comment">// &#39;:&#39;</span>
<span class="op">+</span> <span class="self">self</span>.<span class="ident">password</span>.<span class="ident">as_ref</span>().<span class="ident">map_or</span>(<span class="number">0</span>, <span class="op">|</span><span class="ident">pwd</span><span class="op">|</span> <span class="ident">pwd</span>.<span class="ident">len</span>()),
<span class="kw">fn </span>try_into_value(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;HeaderValue, <span class="self">Self</span>::Error&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>credentials = BytesMut::with_capacity(
<span class="self">self</span>.user_id.len()
+ <span class="number">1 </span><span class="comment">// &#39;:&#39;
</span>+ <span class="self">self</span>.password.as_ref().map_or(<span class="number">0</span>, |pwd| pwd.len()),
);
<span class="ident">credentials</span>.<span class="ident">extend_from_slice</span>(<span class="self">self</span>.<span class="ident">user_id</span>.<span class="ident">as_bytes</span>());
<span class="ident">credentials</span>.<span class="ident">put_u8</span>(<span class="string">b&#39;:&#39;</span>);
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="ident">password</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">password</span> {
<span class="ident">credentials</span>.<span class="ident">extend_from_slice</span>(<span class="ident">password</span>.<span class="ident">as_bytes</span>());
credentials.extend_from_slice(<span class="self">self</span>.user_id.as_bytes());
credentials.put_u8(<span class="string">b&#39;:&#39;</span>);
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>password) = <span class="self">self</span>.password {
credentials.extend_from_slice(password.as_bytes());
}
<span class="comment">// TODO: It would be nice not to allocate new `String` here but write</span>
<span class="comment">// directly to `value`</span>
<span class="kw">let</span> <span class="ident">encoded</span> <span class="op">=</span> <span class="ident">base64::encode</span>(<span class="kw-2">&amp;</span><span class="ident">credentials</span>);
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">BytesMut::with_capacity</span>(<span class="number">6</span> <span class="op">+</span> <span class="ident">encoded</span>.<span class="ident">len</span>());
<span class="ident">value</span>.<span class="ident">put</span>(<span class="kw-2">&amp;</span><span class="string">b&quot;Basic &quot;</span>[..]);
<span class="ident">value</span>.<span class="ident">put</span>(<span class="ident">encoded</span>.<span class="ident">as_bytes</span>());
<span class="comment">// TODO: It would be nice not to allocate new `String` here but write
// directly to `value`
</span><span class="kw">let </span>encoded = base64::encode(<span class="kw-2">&amp;</span>credentials);
<span class="kw">let </span><span class="kw-2">mut </span>value = BytesMut::with_capacity(<span class="number">6 </span>+ encoded.len());
value.put(<span class="kw-2">&amp;</span><span class="string">b&quot;Basic &quot;</span>[..]);
value.put(encoded.as_bytes());
<span class="ident">HeaderValue::from_maybe_shared</span>(<span class="ident">value</span>.<span class="ident">freeze</span>())
HeaderValue::from_maybe_shared(value.freeze())
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_parse_header</span>() {
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==&quot;</span>);
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">Basic::parse</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_parse_header() {
<span class="kw">let </span>value = HeaderValue::from_static(<span class="string">&quot;Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==&quot;</span>);
<span class="kw">let </span>scheme = Basic::parse(<span class="kw-2">&amp;</span>value);
<span class="macro">assert!</span>(<span class="ident">scheme</span>.<span class="ident">is_ok</span>());
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">scheme</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">scheme</span>.<span class="ident">user_id</span>, <span class="string">&quot;Aladdin&quot;</span>);
<span class="macro">assert_eq!</span>(<span class="ident">scheme</span>.<span class="ident">password</span>, <span class="prelude-val">Some</span>(<span class="string">&quot;open sesame&quot;</span>.<span class="ident">into</span>()));
<span class="macro">assert!</span>(scheme.is_ok());
<span class="kw">let </span>scheme = scheme.unwrap();
<span class="macro">assert_eq!</span>(scheme.user_id, <span class="string">&quot;Aladdin&quot;</span>);
<span class="macro">assert_eq!</span>(scheme.password, <span class="prelude-val">Some</span>(<span class="string">&quot;open sesame&quot;</span>.into()));
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_empty_password</span>() {
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;Basic QWxhZGRpbjo=&quot;</span>);
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">Basic::parse</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_empty_password() {
<span class="kw">let </span>value = HeaderValue::from_static(<span class="string">&quot;Basic QWxhZGRpbjo=&quot;</span>);
<span class="kw">let </span>scheme = Basic::parse(<span class="kw-2">&amp;</span>value);
<span class="macro">assert!</span>(<span class="ident">scheme</span>.<span class="ident">is_ok</span>());
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">scheme</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">scheme</span>.<span class="ident">user_id</span>, <span class="string">&quot;Aladdin&quot;</span>);
<span class="macro">assert_eq!</span>(<span class="ident">scheme</span>.<span class="ident">password</span>, <span class="prelude-val">None</span>);
<span class="macro">assert!</span>(scheme.is_ok());
<span class="kw">let </span>scheme = scheme.unwrap();
<span class="macro">assert_eq!</span>(scheme.user_id, <span class="string">&quot;Aladdin&quot;</span>);
<span class="macro">assert_eq!</span>(scheme.password, <span class="prelude-val">None</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_empty_header</span>() {
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;&quot;</span>);
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">Basic::parse</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_empty_header() {
<span class="kw">let </span>value = HeaderValue::from_static(<span class="string">&quot;&quot;</span>);
<span class="kw">let </span>scheme = Basic::parse(<span class="kw-2">&amp;</span>value);
<span class="macro">assert!</span>(<span class="ident">scheme</span>.<span class="ident">is_err</span>());
<span class="macro">assert!</span>(scheme.is_err());
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_wrong_scheme</span>() {
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;THOUSHALLNOTPASS please?&quot;</span>);
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">Basic::parse</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_wrong_scheme() {
<span class="kw">let </span>value = HeaderValue::from_static(<span class="string">&quot;THOUSHALLNOTPASS please?&quot;</span>);
<span class="kw">let </span>scheme = Basic::parse(<span class="kw-2">&amp;</span>value);
<span class="macro">assert!</span>(<span class="ident">scheme</span>.<span class="ident">is_err</span>());
<span class="macro">assert!</span>(scheme.is_err());
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_missing_credentials</span>() {
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;Basic &quot;</span>);
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">Basic::parse</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_missing_credentials() {
<span class="kw">let </span>value = HeaderValue::from_static(<span class="string">&quot;Basic &quot;</span>);
<span class="kw">let </span>scheme = Basic::parse(<span class="kw-2">&amp;</span>value);
<span class="macro">assert!</span>(<span class="ident">scheme</span>.<span class="ident">is_err</span>());
<span class="macro">assert!</span>(scheme.is_err());
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_missing_credentials_colon</span>() {
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;Basic QWxsYWRpbg==&quot;</span>);
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">Basic::parse</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_missing_credentials_colon() {
<span class="kw">let </span>value = HeaderValue::from_static(<span class="string">&quot;Basic QWxsYWRpbg==&quot;</span>);
<span class="kw">let </span>scheme = Basic::parse(<span class="kw-2">&amp;</span>value);
<span class="macro">assert!</span>(<span class="ident">scheme</span>.<span class="ident">is_err</span>());
<span class="macro">assert!</span>(scheme.is_err());
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_into_header_value</span>() {
<span class="kw">let</span> <span class="ident">basic</span> <span class="op">=</span> <span class="ident">Basic</span> {
<span class="ident">user_id</span>: <span class="string">&quot;Aladdin&quot;</span>.<span class="ident">into</span>(),
<span class="ident">password</span>: <span class="prelude-val">Some</span>(<span class="string">&quot;open sesame&quot;</span>.<span class="ident">into</span>()),
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_into_header_value() {
<span class="kw">let </span>basic = Basic {
user_id: <span class="string">&quot;Aladdin&quot;</span>.into(),
password: <span class="prelude-val">Some</span>(<span class="string">&quot;open sesame&quot;</span>.into()),
};
<span class="kw">let</span> <span class="ident">result</span> <span class="op">=</span> <span class="ident">basic</span>.<span class="ident">try_into_value</span>();
<span class="macro">assert!</span>(<span class="ident">result</span>.<span class="ident">is_ok</span>());
<span class="kw">let </span>result = basic.try_into_value();
<span class="macro">assert!</span>(result.is_ok());
<span class="macro">assert_eq!</span>(
<span class="ident">result</span>.<span class="ident">unwrap</span>(),
<span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==&quot;</span>)
result.unwrap(),
HeaderValue::from_static(<span class="string">&quot;Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==&quot;</span>)
);
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -136,143 +136,143 @@
<span id="136">136</span>
<span id="137">137</span>
<span id="138">138</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">borrow::Cow</span>, <span class="ident">fmt</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{borrow::Cow, fmt};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">http::header</span>::{<span class="ident">HeaderValue</span>, <span class="ident">InvalidHeaderValue</span>, <span class="ident">TryIntoHeaderValue</span>},
<span class="ident">web</span>::{<span class="ident">BufMut</span>, <span class="ident">BytesMut</span>},
<span class="kw">use </span>actix_web::{
http::header::{HeaderValue, InvalidHeaderValue, TryIntoHeaderValue},
web::{BufMut, BytesMut},
};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::headers::authorization</span>::{<span class="ident">errors::ParseError</span>, <span class="ident">scheme::Scheme</span>};
<span class="kw">use </span><span class="kw">crate</span>::headers::authorization::{errors::ParseError, scheme::Scheme};
<span class="doccomment">/// Credentials for `Bearer` authentication scheme, defined in [RFC 6750].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Should be used in combination with [`Authorization`](super::Authorization) header.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [RFC 6750]: https://tools.ietf.org/html/rfc6750</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Clone</span>, <span class="ident">Eq</span>, <span class="ident">Ord</span>, <span class="ident">PartialEq</span>, <span class="ident">PartialOrd</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Bearer</span> {
<span class="ident">token</span>: <span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span>,
<span class="doccomment">/// Credentials for `Bearer` authentication scheme, defined in [RFC 6750].
///
/// Should be used in combination with [`Authorization`](super::Authorization) header.
///
/// [RFC 6750]: https://tools.ietf.org/html/rfc6750
</span><span class="attribute">#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
</span><span class="kw">pub struct </span>Bearer {
token: Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;,
}
<span class="kw">impl</span> <span class="ident">Bearer</span> {
<span class="doccomment">/// Creates new `Bearer` credentials with the token provided.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Example</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web_httpauth::headers::authorization::Bearer;</span>
<span class="doccomment">/// let credentials = Bearer::new(&quot;mF_9.B5f-4.1JqM&quot;);</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">new</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>(<span class="ident">token</span>: <span class="ident">T</span>) -&gt; <span class="ident">Bearer</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">impl </span>Bearer {
<span class="doccomment">/// Creates new `Bearer` credentials with the token provided.
///
/// # Example
/// ```
/// # use actix_web_httpauth::headers::authorization::Bearer;
/// let credentials = Bearer::new(&quot;mF_9.B5f-4.1JqM&quot;);
/// ```
</span><span class="kw">pub fn </span>new&lt;T&gt;(token: T) -&gt; Bearer
<span class="kw">where
</span>T: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
{
<span class="ident">Bearer</span> {
<span class="ident">token</span>: <span class="ident">token</span>.<span class="ident">into</span>(),
Bearer {
token: token.into(),
}
}
<span class="doccomment">/// Gets reference to the credentials token.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">token</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="ident">str</span> {
<span class="self">self</span>.<span class="ident">token</span>.<span class="ident">as_ref</span>()
<span class="doccomment">/// Gets reference to the credentials token.
</span><span class="kw">pub fn </span>token(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="self">self</span>.token.as_ref()
}
}
<span class="kw">impl</span> <span class="ident">Scheme</span> <span class="kw">for</span> <span class="ident">Bearer</span> {
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">header</span>: <span class="kw-2">&amp;</span><span class="ident">HeaderValue</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">ParseError</span><span class="op">&gt;</span> {
<span class="comment">// &quot;Bearer *&quot; length</span>
<span class="kw">if</span> <span class="ident">header</span>.<span class="ident">len</span>() <span class="op">&lt;</span> <span class="number">8</span> {
<span class="kw">return</span> <span class="prelude-val">Err</span>(<span class="ident">ParseError::Invalid</span>);
<span class="kw">impl </span>Scheme <span class="kw">for </span>Bearer {
<span class="kw">fn </span>parse(header: <span class="kw-2">&amp;</span>HeaderValue) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, ParseError&gt; {
<span class="comment">// &quot;Bearer *&quot; length
</span><span class="kw">if </span>header.len() &lt; <span class="number">8 </span>{
<span class="kw">return </span><span class="prelude-val">Err</span>(ParseError::Invalid);
}
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">parts</span> <span class="op">=</span> <span class="ident">header</span>.<span class="ident">to_str</span>()<span class="question-mark">?</span>.<span class="ident">splitn</span>(<span class="number">2</span>, <span class="string">&#39; &#39;</span>);
<span class="kw">let </span><span class="kw-2">mut </span>parts = header.to_str()<span class="question-mark">?</span>.splitn(<span class="number">2</span>, <span class="string">&#39; &#39;</span>);
<span class="kw">match</span> <span class="ident">parts</span>.<span class="ident">next</span>() {
<span class="prelude-val">Some</span>(<span class="ident">scheme</span>) <span class="kw">if</span> <span class="ident">scheme</span> <span class="op">==</span> <span class="string">&quot;Bearer&quot;</span> =&gt; {}
<span class="kw">_</span> =&gt; <span class="kw">return</span> <span class="prelude-val">Err</span>(<span class="ident">ParseError::MissingScheme</span>),
<span class="kw">match </span>parts.next() {
<span class="prelude-val">Some</span>(scheme) <span class="kw">if </span>scheme == <span class="string">&quot;Bearer&quot; </span>=&gt; {}
<span class="kw">_ </span>=&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(ParseError::MissingScheme),
}
<span class="kw">let</span> <span class="ident">token</span> <span class="op">=</span> <span class="ident">parts</span>.<span class="ident">next</span>().<span class="ident">ok_or</span>(<span class="ident">ParseError::Invalid</span>)<span class="question-mark">?</span>;
<span class="kw">let </span>token = parts.next().ok_or(ParseError::Invalid)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(<span class="ident">Bearer</span> {
<span class="ident">token</span>: <span class="ident">token</span>.<span class="ident">to_string</span>().<span class="ident">into</span>(),
<span class="prelude-val">Ok</span>(Bearer {
token: token.to_string().into(),
})
}
}
<span class="kw">impl</span> <span class="ident">fmt::Debug</span> <span class="kw">for</span> <span class="ident">Bearer</span> {
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="ident">f</span>.<span class="ident">write_fmt</span>(<span class="macro">format_args!</span>(<span class="string">&quot;Bearer ******&quot;</span>))
<span class="kw">impl </span>fmt::Debug <span class="kw">for </span>Bearer {
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
f.write_fmt(<span class="macro">format_args!</span>(<span class="string">&quot;Bearer ******&quot;</span>))
}
}
<span class="kw">impl</span> <span class="ident">fmt::Display</span> <span class="kw">for</span> <span class="ident">Bearer</span> {
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="ident">f</span>.<span class="ident">write_fmt</span>(<span class="macro">format_args!</span>(<span class="string">&quot;Bearer {}&quot;</span>, <span class="self">self</span>.<span class="ident">token</span>))
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>Bearer {
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
f.write_fmt(<span class="macro">format_args!</span>(<span class="string">&quot;Bearer {}&quot;</span>, <span class="self">self</span>.token))
}
}
<span class="kw">impl</span> <span class="ident">TryIntoHeaderValue</span> <span class="kw">for</span> <span class="ident">Bearer</span> {
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">InvalidHeaderValue</span>;
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>Bearer {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="kw">fn</span> <span class="ident">try_into_value</span>(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HeaderValue</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">buffer</span> <span class="op">=</span> <span class="ident">BytesMut::with_capacity</span>(<span class="number">7</span> <span class="op">+</span> <span class="self">self</span>.<span class="ident">token</span>.<span class="ident">len</span>());
<span class="ident">buffer</span>.<span class="ident">put</span>(<span class="kw-2">&amp;</span><span class="string">b&quot;Bearer &quot;</span>[..]);
<span class="ident">buffer</span>.<span class="ident">extend_from_slice</span>(<span class="self">self</span>.<span class="ident">token</span>.<span class="ident">as_bytes</span>());
<span class="kw">fn </span>try_into_value(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;HeaderValue, <span class="self">Self</span>::Error&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>buffer = BytesMut::with_capacity(<span class="number">7 </span>+ <span class="self">self</span>.token.len());
buffer.put(<span class="kw-2">&amp;</span><span class="string">b&quot;Bearer &quot;</span>[..]);
buffer.extend_from_slice(<span class="self">self</span>.token.as_bytes());
<span class="ident">HeaderValue::from_maybe_shared</span>(<span class="ident">buffer</span>.<span class="ident">freeze</span>())
HeaderValue::from_maybe_shared(buffer.freeze())
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_parse_header</span>() {
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;Bearer mF_9.B5f-4.1JqM&quot;</span>);
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">Bearer::parse</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_parse_header() {
<span class="kw">let </span>value = HeaderValue::from_static(<span class="string">&quot;Bearer mF_9.B5f-4.1JqM&quot;</span>);
<span class="kw">let </span>scheme = Bearer::parse(<span class="kw-2">&amp;</span>value);
<span class="macro">assert!</span>(<span class="ident">scheme</span>.<span class="ident">is_ok</span>());
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">scheme</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">scheme</span>.<span class="ident">token</span>, <span class="string">&quot;mF_9.B5f-4.1JqM&quot;</span>);
<span class="macro">assert!</span>(scheme.is_ok());
<span class="kw">let </span>scheme = scheme.unwrap();
<span class="macro">assert_eq!</span>(scheme.token, <span class="string">&quot;mF_9.B5f-4.1JqM&quot;</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_empty_header</span>() {
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;&quot;</span>);
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">Bearer::parse</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_empty_header() {
<span class="kw">let </span>value = HeaderValue::from_static(<span class="string">&quot;&quot;</span>);
<span class="kw">let </span>scheme = Bearer::parse(<span class="kw-2">&amp;</span>value);
<span class="macro">assert!</span>(<span class="ident">scheme</span>.<span class="ident">is_err</span>());
<span class="macro">assert!</span>(scheme.is_err());
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_wrong_scheme</span>() {
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;OAuthToken foo&quot;</span>);
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">Bearer::parse</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_wrong_scheme() {
<span class="kw">let </span>value = HeaderValue::from_static(<span class="string">&quot;OAuthToken foo&quot;</span>);
<span class="kw">let </span>scheme = Bearer::parse(<span class="kw-2">&amp;</span>value);
<span class="macro">assert!</span>(<span class="ident">scheme</span>.<span class="ident">is_err</span>());
<span class="macro">assert!</span>(scheme.is_err());
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_missing_token</span>() {
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;Bearer &quot;</span>);
<span class="kw">let</span> <span class="ident">scheme</span> <span class="op">=</span> <span class="ident">Bearer::parse</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_missing_token() {
<span class="kw">let </span>value = HeaderValue::from_static(<span class="string">&quot;Bearer &quot;</span>);
<span class="kw">let </span>scheme = Bearer::parse(<span class="kw-2">&amp;</span>value);
<span class="macro">assert!</span>(<span class="ident">scheme</span>.<span class="ident">is_err</span>());
<span class="macro">assert!</span>(scheme.is_err());
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_into_header_value</span>() {
<span class="kw">let</span> <span class="ident">bearer</span> <span class="op">=</span> <span class="ident">Bearer::new</span>(<span class="string">&quot;mF_9.B5f-4.1JqM&quot;</span>);
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_into_header_value() {
<span class="kw">let </span>bearer = Bearer::new(<span class="string">&quot;mF_9.B5f-4.1JqM&quot;</span>);
<span class="kw">let</span> <span class="ident">result</span> <span class="op">=</span> <span class="ident">bearer</span>.<span class="ident">try_into_value</span>();
<span class="macro">assert!</span>(<span class="ident">result</span>.<span class="ident">is_ok</span>());
<span class="kw">let </span>result = bearer.try_into_value();
<span class="macro">assert!</span>(result.is_ok());
<span class="macro">assert_eq!</span>(
<span class="ident">result</span>.<span class="ident">unwrap</span>(),
<span class="ident">HeaderValue::from_static</span>(<span class="string">&quot;Bearer mF_9.B5f-4.1JqM&quot;</span>)
result.unwrap(),
HeaderValue::from_static(<span class="string">&quot;Bearer mF_9.B5f-4.1JqM&quot;</span>)
);
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -12,19 +12,19 @@
<span id="12">12</span>
<span id="13">13</span>
<span id="14">14</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::fmt</span>::{<span class="ident">Debug</span>, <span class="ident">Display</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::fmt::{Debug, Display};
<span class="kw">use</span> <span class="ident">actix_web::http::header</span>::{<span class="ident">HeaderValue</span>, <span class="ident">TryIntoHeaderValue</span>};
<span class="kw">use </span>actix_web::http::header::{HeaderValue, TryIntoHeaderValue};
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">basic</span>;
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">bearer</span>;
<span class="kw">pub mod </span>basic;
<span class="kw">pub mod </span>bearer;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::headers::authorization::errors::ParseError</span>;
<span class="kw">use </span><span class="kw">crate</span>::headers::authorization::errors::ParseError;
<span class="doccomment">/// Authentication scheme for [`Authorization`](super::Authorization) header.</span>
<span class="kw">pub</span> <span class="kw">trait</span> <span class="ident">Scheme</span>: <span class="ident">TryIntoHeaderValue</span> <span class="op">+</span> <span class="ident">Debug</span> <span class="op">+</span> <span class="ident">Display</span> <span class="op">+</span> <span class="ident">Clone</span> <span class="op">+</span> <span class="ident">Send</span> <span class="op">+</span> <span class="ident">Sync</span> {
<span class="doccomment">/// Try to parse an authentication scheme from the `Authorization` header.</span>
<span class="kw">fn</span> <span class="ident">parse</span>(<span class="ident">header</span>: <span class="kw-2">&amp;</span><span class="ident">HeaderValue</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">ParseError</span><span class="op">&gt;</span>;
<span class="doccomment">/// Authentication scheme for [`Authorization`](super::Authorization) header.
</span><span class="kw">pub trait </span>Scheme: TryIntoHeaderValue + Debug + Display + Clone + Send + Sync {
<span class="doccomment">/// Try to parse an authentication scheme from the `Authorization` header.
</span><span class="kw">fn </span>parse(header: <span class="kw-2">&amp;</span>HeaderValue) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, ParseError&gt;;
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -2,9 +2,9 @@
<span id="2">2</span>
<span id="3">3</span>
<span id="4">4</span>
</pre><pre class="rust"><code><span class="doccomment">//! Typed HTTP headers.</span>
</pre><pre class="rust"><code><span class="doccomment">//! Typed HTTP headers.
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">authorization</span>;
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">www_authenticate</span>;
</span><span class="kw">pub mod </span>authorization;
<span class="kw">pub mod </span>www_authenticate;
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -134,141 +134,141 @@
<span id="134">134</span>
<span id="135">135</span>
<span id="136">136</span>
</pre><pre class="rust"><code><span class="doccomment">//! Challenge for the &quot;Basic&quot; HTTP Authentication Scheme.</span>
</pre><pre class="rust"><code><span class="doccomment">//! Challenge for the &quot;Basic&quot; HTTP Authentication Scheme.
<span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">borrow::Cow</span>, <span class="ident">fmt</span>, <span class="ident">str</span>};
</span><span class="kw">use </span>std::{borrow::Cow, fmt, str};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">http::header</span>::{<span class="ident">HeaderValue</span>, <span class="ident">InvalidHeaderValue</span>, <span class="ident">TryIntoHeaderValue</span>},
<span class="ident">web</span>::{<span class="ident">BufMut</span>, <span class="ident">Bytes</span>, <span class="ident">BytesMut</span>},
<span class="kw">use </span>actix_web::{
http::header::{HeaderValue, InvalidHeaderValue, TryIntoHeaderValue},
web::{BufMut, Bytes, BytesMut},
};
<span class="kw">use</span> <span class="ident"><span class="kw">super</span>::Challenge</span>;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::utils</span>;
<span class="kw">use </span><span class="kw">super</span>::Challenge;
<span class="kw">use </span><span class="kw">crate</span>::utils;
<span class="doccomment">/// Challenge for [`WWW-Authenticate`] header with HTTP Basic auth scheme,</span>
<span class="doccomment">/// described in [RFC 7617](https://tools.ietf.org/html/rfc7617)</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer};</span>
<span class="doccomment">/// use actix_web_httpauth::headers::www_authenticate::basic::Basic;</span>
<span class="doccomment">/// use actix_web_httpauth::headers::www_authenticate::WwwAuthenticate;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// fn index(_req: HttpRequest) -&gt; HttpResponse {</span>
<span class="doccomment">/// let challenge = Basic::with_realm(&quot;Restricted area&quot;);</span>
<span class="doccomment">///</span>
<span class="doccomment">/// HttpResponse::Unauthorized()</span>
<span class="doccomment">/// .insert_header(WwwAuthenticate(challenge))</span>
<span class="doccomment">/// .finish()</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`WWW-Authenticate`]: ../struct.WwwAuthenticate.html</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Eq</span>, <span class="ident">PartialEq</span>, <span class="ident">Ord</span>, <span class="ident">PartialOrd</span>, <span class="ident">Hash</span>, <span class="ident">Debug</span>, <span class="ident">Default</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Basic</span> {
<span class="comment">// &quot;realm&quot; parameter is optional now: https://tools.ietf.org/html/rfc7235#appendix-A</span>
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">realm</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="doccomment">/// Challenge for [`WWW-Authenticate`] header with HTTP Basic auth scheme,
/// described in [RFC 7617](https://tools.ietf.org/html/rfc7617)
///
/// # Examples
/// ```
/// # use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer};
/// use actix_web_httpauth::headers::www_authenticate::basic::Basic;
/// use actix_web_httpauth::headers::www_authenticate::WwwAuthenticate;
///
/// fn index(_req: HttpRequest) -&gt; HttpResponse {
/// let challenge = Basic::with_realm(&quot;Restricted area&quot;);
///
/// HttpResponse::Unauthorized()
/// .insert_header(WwwAuthenticate(challenge))
/// .finish()
/// }
/// ```
///
/// [`WWW-Authenticate`]: ../struct.WwwAuthenticate.html
</span><span class="attribute">#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Clone)]
</span><span class="kw">pub struct </span>Basic {
<span class="comment">// &quot;realm&quot; parameter is optional now: https://tools.ietf.org/html/rfc7235#appendix-A
</span><span class="kw">pub</span>(<span class="kw">crate</span>) realm: <span class="prelude-ty">Option</span>&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
}
<span class="kw">impl</span> <span class="ident">Basic</span> {
<span class="doccomment">/// Creates new `Basic` challenge with an empty `realm` field.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web_httpauth::headers::www_authenticate::basic::Basic;</span>
<span class="doccomment">/// let challenge = Basic::new();</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">new</span>() -&gt; <span class="ident">Basic</span> {
<span class="ident">Default::default</span>()
<span class="kw">impl </span>Basic {
<span class="doccomment">/// Creates new `Basic` challenge with an empty `realm` field.
///
/// # Examples
/// ```
/// # use actix_web_httpauth::headers::www_authenticate::basic::Basic;
/// let challenge = Basic::new();
/// ```
</span><span class="kw">pub fn </span>new() -&gt; Basic {
Default::default()
}
<span class="doccomment">/// Creates new `Basic` challenge from the provided `realm` field value.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web_httpauth::headers::www_authenticate::basic::Basic;</span>
<span class="doccomment">/// let challenge = Basic::with_realm(&quot;Restricted area&quot;);</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web_httpauth::headers::www_authenticate::basic::Basic;</span>
<span class="doccomment">/// let my_realm = &quot;Earth realm&quot;.to_string();</span>
<span class="doccomment">/// let challenge = Basic::with_realm(my_realm);</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">with_realm</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>(<span class="ident">value</span>: <span class="ident">T</span>) -&gt; <span class="ident">Basic</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="doccomment">/// Creates new `Basic` challenge from the provided `realm` field value.
///
/// # Examples
///
/// ```
/// # use actix_web_httpauth::headers::www_authenticate::basic::Basic;
/// let challenge = Basic::with_realm(&quot;Restricted area&quot;);
/// ```
///
/// ```
/// # use actix_web_httpauth::headers::www_authenticate::basic::Basic;
/// let my_realm = &quot;Earth realm&quot;.to_string();
/// let challenge = Basic::with_realm(my_realm);
/// ```
</span><span class="kw">pub fn </span>with_realm&lt;T&gt;(value: T) -&gt; Basic
<span class="kw">where
</span>T: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
{
<span class="ident">Basic</span> {
<span class="ident">realm</span>: <span class="prelude-val">Some</span>(<span class="ident">value</span>.<span class="ident">into</span>()),
Basic {
realm: <span class="prelude-val">Some</span>(value.into()),
}
}
}
<span class="attribute">#[<span class="ident">doc</span>(<span class="ident">hidden</span>)]</span>
<span class="kw">impl</span> <span class="ident">Challenge</span> <span class="kw">for</span> <span class="ident">Basic</span> {
<span class="kw">fn</span> <span class="ident">to_bytes</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Bytes</span> {
<span class="comment">// 5 is for `&quot;Basic&quot;`, 9 is for `&quot;realm=\&quot;\&quot;&quot;`</span>
<span class="kw">let</span> <span class="ident">length</span> <span class="op">=</span> <span class="number">5</span> <span class="op">+</span> <span class="self">self</span>.<span class="ident">realm</span>.<span class="ident">as_ref</span>().<span class="ident">map_or</span>(<span class="number">0</span>, <span class="op">|</span><span class="ident">realm</span><span class="op">|</span> <span class="ident">realm</span>.<span class="ident">len</span>() <span class="op">+</span> <span class="number">9</span>);
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">buffer</span> <span class="op">=</span> <span class="ident">BytesMut::with_capacity</span>(<span class="ident">length</span>);
<span class="ident">buffer</span>.<span class="ident">put</span>(<span class="kw-2">&amp;</span><span class="string">b&quot;Basic&quot;</span>[..]);
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="ident">realm</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">realm</span> {
<span class="ident">buffer</span>.<span class="ident">put</span>(<span class="kw-2">&amp;</span><span class="string">b&quot; realm=\&quot;&quot;</span>[..]);
<span class="ident">utils::put_quoted</span>(<span class="kw-2">&amp;mut</span> <span class="ident">buffer</span>, <span class="ident">realm</span>);
<span class="ident">buffer</span>.<span class="ident">put_u8</span>(<span class="string">b&#39;&quot;&#39;</span>);
<span class="attribute">#[doc(hidden)]
</span><span class="kw">impl </span>Challenge <span class="kw">for </span>Basic {
<span class="kw">fn </span>to_bytes(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Bytes {
<span class="comment">// 5 is for `&quot;Basic&quot;`, 9 is for `&quot;realm=\&quot;\&quot;&quot;`
</span><span class="kw">let </span>length = <span class="number">5 </span>+ <span class="self">self</span>.realm.as_ref().map_or(<span class="number">0</span>, |realm| realm.len() + <span class="number">9</span>);
<span class="kw">let </span><span class="kw-2">mut </span>buffer = BytesMut::with_capacity(length);
buffer.put(<span class="kw-2">&amp;</span><span class="string">b&quot;Basic&quot;</span>[..]);
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>realm) = <span class="self">self</span>.realm {
buffer.put(<span class="kw-2">&amp;</span><span class="string">b&quot; realm=\&quot;&quot;</span>[..]);
utils::put_quoted(<span class="kw-2">&amp;mut </span>buffer, realm);
buffer.put_u8(<span class="string">b&#39;&quot;&#39;</span>);
}
<span class="ident">buffer</span>.<span class="ident">freeze</span>()
buffer.freeze()
}
}
<span class="kw">impl</span> <span class="ident">fmt::Display</span> <span class="kw">for</span> <span class="ident">Basic</span> {
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">fmt::Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">bytes</span> <span class="op">=</span> <span class="self">self</span>.<span class="ident">to_bytes</span>();
<span class="kw">let</span> <span class="ident">repr</span> <span class="op">=</span> <span class="ident">str::from_utf8</span>(<span class="kw-2">&amp;</span><span class="ident">bytes</span>)
<span class="comment">// Should not happen since challenges are crafted manually</span>
<span class="comment">// from a `&amp;&#39;static str` or `String`</span>
.<span class="ident">map_err</span>(<span class="op">|</span><span class="kw">_</span><span class="op">|</span> <span class="ident">fmt::Error</span>)<span class="question-mark">?</span>;
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>Basic {
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;(), fmt::Error&gt; {
<span class="kw">let </span>bytes = <span class="self">self</span>.to_bytes();
<span class="kw">let </span>repr = str::from_utf8(<span class="kw-2">&amp;</span>bytes)
<span class="comment">// Should not happen since challenges are crafted manually
// from a `&amp;&#39;static str` or `String`
</span>.map_err(|<span class="kw">_</span>| fmt::Error)<span class="question-mark">?</span>;
<span class="ident">f</span>.<span class="ident">write_str</span>(<span class="ident">repr</span>)
f.write_str(repr)
}
}
<span class="kw">impl</span> <span class="ident">TryIntoHeaderValue</span> <span class="kw">for</span> <span class="ident">Basic</span> {
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">InvalidHeaderValue</span>;
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>Basic {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="kw">fn</span> <span class="ident">try_into_value</span>(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HeaderValue</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span> {
<span class="ident">HeaderValue::from_maybe_shared</span>(<span class="self">self</span>.<span class="ident">to_bytes</span>())
<span class="kw">fn </span>try_into_value(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;HeaderValue, <span class="self">Self</span>::Error&gt; {
HeaderValue::from_maybe_shared(<span class="self">self</span>.to_bytes())
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_plain_into_header_value</span>() {
<span class="kw">let</span> <span class="ident">challenge</span> <span class="op">=</span> <span class="ident">Basic</span> { <span class="ident">realm</span>: <span class="prelude-val">None</span> };
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_plain_into_header_value() {
<span class="kw">let </span>challenge = Basic { realm: <span class="prelude-val">None </span>};
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">challenge</span>.<span class="ident">try_into_value</span>();
<span class="macro">assert!</span>(<span class="ident">value</span>.<span class="ident">is_ok</span>());
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">value</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">value</span>, <span class="string">&quot;Basic&quot;</span>);
<span class="kw">let </span>value = challenge.try_into_value();
<span class="macro">assert!</span>(value.is_ok());
<span class="kw">let </span>value = value.unwrap();
<span class="macro">assert_eq!</span>(value, <span class="string">&quot;Basic&quot;</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_with_realm_into_header_value</span>() {
<span class="kw">let</span> <span class="ident">challenge</span> <span class="op">=</span> <span class="ident">Basic</span> {
<span class="ident">realm</span>: <span class="prelude-val">Some</span>(<span class="string">&quot;Restricted area&quot;</span>.<span class="ident">into</span>()),
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_with_realm_into_header_value() {
<span class="kw">let </span>challenge = Basic {
realm: <span class="prelude-val">Some</span>(<span class="string">&quot;Restricted area&quot;</span>.into()),
};
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">challenge</span>.<span class="ident">try_into_value</span>();
<span class="macro">assert!</span>(<span class="ident">value</span>.<span class="ident">is_ok</span>());
<span class="kw">let</span> <span class="ident">value</span> <span class="op">=</span> <span class="ident">value</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">value</span>, <span class="string">&quot;Basic realm=\&quot;Restricted area\&quot;&quot;</span>);
<span class="kw">let </span>value = challenge.try_into_value();
<span class="macro">assert!</span>(value.is_ok());
<span class="kw">let </span>value = value.unwrap();
<span class="macro">assert_eq!</span>(value, <span class="string">&quot;Basic realm=\&quot;Restricted area\&quot;&quot;</span>);
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -69,76 +69,76 @@
<span id="69">69</span>
<span id="70">70</span>
<span id="71">71</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::borrow::Cow</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::borrow::Cow;
<span class="kw">use</span> <span class="kw">super</span>::{<span class="ident">Bearer</span>, <span class="ident">Error</span>};
<span class="kw">use super</span>::{Bearer, Error};
<span class="doccomment">/// Builder for the [`Bearer`] challenge.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// It is up to implementor to fill all required fields, neither this `Builder` nor [`Bearer`]</span>
<span class="doccomment">/// provide any validation.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Default</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">BearerBuilder</span>(<span class="ident">Bearer</span>);
<span class="doccomment">/// Builder for the [`Bearer`] challenge.
///
/// It is up to implementor to fill all required fields, neither this `Builder` nor [`Bearer`]
/// provide any validation.
</span><span class="attribute">#[derive(Debug, Default)]
</span><span class="kw">pub struct </span>BearerBuilder(Bearer);
<span class="kw">impl</span> <span class="ident">BearerBuilder</span> {
<span class="doccomment">/// Provides the `scope` attribute, as defined in [RFC 6749 §3.3].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [RFC 6749 §3.3]: https://tools.ietf.org/html/rfc6749#section-3.3</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">scope</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">value</span>: <span class="ident">T</span>) -&gt; <span class="self">Self</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">impl </span>BearerBuilder {
<span class="doccomment">/// Provides the `scope` attribute, as defined in [RFC 6749 §3.3].
///
/// [RFC 6749 §3.3]: https://tools.ietf.org/html/rfc6749#section-3.3
</span><span class="kw">pub fn </span>scope&lt;T&gt;(<span class="kw-2">mut </span><span class="self">self</span>, value: T) -&gt; <span class="self">Self
</span><span class="kw">where
</span>T: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
{
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">scope</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">value</span>.<span class="ident">into</span>());
<span class="self">self</span>
}
<span class="self">self</span>.<span class="number">0</span>.scope = <span class="prelude-val">Some</span>(value.into());
<span class="self">self
</span>}
<span class="doccomment">/// Provides the `realm` attribute, as defined in [RFC 2617].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [RFC 2617]: https://tools.ietf.org/html/rfc2617</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">realm</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">value</span>: <span class="ident">T</span>) -&gt; <span class="self">Self</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="doccomment">/// Provides the `realm` attribute, as defined in [RFC 2617].
///
/// [RFC 2617]: https://tools.ietf.org/html/rfc2617
</span><span class="kw">pub fn </span>realm&lt;T&gt;(<span class="kw-2">mut </span><span class="self">self</span>, value: T) -&gt; <span class="self">Self
</span><span class="kw">where
</span>T: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
{
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">realm</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">value</span>.<span class="ident">into</span>());
<span class="self">self</span>
}
<span class="self">self</span>.<span class="number">0</span>.realm = <span class="prelude-val">Some</span>(value.into());
<span class="self">self
</span>}
<span class="doccomment">/// Provides the `error` attribute, as defined in [RFC 6750, Section 3.1].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [RFC 6750 §3.1]: https://tools.ietf.org/html/rfc6750#section-3.1</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">error</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">value</span>: <span class="ident">Error</span>) -&gt; <span class="self">Self</span> {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">error</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">value</span>);
<span class="self">self</span>
}
<span class="doccomment">/// Provides the `error` attribute, as defined in [RFC 6750, Section 3.1].
///
/// [RFC 6750 §3.1]: https://tools.ietf.org/html/rfc6750#section-3.1
</span><span class="kw">pub fn </span>error(<span class="kw-2">mut </span><span class="self">self</span>, value: Error) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.<span class="number">0</span>.error = <span class="prelude-val">Some</span>(value);
<span class="self">self
</span>}
<span class="doccomment">/// Provides the `error_description` attribute, as defined in [RFC 6750, Section 3].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [RFC 6750 §3]: https://tools.ietf.org/html/rfc6750#section-3</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">error_description</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">value</span>: <span class="ident">T</span>) -&gt; <span class="self">Self</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="doccomment">/// Provides the `error_description` attribute, as defined in [RFC 6750, Section 3].
///
/// [RFC 6750 §3]: https://tools.ietf.org/html/rfc6750#section-3
</span><span class="kw">pub fn </span>error_description&lt;T&gt;(<span class="kw-2">mut </span><span class="self">self</span>, value: T) -&gt; <span class="self">Self
</span><span class="kw">where
</span>T: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
{
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">error_description</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">value</span>.<span class="ident">into</span>());
<span class="self">self</span>
}
<span class="self">self</span>.<span class="number">0</span>.error_description = <span class="prelude-val">Some</span>(value.into());
<span class="self">self
</span>}
<span class="doccomment">/// Provides the `error_uri` attribute, as defined in [RFC 6750 §3].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// It is up to implementor to provide properly-formed absolute URI.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [RFC 6750 §3](https://tools.ietf.org/html/rfc6750#section-3)</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">error_uri</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>(<span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">value</span>: <span class="ident">T</span>) -&gt; <span class="self">Self</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="doccomment">/// Provides the `error_uri` attribute, as defined in [RFC 6750 §3].
///
/// It is up to implementor to provide properly-formed absolute URI.
///
/// [RFC 6750 §3](https://tools.ietf.org/html/rfc6750#section-3)
</span><span class="kw">pub fn </span>error_uri&lt;T&gt;(<span class="kw-2">mut </span><span class="self">self</span>, value: T) -&gt; <span class="self">Self
</span><span class="kw">where
</span>T: Into&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
{
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">error_uri</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">value</span>.<span class="ident">into</span>());
<span class="self">self</span>
}
<span class="self">self</span>.<span class="number">0</span>.error_uri = <span class="prelude-val">Some</span>(value.into());
<span class="self">self
</span>}
<span class="doccomment">/// Consumes the builder and returns built `Bearer` instance.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">finish</span>(<span class="self">self</span>) -&gt; <span class="ident">Bearer</span> {
<span class="self">self</span>.<span class="number">0</span>
}
<span class="doccomment">/// Consumes the builder and returns built `Bearer` instance.
</span><span class="kw">pub fn </span>finish(<span class="self">self</span>) -&gt; Bearer {
<span class="self">self</span>.<span class="number">0
</span>}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -140,147 +140,147 @@
<span id="140">140</span>
<span id="141">141</span>
<span id="142">142</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std</span>::{<span class="ident">borrow::Cow</span>, <span class="ident">fmt</span>, <span class="ident">str</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::{borrow::Cow, fmt, str};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">http::header</span>::{<span class="ident">HeaderValue</span>, <span class="ident">InvalidHeaderValue</span>, <span class="ident">TryIntoHeaderValue</span>},
<span class="ident">web</span>::{<span class="ident">BufMut</span>, <span class="ident">Bytes</span>, <span class="ident">BytesMut</span>},
<span class="kw">use </span>actix_web::{
http::header::{HeaderValue, InvalidHeaderValue, TryIntoHeaderValue},
web::{BufMut, Bytes, BytesMut},
};
<span class="kw">use</span> <span class="ident"><span class="kw">super</span>::<span class="kw">super</span>::Challenge</span>;
<span class="kw">use</span> <span class="kw">super</span>::{<span class="ident">BearerBuilder</span>, <span class="ident">Error</span>};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::utils</span>;
<span class="kw">use </span><span class="kw">super</span>::<span class="kw">super</span>::Challenge;
<span class="kw">use super</span>::{BearerBuilder, Error};
<span class="kw">use </span><span class="kw">crate</span>::utils;
<span class="doccomment">/// Challenge for [`WWW-Authenticate`] header with HTTP Bearer auth scheme, described in [RFC 6750].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer};</span>
<span class="doccomment">/// use actix_web_httpauth::headers::www_authenticate::bearer::{</span>
<span class="doccomment">/// Bearer, Error,</span>
<span class="doccomment">/// };</span>
<span class="doccomment">/// use actix_web_httpauth::headers::www_authenticate::WwwAuthenticate;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// fn index(_req: HttpRequest) -&gt; HttpResponse {</span>
<span class="doccomment">/// let challenge = Bearer::build()</span>
<span class="doccomment">/// .realm(&quot;example&quot;)</span>
<span class="doccomment">/// .scope(&quot;openid profile email&quot;)</span>
<span class="doccomment">/// .error(Error::InvalidToken)</span>
<span class="doccomment">/// .error_description(&quot;The access token expired&quot;)</span>
<span class="doccomment">/// .error_uri(&quot;http://example.org&quot;)</span>
<span class="doccomment">/// .finish();</span>
<span class="doccomment">///</span>
<span class="doccomment">/// HttpResponse::Unauthorized()</span>
<span class="doccomment">/// .insert_header(WwwAuthenticate(challenge))</span>
<span class="doccomment">/// .finish()</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [`WWW-Authenticate`]: crate::headers::www_authenticate::WwwAuthenticate</span>
<span class="doccomment">/// [RFC 6750]: https://tools.ietf.org/html/rfc6750#section-3</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Default</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">PartialOrd</span>, <span class="ident">Ord</span>, <span class="ident">Hash</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Bearer</span> {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">scope</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">realm</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">error</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Error</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">error_description</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="ident">error_uri</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">Cow</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="ident">str</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="doccomment">/// Challenge for [`WWW-Authenticate`] header with HTTP Bearer auth scheme, described in [RFC 6750].
///
/// # Examples
/// ```
/// # use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer};
/// use actix_web_httpauth::headers::www_authenticate::bearer::{
/// Bearer, Error,
/// };
/// use actix_web_httpauth::headers::www_authenticate::WwwAuthenticate;
///
/// fn index(_req: HttpRequest) -&gt; HttpResponse {
/// let challenge = Bearer::build()
/// .realm(&quot;example&quot;)
/// .scope(&quot;openid profile email&quot;)
/// .error(Error::InvalidToken)
/// .error_description(&quot;The access token expired&quot;)
/// .error_uri(&quot;http://example.org&quot;)
/// .finish();
///
/// HttpResponse::Unauthorized()
/// .insert_header(WwwAuthenticate(challenge))
/// .finish()
/// }
/// ```
///
/// [`WWW-Authenticate`]: crate::headers::www_authenticate::WwwAuthenticate
/// [RFC 6750]: https://tools.ietf.org/html/rfc6750#section-3
</span><span class="attribute">#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
</span><span class="kw">pub struct </span>Bearer {
<span class="kw">pub</span>(<span class="kw">crate</span>) scope: <span class="prelude-ty">Option</span>&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) realm: <span class="prelude-ty">Option</span>&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) error: <span class="prelude-ty">Option</span>&lt;Error&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) error_description: <span class="prelude-ty">Option</span>&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) error_uri: <span class="prelude-ty">Option</span>&lt;Cow&lt;<span class="lifetime">&#39;static</span>, str&gt;&gt;,
}
<span class="kw">impl</span> <span class="ident">Bearer</span> {
<span class="doccomment">/// Creates the builder for `Bearer` challenge.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web_httpauth::headers::www_authenticate::bearer::{Bearer};</span>
<span class="doccomment">/// let challenge = Bearer::build()</span>
<span class="doccomment">/// .realm(&quot;Restricted area&quot;)</span>
<span class="doccomment">/// .scope(&quot;openid profile email&quot;)</span>
<span class="doccomment">/// .finish();</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">build</span>() -&gt; <span class="ident">BearerBuilder</span> {
<span class="ident">BearerBuilder::default</span>()
<span class="kw">impl </span>Bearer {
<span class="doccomment">/// Creates the builder for `Bearer` challenge.
///
/// # Examples
/// ```
/// # use actix_web_httpauth::headers::www_authenticate::bearer::{Bearer};
/// let challenge = Bearer::build()
/// .realm(&quot;Restricted area&quot;)
/// .scope(&quot;openid profile email&quot;)
/// .finish();
/// ```
</span><span class="kw">pub fn </span>build() -&gt; BearerBuilder {
BearerBuilder::default()
}
}
<span class="attribute">#[<span class="ident">doc</span>(<span class="ident">hidden</span>)]</span>
<span class="kw">impl</span> <span class="ident">Challenge</span> <span class="kw">for</span> <span class="ident">Bearer</span> {
<span class="kw">fn</span> <span class="ident">to_bytes</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Bytes</span> {
<span class="kw">let</span> <span class="ident">desc_uri_required</span> <span class="op">=</span> <span class="self">self</span>
.<span class="ident">error_description</span>
.<span class="ident">as_ref</span>()
.<span class="ident">map_or</span>(<span class="number">0</span>, <span class="op">|</span><span class="ident">desc</span><span class="op">|</span> <span class="ident">desc</span>.<span class="ident">len</span>() <span class="op">+</span> <span class="number">20</span>)
<span class="op">+</span> <span class="self">self</span>.<span class="ident">error_uri</span>.<span class="ident">as_ref</span>().<span class="ident">map_or</span>(<span class="number">0</span>, <span class="op">|</span><span class="ident">url</span><span class="op">|</span> <span class="ident">url</span>.<span class="ident">len</span>() <span class="op">+</span> <span class="number">12</span>);
<span class="attribute">#[doc(hidden)]
</span><span class="kw">impl </span>Challenge <span class="kw">for </span>Bearer {
<span class="kw">fn </span>to_bytes(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Bytes {
<span class="kw">let </span>desc_uri_required = <span class="self">self
</span>.error_description
.as_ref()
.map_or(<span class="number">0</span>, |desc| desc.len() + <span class="number">20</span>)
+ <span class="self">self</span>.error_uri.as_ref().map_or(<span class="number">0</span>, |url| url.len() + <span class="number">12</span>);
<span class="kw">let</span> <span class="ident">capacity</span> <span class="op">=</span> <span class="number">6</span>
<span class="op">+</span> <span class="self">self</span>.<span class="ident">realm</span>.<span class="ident">as_ref</span>().<span class="ident">map_or</span>(<span class="number">0</span>, <span class="op">|</span><span class="ident">realm</span><span class="op">|</span> <span class="ident">realm</span>.<span class="ident">len</span>() <span class="op">+</span> <span class="number">9</span>)
<span class="op">+</span> <span class="self">self</span>.<span class="ident">scope</span>.<span class="ident">as_ref</span>().<span class="ident">map_or</span>(<span class="number">0</span>, <span class="op">|</span><span class="ident">scope</span><span class="op">|</span> <span class="ident">scope</span>.<span class="ident">len</span>() <span class="op">+</span> <span class="number">9</span>)
<span class="op">+</span> <span class="ident">desc_uri_required</span>;
<span class="kw">let </span>capacity = <span class="number">6
</span>+ <span class="self">self</span>.realm.as_ref().map_or(<span class="number">0</span>, |realm| realm.len() + <span class="number">9</span>)
+ <span class="self">self</span>.scope.as_ref().map_or(<span class="number">0</span>, |scope| scope.len() + <span class="number">9</span>)
+ desc_uri_required;
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">buffer</span> <span class="op">=</span> <span class="ident">BytesMut::with_capacity</span>(<span class="ident">capacity</span>);
<span class="ident">buffer</span>.<span class="ident">put</span>(<span class="kw-2">&amp;</span><span class="string">b&quot;Bearer&quot;</span>[..]);
<span class="kw">let </span><span class="kw-2">mut </span>buffer = BytesMut::with_capacity(capacity);
buffer.put(<span class="kw-2">&amp;</span><span class="string">b&quot;Bearer&quot;</span>[..]);
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="ident">realm</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">realm</span> {
<span class="ident">buffer</span>.<span class="ident">put</span>(<span class="kw-2">&amp;</span><span class="string">b&quot; realm=\&quot;&quot;</span>[..]);
<span class="ident">utils::put_quoted</span>(<span class="kw-2">&amp;mut</span> <span class="ident">buffer</span>, <span class="ident">realm</span>);
<span class="ident">buffer</span>.<span class="ident">put_u8</span>(<span class="string">b&#39;&quot;&#39;</span>);
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>realm) = <span class="self">self</span>.realm {
buffer.put(<span class="kw-2">&amp;</span><span class="string">b&quot; realm=\&quot;&quot;</span>[..]);
utils::put_quoted(<span class="kw-2">&amp;mut </span>buffer, realm);
buffer.put_u8(<span class="string">b&#39;&quot;&#39;</span>);
}
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="ident">scope</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">scope</span> {
<span class="ident">buffer</span>.<span class="ident">put</span>(<span class="kw-2">&amp;</span><span class="string">b&quot; scope=\&quot;&quot;</span>[..]);
<span class="ident">utils::put_quoted</span>(<span class="kw-2">&amp;mut</span> <span class="ident">buffer</span>, <span class="ident">scope</span>);
<span class="ident">buffer</span>.<span class="ident">put_u8</span>(<span class="string">b&#39;&quot;&#39;</span>);
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>scope) = <span class="self">self</span>.scope {
buffer.put(<span class="kw-2">&amp;</span><span class="string">b&quot; scope=\&quot;&quot;</span>[..]);
utils::put_quoted(<span class="kw-2">&amp;mut </span>buffer, scope);
buffer.put_u8(<span class="string">b&#39;&quot;&#39;</span>);
}
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="ident">error</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">error</span> {
<span class="kw">let</span> <span class="ident">error_repr</span> <span class="op">=</span> <span class="ident">error</span>.<span class="ident">as_str</span>();
<span class="kw">let</span> <span class="ident">remaining</span> <span class="op">=</span> <span class="ident">buffer</span>.<span class="ident">remaining_mut</span>();
<span class="kw">let</span> <span class="ident">required</span> <span class="op">=</span> <span class="ident">desc_uri_required</span> <span class="op">+</span> <span class="ident">error_repr</span>.<span class="ident">len</span>() <span class="op">+</span> <span class="number">9</span>; <span class="comment">// 9 is for `&quot; error=\&quot;\&quot;&quot;`</span>
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>error) = <span class="self">self</span>.error {
<span class="kw">let </span>error_repr = error.as_str();
<span class="kw">let </span>remaining = buffer.remaining_mut();
<span class="kw">let </span>required = desc_uri_required + error_repr.len() + <span class="number">9</span>; <span class="comment">// 9 is for `&quot; error=\&quot;\&quot;&quot;`
<span class="kw">if</span> <span class="ident">remaining</span> <span class="op">&lt;</span> <span class="ident">required</span> {
<span class="ident">buffer</span>.<span class="ident">reserve</span>(<span class="ident">required</span>);
</span><span class="kw">if </span>remaining &lt; required {
buffer.reserve(required);
}
<span class="ident">buffer</span>.<span class="ident">put</span>(<span class="kw-2">&amp;</span><span class="string">b&quot; error=\&quot;&quot;</span>[..]);
<span class="ident">utils::put_quoted</span>(<span class="kw-2">&amp;mut</span> <span class="ident">buffer</span>, <span class="ident">error_repr</span>);
<span class="ident">buffer</span>.<span class="ident">put_u8</span>(<span class="string">b&#39;&quot;&#39;</span>)
buffer.put(<span class="kw-2">&amp;</span><span class="string">b&quot; error=\&quot;&quot;</span>[..]);
utils::put_quoted(<span class="kw-2">&amp;mut </span>buffer, error_repr);
buffer.put_u8(<span class="string">b&#39;&quot;&#39;</span>)
}
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="ident">error_description</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">error_description</span> {
<span class="ident">buffer</span>.<span class="ident">put</span>(<span class="kw-2">&amp;</span><span class="string">b&quot; error_description=\&quot;&quot;</span>[..]);
<span class="ident">utils::put_quoted</span>(<span class="kw-2">&amp;mut</span> <span class="ident">buffer</span>, <span class="ident">error_description</span>);
<span class="ident">buffer</span>.<span class="ident">put_u8</span>(<span class="string">b&#39;&quot;&#39;</span>);
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>error_description) = <span class="self">self</span>.error_description {
buffer.put(<span class="kw-2">&amp;</span><span class="string">b&quot; error_description=\&quot;&quot;</span>[..]);
utils::put_quoted(<span class="kw-2">&amp;mut </span>buffer, error_description);
buffer.put_u8(<span class="string">b&#39;&quot;&#39;</span>);
}
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="kw-2">ref</span> <span class="ident">error_uri</span>) <span class="op">=</span> <span class="self">self</span>.<span class="ident">error_uri</span> {
<span class="ident">buffer</span>.<span class="ident">put</span>(<span class="kw-2">&amp;</span><span class="string">b&quot; error_uri=\&quot;&quot;</span>[..]);
<span class="ident">utils::put_quoted</span>(<span class="kw-2">&amp;mut</span> <span class="ident">buffer</span>, <span class="ident">error_uri</span>);
<span class="ident">buffer</span>.<span class="ident">put_u8</span>(<span class="string">b&#39;&quot;&#39;</span>);
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>error_uri) = <span class="self">self</span>.error_uri {
buffer.put(<span class="kw-2">&amp;</span><span class="string">b&quot; error_uri=\&quot;&quot;</span>[..]);
utils::put_quoted(<span class="kw-2">&amp;mut </span>buffer, error_uri);
buffer.put_u8(<span class="string">b&#39;&quot;&#39;</span>);
}
<span class="ident">buffer</span>.<span class="ident">freeze</span>()
buffer.freeze()
}
}
<span class="kw">impl</span> <span class="ident">fmt::Display</span> <span class="kw">for</span> <span class="ident">Bearer</span> {
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">fmt::Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="ident">bytes</span> <span class="op">=</span> <span class="self">self</span>.<span class="ident">to_bytes</span>();
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>Bearer {
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;(), fmt::Error&gt; {
<span class="kw">let </span>bytes = <span class="self">self</span>.to_bytes();
<span class="kw">let</span> <span class="ident">repr</span> <span class="op">=</span> <span class="ident">str::from_utf8</span>(<span class="kw-2">&amp;</span><span class="ident">bytes</span>)
<span class="comment">// Should not happen since challenges are crafted manually</span>
<span class="comment">// from `&amp;&#39;static str`&#39;s and Strings</span>
.<span class="ident">map_err</span>(<span class="op">|</span><span class="kw">_</span><span class="op">|</span> <span class="ident">fmt::Error</span>)<span class="question-mark">?</span>;
<span class="kw">let </span>repr = str::from_utf8(<span class="kw-2">&amp;</span>bytes)
<span class="comment">// Should not happen since challenges are crafted manually
// from `&amp;&#39;static str`&#39;s and Strings
</span>.map_err(|<span class="kw">_</span>| fmt::Error)<span class="question-mark">?</span>;
<span class="ident">f</span>.<span class="ident">write_str</span>(<span class="ident">repr</span>)
f.write_str(repr)
}
}
<span class="kw">impl</span> <span class="ident">TryIntoHeaderValue</span> <span class="kw">for</span> <span class="ident">Bearer</span> {
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">InvalidHeaderValue</span>;
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>Bearer {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="kw">fn</span> <span class="ident">try_into_value</span>(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HeaderValue</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span> {
<span class="ident">HeaderValue::from_maybe_shared</span>(<span class="self">self</span>.<span class="ident">to_bytes</span>())
<span class="kw">fn </span>try_into_value(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;HeaderValue, <span class="self">Self</span>::Error&gt; {
HeaderValue::from_maybe_shared(<span class="self">self</span>.to_bytes())
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -48,55 +48,55 @@
<span id="48">48</span>
<span id="49">49</span>
<span id="50">50</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::fmt</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::fmt;
<span class="kw">use</span> <span class="ident">actix_web::http::StatusCode</span>;
<span class="kw">use </span>actix_web::http::StatusCode;
<span class="doccomment">/// Bearer authorization error types, described in [RFC 6750].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [RFC 6750]: https://tools.ietf.org/html/rfc6750#section-3.1</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>, <span class="ident">Copy</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">PartialOrd</span>, <span class="ident">Ord</span>, <span class="ident">Hash</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">Error</span> {
<span class="doccomment">/// The request is missing a required parameter, includes an unsupported parameter or parameter</span>
<span class="doccomment">/// value, repeats the same parameter, uses more than one method for including an access token,</span>
<span class="doccomment">/// or is otherwise malformed.</span>
<span class="ident">InvalidRequest</span>,
<span class="doccomment">/// Bearer authorization error types, described in [RFC 6750].
///
/// [RFC 6750]: https://tools.ietf.org/html/rfc6750#section-3.1
</span><span class="attribute">#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
</span><span class="kw">pub enum </span>Error {
<span class="doccomment">/// The request is missing a required parameter, includes an unsupported parameter or parameter
/// value, repeats the same parameter, uses more than one method for including an access token,
/// or is otherwise malformed.
</span>InvalidRequest,
<span class="doccomment">/// The access token provided is expired, revoked, malformed, or invalid for other reasons.</span>
<span class="ident">InvalidToken</span>,
<span class="doccomment">/// The access token provided is expired, revoked, malformed, or invalid for other reasons.
</span>InvalidToken,
<span class="doccomment">/// The request requires higher privileges than provided by the access token.</span>
<span class="ident">InsufficientScope</span>,
<span class="doccomment">/// The request requires higher privileges than provided by the access token.
</span>InsufficientScope,
}
<span class="kw">impl</span> <span class="ident">Error</span> {
<span class="doccomment">/// Returns [HTTP status code] suitable for current error type.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [HTTP status code]: `actix_web::http::StatusCode`</span>
<span class="attribute">#[<span class="ident">allow</span>(<span class="ident">clippy::trivially_copy_pass_by_ref</span>)]</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">status_code</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">StatusCode</span> {
<span class="kw">match</span> <span class="self">self</span> {
<span class="ident">Error::InvalidRequest</span> =&gt; <span class="ident">StatusCode::BAD_REQUEST</span>,
<span class="ident">Error::InvalidToken</span> =&gt; <span class="ident">StatusCode::UNAUTHORIZED</span>,
<span class="ident">Error::InsufficientScope</span> =&gt; <span class="ident">StatusCode::FORBIDDEN</span>,
<span class="kw">impl </span>Error {
<span class="doccomment">/// Returns [HTTP status code] suitable for current error type.
///
/// [HTTP status code]: `actix_web::http::StatusCode`
</span><span class="attribute">#[allow(clippy::trivially_copy_pass_by_ref)]
</span><span class="kw">pub fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
<span class="kw">match </span><span class="self">self </span>{
Error::InvalidRequest =&gt; StatusCode::BAD_REQUEST,
Error::InvalidToken =&gt; StatusCode::UNAUTHORIZED,
Error::InsufficientScope =&gt; StatusCode::FORBIDDEN,
}
}
<span class="attribute">#[<span class="ident">doc</span>(<span class="ident">hidden</span>)]</span>
<span class="attribute">#[<span class="ident">allow</span>(<span class="ident">clippy::trivially_copy_pass_by_ref</span>)]</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">as_str</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="ident">str</span> {
<span class="kw">match</span> <span class="self">self</span> {
<span class="ident">Error::InvalidRequest</span> =&gt; <span class="string">&quot;invalid_request&quot;</span>,
<span class="ident">Error::InvalidToken</span> =&gt; <span class="string">&quot;invalid_token&quot;</span>,
<span class="ident">Error::InsufficientScope</span> =&gt; <span class="string">&quot;insufficient_scope&quot;</span>,
<span class="attribute">#[doc(hidden)]
#[allow(clippy::trivially_copy_pass_by_ref)]
</span><span class="kw">pub fn </span>as_str(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="kw">match </span><span class="self">self </span>{
Error::InvalidRequest =&gt; <span class="string">&quot;invalid_request&quot;</span>,
Error::InvalidToken =&gt; <span class="string">&quot;invalid_token&quot;</span>,
Error::InsufficientScope =&gt; <span class="string">&quot;insufficient_scope&quot;</span>,
}
}
}
<span class="kw">impl</span> <span class="ident">fmt::Display</span> <span class="kw">for</span> <span class="ident">Error</span> {
<span class="kw">fn</span> <span class="ident">fmt</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">f</span>: <span class="kw-2">&amp;mut</span> <span class="ident">fmt::Formatter</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">fmt::Result</span> {
<span class="ident">f</span>.<span class="ident">write_str</span>(<span class="self">self</span>.<span class="ident">as_str</span>())
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>Error {
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; fmt::Result {
f.write_str(<span class="self">self</span>.as_str())
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -25,32 +25,32 @@
<span id="25">25</span>
<span id="26">26</span>
<span id="27">27</span>
</pre><pre class="rust"><code><span class="doccomment">//! Challenge for the &quot;Bearer&quot; HTTP Authentication Scheme.</span>
</pre><pre class="rust"><code><span class="doccomment">//! Challenge for the &quot;Bearer&quot; HTTP Authentication Scheme.
<span class="kw">mod</span> <span class="ident">builder</span>;
<span class="kw">mod</span> <span class="ident">challenge</span>;
<span class="kw">mod</span> <span class="ident">errors</span>;
</span><span class="kw">mod </span>builder;
<span class="kw">mod </span>challenge;
<span class="kw">mod </span>errors;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::builder::BearerBuilder</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::challenge::Bearer</span>;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::errors::Error</span>;
<span class="kw">pub use </span><span class="self">self</span>::builder::BearerBuilder;
<span class="kw">pub use </span><span class="self">self</span>::challenge::Bearer;
<span class="kw">pub use </span><span class="self">self</span>::errors::Error;
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">to_bytes</span>() {
<span class="kw">let</span> <span class="ident">b</span> <span class="op">=</span> <span class="ident">Bearer::build</span>()
.<span class="ident">error</span>(<span class="ident">Error::InvalidToken</span>)
.<span class="ident">error_description</span>(<span class="string">&quot;Subject 8740827c-2e0a-447b-9716-d73042e4039d not found&quot;</span>)
.<span class="ident">finish</span>();
<span class="attribute">#[test]
</span><span class="kw">fn </span>to_bytes() {
<span class="kw">let </span>b = Bearer::build()
.error(Error::InvalidToken)
.error_description(<span class="string">&quot;Subject 8740827c-2e0a-447b-9716-d73042e4039d not found&quot;</span>)
.finish();
<span class="macro">assert_eq!</span>(
<span class="string">&quot;Bearer error=\&quot;invalid_token\&quot; error_description=\&quot;Subject 8740827c-2e0a-447b-9716-d73042e4039d not found\&quot;&quot;</span>,
<span class="macro">format!</span>(<span class="string">&quot;{}&quot;</span>, <span class="ident">b</span>)
<span class="macro">format!</span>(<span class="string">&quot;{}&quot;</span>, b)
);
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -10,17 +10,17 @@
<span id="10">10</span>
<span id="11">11</span>
<span id="12">12</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::fmt</span>::{<span class="ident">Debug</span>, <span class="ident">Display</span>};
</pre><pre class="rust"><code><span class="kw">use </span>std::fmt::{Debug, Display};
<span class="kw">use</span> <span class="ident">actix_web</span>::{<span class="ident">http::header::TryIntoHeaderValue</span>, <span class="ident">web::Bytes</span>};
<span class="kw">use </span>actix_web::{http::header::TryIntoHeaderValue, web::Bytes};
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">basic</span>;
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">bearer</span>;
<span class="kw">pub mod </span>basic;
<span class="kw">pub mod </span>bearer;
<span class="doccomment">/// Authentication challenge for `WWW-Authenticate` header.</span>
<span class="kw">pub</span> <span class="kw">trait</span> <span class="ident">Challenge</span>: <span class="ident">TryIntoHeaderValue</span> <span class="op">+</span> <span class="ident">Debug</span> <span class="op">+</span> <span class="ident">Display</span> <span class="op">+</span> <span class="ident">Clone</span> <span class="op">+</span> <span class="ident">Send</span> <span class="op">+</span> <span class="ident">Sync</span> {
<span class="doccomment">/// Converts the challenge into a bytes suitable for HTTP transmission.</span>
<span class="kw">fn</span> <span class="ident">to_bytes</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Bytes</span>;
<span class="doccomment">/// Authentication challenge for `WWW-Authenticate` header.
</span><span class="kw">pub trait </span>Challenge: TryIntoHeaderValue + Debug + Display + Clone + Send + Sync {
<span class="doccomment">/// Converts the challenge into a bytes suitable for HTTP transmission.
</span><span class="kw">fn </span>to_bytes(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Bytes;
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -33,40 +33,40 @@
<span id="33">33</span>
<span id="34">34</span>
<span id="35">35</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">error::ParseError</span>,
<span class="ident">http::header</span>::{<span class="ident">Header</span>, <span class="ident">HeaderName</span>, <span class="ident">HeaderValue</span>, <span class="ident">TryIntoHeaderValue</span>, <span class="ident">WWW_AUTHENTICATE</span>},
<span class="ident">HttpMessage</span>,
</pre><pre class="rust"><code><span class="kw">use </span>actix_web::{
error::ParseError,
http::header::{Header, HeaderName, HeaderValue, TryIntoHeaderValue, WWW_AUTHENTICATE},
HttpMessage,
};
<span class="kw">use</span> <span class="ident"><span class="kw">super</span>::Challenge</span>;
<span class="kw">use </span><span class="kw">super</span>::Challenge;
<span class="doccomment">/// `WWW-Authenticate` header, described in [RFC 7235].</span>
<span class="doccomment">///</span>
<span class="doccomment">/// This header is generic over the [`Challenge`] trait, see [`Basic`](super::basic::Basic) and</span>
<span class="doccomment">/// [`Bearer`](super::bearer::Bearer) challenges for details.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// [RFC 7235]: https://tools.ietf.org/html/rfc7235#section-4.1</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Default</span>, <span class="ident">Clone</span>, <span class="ident">PartialEq</span>, <span class="ident">Eq</span>, <span class="ident">PartialOrd</span>, <span class="ident">Ord</span>, <span class="ident">Hash</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">WwwAuthenticate</span><span class="op">&lt;</span><span class="ident">C</span>: <span class="ident">Challenge</span><span class="op">&gt;</span>(<span class="kw">pub</span> <span class="ident">C</span>);
<span class="doccomment">/// `WWW-Authenticate` header, described in [RFC 7235].
///
/// This header is generic over the [`Challenge`] trait, see [`Basic`](super::basic::Basic) and
/// [`Bearer`](super::bearer::Bearer) challenges for details.
///
/// [RFC 7235]: https://tools.ietf.org/html/rfc7235#section-4.1
</span><span class="attribute">#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
</span><span class="kw">pub struct </span>WwwAuthenticate&lt;C: Challenge&gt;(<span class="kw">pub </span>C);
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">C</span>: <span class="ident">Challenge</span><span class="op">&gt;</span> <span class="ident">Header</span> <span class="kw">for</span> <span class="ident">WwwAuthenticate</span><span class="op">&lt;</span><span class="ident">C</span><span class="op">&gt;</span> {
<span class="attribute">#[<span class="ident">inline</span>]</span>
<span class="kw">fn</span> <span class="ident">name</span>() -&gt; <span class="ident">HeaderName</span> {
<span class="ident">WWW_AUTHENTICATE</span>
<span class="kw">impl</span>&lt;C: Challenge&gt; Header <span class="kw">for </span>WwwAuthenticate&lt;C&gt; {
<span class="attribute">#[inline]
</span><span class="kw">fn </span>name() -&gt; HeaderName {
WWW_AUTHENTICATE
}
<span class="kw">fn</span> <span class="ident">parse</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">HttpMessage</span><span class="op">&gt;</span>(<span class="ident">_msg</span>: <span class="kw-2">&amp;</span><span class="ident">T</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>, <span class="ident">ParseError</span><span class="op">&gt;</span> {
<span class="kw">fn </span>parse&lt;T: HttpMessage&gt;(_msg: <span class="kw-2">&amp;</span>T) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, ParseError&gt; {
<span class="macro">unimplemented!</span>()
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">C</span>: <span class="ident">Challenge</span><span class="op">&gt;</span> <span class="ident">TryIntoHeaderValue</span> <span class="kw">for</span> <span class="ident">WwwAuthenticate</span><span class="op">&lt;</span><span class="ident">C</span><span class="op">&gt;</span> {
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="op">&lt;</span><span class="ident">C</span> <span class="kw">as</span> <span class="ident">TryIntoHeaderValue</span><span class="op">&gt;</span><span class="ident">::Error</span>;
<span class="kw">impl</span>&lt;C: Challenge&gt; TryIntoHeaderValue <span class="kw">for </span>WwwAuthenticate&lt;C&gt; {
<span class="kw">type </span>Error = &lt;C <span class="kw">as </span>TryIntoHeaderValue&gt;::Error;
<span class="kw">fn</span> <span class="ident">try_into_value</span>(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">HeaderValue</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span> {
<span class="self">self</span>.<span class="number">0</span>.<span class="ident">try_into_value</span>()
<span class="kw">fn </span>try_into_value(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;HeaderValue, <span class="self">Self</span>::Error&gt; {
<span class="self">self</span>.<span class="number">0</span>.try_into_value()
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -5,12 +5,12 @@
<span id="5">5</span>
<span id="6">6</span>
<span id="7">7</span>
</pre><pre class="rust"><code><span class="doccomment">//! `WWW-Authenticate` header and various auth challenges.</span>
</pre><pre class="rust"><code><span class="doccomment">//! `WWW-Authenticate` header and various auth challenges.
<span class="kw">mod</span> <span class="ident">challenge</span>;
<span class="kw">mod</span> <span class="ident">header</span>;
</span><span class="kw">mod </span>challenge;
<span class="kw">mod </span>header;
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::challenge</span>::{<span class="ident">basic</span>, <span class="ident">bearer</span>, <span class="ident">Challenge</span>};
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::header::WwwAuthenticate</span>;
<span class="kw">pub use </span><span class="self">self</span>::challenge::{basic, bearer, Challenge};
<span class="kw">pub use </span><span class="self">self</span>::header::WwwAuthenticate;
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -22,29 +22,29 @@
<span id="22">22</span>
<span id="23">23</span>
<span id="24">24</span>
</pre><pre class="rust"><code><span class="doccomment">//! HTTP authentication schemes for [Actix Web](https://actix.rs).</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! Provides:</span>
<span class="doccomment">//! - Typed [Authorization] and [WWW-Authenticate] headers</span>
<span class="doccomment">//! - [Extractors] for an [Authorization] header</span>
<span class="doccomment">//! - [Middleware] for easier authorization checking</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! ## Supported schemes</span>
<span class="doccomment">//! - `Bearer` as defined in [RFC 6750](https://tools.ietf.org/html/rfc6750).</span>
<span class="doccomment">//! - `Basic` as defined in [RFC 7617](https://tools.ietf.org/html/rfc7617).</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! [Authorization]: `self::headers::authorization::Authorization`</span>
<span class="doccomment">//! [WWW-Authenticate]: `self::headers::www_authenticate::WwwAuthenticate`</span>
<span class="doccomment">//! [Extractors]: https://actix.rs/docs/extractors</span>
<span class="doccomment">//! [Middleware]: self::middleware</span>
</pre><pre class="rust"><code><span class="doccomment">//! HTTP authentication schemes for [Actix Web](https://actix.rs).
//!
//! Provides:
//! - Typed [Authorization] and [WWW-Authenticate] headers
//! - [Extractors] for an [Authorization] header
//! - [Middleware] for easier authorization checking
//!
//! ## Supported schemes
//! - `Bearer` as defined in [RFC 6750](https://tools.ietf.org/html/rfc6750).
//! - `Basic` as defined in [RFC 7617](https://tools.ietf.org/html/rfc7617).
//!
//! [Authorization]: `self::headers::authorization::Authorization`
//! [WWW-Authenticate]: `self::headers::www_authenticate::WwwAuthenticate`
//! [Extractors]: https://actix.rs/docs/extractors
//! [Middleware]: self::middleware
<span class="attribute">#![<span class="ident">forbid</span>(<span class="ident">unsafe_code</span>)]</span>
<span class="attribute">#![<span class="ident">deny</span>(<span class="ident">rust_2018_idioms</span>, <span class="ident">nonstandard_style</span>)]</span>
<span class="attribute">#![<span class="ident">warn</span>(<span class="ident">future_incompatible</span>, <span class="ident">missing_docs</span>)]</span>
</span><span class="attribute">#![forbid(unsafe_code)]
#![deny(rust_2018_idioms, nonstandard_style)]
#![warn(future_incompatible, missing_docs)]
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">extractors</span>;
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">headers</span>;
<span class="kw">pub</span> <span class="kw">mod</span> <span class="ident">middleware</span>;
<span class="kw">mod</span> <span class="ident">utils</span>;
</span><span class="kw">pub mod </span>extractors;
<span class="kw">pub mod </span>headers;
<span class="kw">pub mod </span>middleware;
<span class="kw">mod </span>utils;
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -415,422 +415,422 @@
<span id="415">415</span>
<span id="416">416</span>
<span id="417">417</span>
</pre><pre class="rust"><code><span class="doccomment">//! HTTP Authentication middleware.</span>
</pre><pre class="rust"><code><span class="doccomment">//! HTTP Authentication middleware.
<span class="kw">use</span> <span class="ident">std</span>::{
<span class="ident">future::Future</span>,
<span class="ident">marker::PhantomData</span>,
<span class="ident">pin::Pin</span>,
<span class="ident">rc::Rc</span>,
<span class="ident">sync::Arc</span>,
<span class="ident">task</span>::{<span class="ident">Context</span>, <span class="ident">Poll</span>},
</span><span class="kw">use </span>std::{
future::Future,
marker::PhantomData,
pin::Pin,
rc::Rc,
sync::Arc,
task::{Context, Poll},
};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">body</span>::{<span class="ident">EitherBody</span>, <span class="ident">MessageBody</span>},
<span class="ident">dev</span>::{<span class="ident">Service</span>, <span class="ident">ServiceRequest</span>, <span class="ident">ServiceResponse</span>, <span class="ident">Transform</span>},
<span class="ident">Error</span>, <span class="ident">FromRequest</span>,
<span class="kw">use </span>actix_web::{
body::{EitherBody, MessageBody},
dev::{Service, ServiceRequest, ServiceResponse, Transform},
Error, FromRequest,
};
<span class="kw">use</span> <span class="ident">futures_core::ready</span>;
<span class="kw">use</span> <span class="ident">futures_util::future</span>::{<span class="self">self</span>, <span class="ident">LocalBoxFuture</span>, <span class="ident">TryFutureExt</span> <span class="kw">as</span> <span class="kw">_</span>};
<span class="kw">use </span>futures_core::ready;
<span class="kw">use </span>futures_util::future::{<span class="self">self</span>, LocalBoxFuture, TryFutureExt <span class="kw">as _</span>};
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::extractors</span>::{<span class="ident">basic</span>, <span class="ident">bearer</span>};
<span class="kw">use </span><span class="kw">crate</span>::extractors::{basic, bearer};
<span class="doccomment">/// Middleware for checking HTTP authentication.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If there is no `Authorization` header in the request, this middleware returns an error</span>
<span class="doccomment">/// immediately, without calling the `F` callback.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Otherwise, it will pass both the request and the parsed credentials into it. In case of</span>
<span class="doccomment">/// successful validation `F` callback is required to return the `ServiceRequest` back.</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>, <span class="ident">Clone</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">HttpAuthentication</span><span class="op">&lt;</span><span class="ident">T</span>, <span class="ident">F</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">FromRequest</span>,
<span class="doccomment">/// Middleware for checking HTTP authentication.
///
/// If there is no `Authorization` header in the request, this middleware returns an error
/// immediately, without calling the `F` callback.
///
/// Otherwise, it will pass both the request and the parsed credentials into it. In case of
/// successful validation `F` callback is required to return the `ServiceRequest` back.
</span><span class="attribute">#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>HttpAuthentication&lt;T, F&gt;
<span class="kw">where
</span>T: FromRequest,
{
<span class="ident">process_fn</span>: <span class="ident">Arc</span><span class="op">&lt;</span><span class="ident">F</span><span class="op">&gt;</span>,
<span class="ident">_extractor</span>: <span class="ident">PhantomData</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>,
process_fn: Arc&lt;F&gt;,
_extractor: PhantomData&lt;T&gt;,
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span>, <span class="ident">F</span>, <span class="ident">O</span><span class="op">&gt;</span> <span class="ident">HttpAuthentication</span><span class="op">&lt;</span><span class="ident">T</span>, <span class="ident">F</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">FromRequest</span>,
<span class="ident">F</span>: <span class="ident">Fn</span>(<span class="ident">ServiceRequest</span>, <span class="ident">T</span>) -&gt; <span class="ident">O</span>,
<span class="ident">O</span>: <span class="ident">Future</span><span class="op">&lt;</span><span class="ident">Output</span> <span class="op">=</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, (<span class="ident">Error</span>, <span class="ident">ServiceRequest</span>)<span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">impl</span>&lt;T, F, O&gt; HttpAuthentication&lt;T, F&gt;
<span class="kw">where
</span>T: FromRequest,
F: Fn(ServiceRequest, T) -&gt; O,
O: Future&lt;Output = <span class="prelude-ty">Result</span>&lt;ServiceRequest, (Error, ServiceRequest)&gt;&gt;,
{
<span class="doccomment">/// Construct `HttpAuthentication` middleware with the provided auth extractor `T` and</span>
<span class="doccomment">/// validation callback `F`.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">with_fn</span>(<span class="ident">process_fn</span>: <span class="ident">F</span>) -&gt; <span class="ident">HttpAuthentication</span><span class="op">&lt;</span><span class="ident">T</span>, <span class="ident">F</span><span class="op">&gt;</span> {
<span class="ident">HttpAuthentication</span> {
<span class="ident">process_fn</span>: <span class="ident">Arc::new</span>(<span class="ident">process_fn</span>),
<span class="ident">_extractor</span>: <span class="ident">PhantomData</span>,
<span class="doccomment">/// Construct `HttpAuthentication` middleware with the provided auth extractor `T` and
/// validation callback `F`.
</span><span class="kw">pub fn </span>with_fn(process_fn: F) -&gt; HttpAuthentication&lt;T, F&gt; {
HttpAuthentication {
process_fn: Arc::new(process_fn),
_extractor: PhantomData,
}
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">F</span>, <span class="ident">O</span><span class="op">&gt;</span> <span class="ident">HttpAuthentication</span><span class="op">&lt;</span><span class="ident">basic::BasicAuth</span>, <span class="ident">F</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">F</span>: <span class="ident">Fn</span>(<span class="ident">ServiceRequest</span>, <span class="ident">basic::BasicAuth</span>) -&gt; <span class="ident">O</span>,
<span class="ident">O</span>: <span class="ident">Future</span><span class="op">&lt;</span><span class="ident">Output</span> <span class="op">=</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, (<span class="ident">Error</span>, <span class="ident">ServiceRequest</span>)<span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">impl</span>&lt;F, O&gt; HttpAuthentication&lt;basic::BasicAuth, F&gt;
<span class="kw">where
</span>F: Fn(ServiceRequest, basic::BasicAuth) -&gt; O,
O: Future&lt;Output = <span class="prelude-ty">Result</span>&lt;ServiceRequest, (Error, ServiceRequest)&gt;&gt;,
{
<span class="doccomment">/// Construct `HttpAuthentication` middleware for the HTTP &quot;Basic&quot; authentication scheme.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web::{Error, dev::ServiceRequest};</span>
<span class="doccomment">/// # use actix_web_httpauth::{extractors::basic::BasicAuth, middleware::HttpAuthentication};</span>
<span class="doccomment">/// // In this example validator returns immediately, but since it is required to return</span>
<span class="doccomment">/// // anything that implements `IntoFuture` trait, it can be extended to query database or to</span>
<span class="doccomment">/// // do something else in a async manner.</span>
<span class="doccomment">/// async fn validator(</span>
<span class="doccomment">/// req: ServiceRequest,</span>
<span class="doccomment">/// credentials: BasicAuth,</span>
<span class="doccomment">/// ) -&gt; Result&lt;ServiceRequest, (Error, ServiceRequest)&gt; {</span>
<span class="doccomment">/// // All users are great and more than welcome!</span>
<span class="doccomment">/// Ok(req)</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// let middleware = HttpAuthentication::basic(validator);</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">basic</span>(<span class="ident">process_fn</span>: <span class="ident">F</span>) -&gt; <span class="self">Self</span> {
<span class="ident"><span class="self">Self</span>::with_fn</span>(<span class="ident">process_fn</span>)
<span class="doccomment">/// Construct `HttpAuthentication` middleware for the HTTP &quot;Basic&quot; authentication scheme.
///
/// # Examples
/// ```
/// # use actix_web::{Error, dev::ServiceRequest};
/// # use actix_web_httpauth::{extractors::basic::BasicAuth, middleware::HttpAuthentication};
/// // In this example validator returns immediately, but since it is required to return
/// // anything that implements `IntoFuture` trait, it can be extended to query database or to
/// // do something else in a async manner.
/// async fn validator(
/// req: ServiceRequest,
/// credentials: BasicAuth,
/// ) -&gt; Result&lt;ServiceRequest, (Error, ServiceRequest)&gt; {
/// // All users are great and more than welcome!
/// Ok(req)
/// }
///
/// let middleware = HttpAuthentication::basic(validator);
/// ```
</span><span class="kw">pub fn </span>basic(process_fn: F) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::with_fn(process_fn)
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">F</span>, <span class="ident">O</span><span class="op">&gt;</span> <span class="ident">HttpAuthentication</span><span class="op">&lt;</span><span class="ident">bearer::BearerAuth</span>, <span class="ident">F</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">F</span>: <span class="ident">Fn</span>(<span class="ident">ServiceRequest</span>, <span class="ident">bearer::BearerAuth</span>) -&gt; <span class="ident">O</span>,
<span class="ident">O</span>: <span class="ident">Future</span><span class="op">&lt;</span><span class="ident">Output</span> <span class="op">=</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, (<span class="ident">Error</span>, <span class="ident">ServiceRequest</span>)<span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="kw">impl</span>&lt;F, O&gt; HttpAuthentication&lt;bearer::BearerAuth, F&gt;
<span class="kw">where
</span>F: Fn(ServiceRequest, bearer::BearerAuth) -&gt; O,
O: Future&lt;Output = <span class="prelude-ty">Result</span>&lt;ServiceRequest, (Error, ServiceRequest)&gt;&gt;,
{
<span class="doccomment">/// Construct `HttpAuthentication` middleware for the HTTP &quot;Bearer&quot; authentication scheme.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web::{Error, dev::ServiceRequest};</span>
<span class="doccomment">/// # use actix_web_httpauth::{</span>
<span class="doccomment">/// # extractors::{AuthenticationError, AuthExtractorConfig, bearer::{self, BearerAuth}},</span>
<span class="doccomment">/// # middleware::HttpAuthentication,</span>
<span class="doccomment">/// # };</span>
<span class="doccomment">/// async fn validator(</span>
<span class="doccomment">/// req: ServiceRequest,</span>
<span class="doccomment">/// credentials: BearerAuth</span>
<span class="doccomment">/// ) -&gt; Result&lt;ServiceRequest, (Error, ServiceRequest)&gt; {</span>
<span class="doccomment">/// if credentials.token() == &quot;mF_9.B5f-4.1JqM&quot; {</span>
<span class="doccomment">/// Ok(req)</span>
<span class="doccomment">/// } else {</span>
<span class="doccomment">/// let config = req.app_data::&lt;bearer::Config&gt;()</span>
<span class="doccomment">/// .cloned()</span>
<span class="doccomment">/// .unwrap_or_default()</span>
<span class="doccomment">/// .scope(&quot;urn:example:channel=HBO&amp;urn:example:rating=G,PG-13&quot;);</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Err((AuthenticationError::from(config).into(), req))</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// let middleware = HttpAuthentication::bearer(validator);</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">bearer</span>(<span class="ident">process_fn</span>: <span class="ident">F</span>) -&gt; <span class="self">Self</span> {
<span class="ident"><span class="self">Self</span>::with_fn</span>(<span class="ident">process_fn</span>)
<span class="doccomment">/// Construct `HttpAuthentication` middleware for the HTTP &quot;Bearer&quot; authentication scheme.
///
/// # Examples
/// ```
/// # use actix_web::{Error, dev::ServiceRequest};
/// # use actix_web_httpauth::{
/// # extractors::{AuthenticationError, AuthExtractorConfig, bearer::{self, BearerAuth}},
/// # middleware::HttpAuthentication,
/// # };
/// async fn validator(
/// req: ServiceRequest,
/// credentials: BearerAuth
/// ) -&gt; Result&lt;ServiceRequest, (Error, ServiceRequest)&gt; {
/// if credentials.token() == &quot;mF_9.B5f-4.1JqM&quot; {
/// Ok(req)
/// } else {
/// let config = req.app_data::&lt;bearer::Config&gt;()
/// .cloned()
/// .unwrap_or_default()
/// .scope(&quot;urn:example:channel=HBO&amp;urn:example:rating=G,PG-13&quot;);
///
/// Err((AuthenticationError::from(config).into(), req))
/// }
/// }
///
/// let middleware = HttpAuthentication::bearer(validator);
/// ```
</span><span class="kw">pub fn </span>bearer(process_fn: F) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::with_fn(process_fn)
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">B</span>, <span class="ident">T</span>, <span class="ident">F</span>, <span class="ident">O</span><span class="op">&gt;</span> <span class="ident">Transform</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">ServiceRequest</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">HttpAuthentication</span><span class="op">&lt;</span><span class="ident">T</span>, <span class="ident">F</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">S</span>: <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>, <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span><span class="op">&gt;</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">S::Future</span>: <span class="lifetime">&#39;static</span>,
<span class="ident">F</span>: <span class="ident">Fn</span>(<span class="ident">ServiceRequest</span>, <span class="ident">T</span>) -&gt; <span class="ident">O</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">O</span>: <span class="ident">Future</span><span class="op">&lt;</span><span class="ident">Output</span> <span class="op">=</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, (<span class="ident">Error</span>, <span class="ident">ServiceRequest</span>)<span class="op">&gt;</span><span class="op">&gt;</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">T</span>: <span class="ident">FromRequest</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">B</span>: <span class="ident">MessageBody</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="kw">impl</span>&lt;S, B, T, F, O&gt; Transform&lt;S, ServiceRequest&gt; <span class="kw">for </span>HttpAuthentication&lt;T, F&gt;
<span class="kw">where
</span>S: Service&lt;ServiceRequest, Response = ServiceResponse&lt;B&gt;, Error = Error&gt; + <span class="lifetime">&#39;static</span>,
S::Future: <span class="lifetime">&#39;static</span>,
F: Fn(ServiceRequest, T) -&gt; O + <span class="lifetime">&#39;static</span>,
O: Future&lt;Output = <span class="prelude-ty">Result</span>&lt;ServiceRequest, (Error, ServiceRequest)&gt;&gt; + <span class="lifetime">&#39;static</span>,
T: FromRequest + <span class="lifetime">&#39;static</span>,
B: MessageBody + <span class="lifetime">&#39;static</span>,
{
<span class="kw">type</span> <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">EitherBody</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span>;
<span class="kw">type</span> <span class="ident">Transform</span> <span class="op">=</span> <span class="ident">AuthenticationMiddleware</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">F</span>, <span class="ident">T</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">InitError</span> <span class="op">=</span> ();
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">future::Ready</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Transform</span>, <span class="ident"><span class="self">Self</span>::InitError</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type </span>Response = ServiceResponse&lt;EitherBody&lt;B&gt;&gt;;
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Transform = AuthenticationMiddleware&lt;S, F, T&gt;;
<span class="kw">type </span>InitError = ();
<span class="kw">type </span>Future = future::Ready&lt;<span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Transform, <span class="self">Self</span>::InitError&gt;&gt;;
<span class="kw">fn</span> <span class="ident">new_transform</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">service</span>: <span class="ident">S</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="ident">future::ok</span>(<span class="ident">AuthenticationMiddleware</span> {
<span class="ident">service</span>: <span class="ident">Rc::new</span>(<span class="ident">service</span>),
<span class="ident">process_fn</span>: <span class="self">self</span>.<span class="ident">process_fn</span>.<span class="ident">clone</span>(),
<span class="ident">_extractor</span>: <span class="ident">PhantomData</span>,
<span class="kw">fn </span>new_transform(<span class="kw-2">&amp;</span><span class="self">self</span>, service: S) -&gt; <span class="self">Self</span>::Future {
future::ok(AuthenticationMiddleware {
service: Rc::new(service),
process_fn: <span class="self">self</span>.process_fn.clone(),
_extractor: PhantomData,
})
}
}
<span class="attribute">#[<span class="ident">doc</span>(<span class="ident">hidden</span>)]</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">AuthenticationMiddleware</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">F</span>, <span class="ident">T</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">FromRequest</span>,
<span class="attribute">#[doc(hidden)]
</span><span class="kw">pub struct </span>AuthenticationMiddleware&lt;S, F, T&gt;
<span class="kw">where
</span>T: FromRequest,
{
<span class="ident">service</span>: <span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">S</span><span class="op">&gt;</span>,
<span class="ident">process_fn</span>: <span class="ident">Arc</span><span class="op">&lt;</span><span class="ident">F</span><span class="op">&gt;</span>,
<span class="ident">_extractor</span>: <span class="ident">PhantomData</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>,
service: Rc&lt;S&gt;,
process_fn: Arc&lt;F&gt;,
_extractor: PhantomData&lt;T&gt;,
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">B</span>, <span class="ident">F</span>, <span class="ident">T</span>, <span class="ident">O</span><span class="op">&gt;</span> <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span><span class="op">&gt;</span> <span class="kw">for</span> <span class="ident">AuthenticationMiddleware</span><span class="op">&lt;</span><span class="ident">S</span>, <span class="ident">F</span>, <span class="ident">T</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">S</span>: <span class="ident">Service</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>, <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span><span class="op">&gt;</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">S::Future</span>: <span class="lifetime">&#39;static</span>,
<span class="ident">F</span>: <span class="ident">Fn</span>(<span class="ident">ServiceRequest</span>, <span class="ident">T</span>) -&gt; <span class="ident">O</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">O</span>: <span class="ident">Future</span><span class="op">&lt;</span><span class="ident">Output</span> <span class="op">=</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, (<span class="ident">Error</span>, <span class="ident">ServiceRequest</span>)<span class="op">&gt;</span><span class="op">&gt;</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">T</span>: <span class="ident">FromRequest</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="ident">B</span>: <span class="ident">MessageBody</span> <span class="op">+</span> <span class="lifetime">&#39;static</span>,
<span class="kw">impl</span>&lt;S, B, F, T, O&gt; Service&lt;ServiceRequest&gt; <span class="kw">for </span>AuthenticationMiddleware&lt;S, F, T&gt;
<span class="kw">where
</span>S: Service&lt;ServiceRequest, Response = ServiceResponse&lt;B&gt;, Error = Error&gt; + <span class="lifetime">&#39;static</span>,
S::Future: <span class="lifetime">&#39;static</span>,
F: Fn(ServiceRequest, T) -&gt; O + <span class="lifetime">&#39;static</span>,
O: Future&lt;Output = <span class="prelude-ty">Result</span>&lt;ServiceRequest, (Error, ServiceRequest)&gt;&gt; + <span class="lifetime">&#39;static</span>,
T: FromRequest + <span class="lifetime">&#39;static</span>,
B: MessageBody + <span class="lifetime">&#39;static</span>,
{
<span class="kw">type</span> <span class="ident">Response</span> <span class="op">=</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">EitherBody</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">S::Error</span>;
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">LocalBoxFuture</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Response</span>, <span class="ident"><span class="self">Self</span>::Error</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="kw">type </span>Response = ServiceResponse&lt;EitherBody&lt;B&gt;&gt;;
<span class="kw">type </span>Error = S::Error;
<span class="kw">type </span>Future = LocalBoxFuture&lt;<span class="lifetime">&#39;static</span>, <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Response, <span class="self">Self</span>::Error&gt;&gt;;
<span class="macro">actix_web::dev::forward_ready!</span>(<span class="ident">service</span>);
<span class="macro">actix_web::dev::forward_ready!</span>(service);
<span class="kw">fn</span> <span class="ident">call</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">req</span>: <span class="ident">ServiceRequest</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="kw">let</span> <span class="ident">process_fn</span> <span class="op">=</span> <span class="ident">Arc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">process_fn</span>);
<span class="kw">let</span> <span class="ident">service</span> <span class="op">=</span> <span class="ident">Rc::clone</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">service</span>);
<span class="kw">fn </span>call(<span class="kw-2">&amp;</span><span class="self">self</span>, req: ServiceRequest) -&gt; <span class="self">Self</span>::Future {
<span class="kw">let </span>process_fn = Arc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.process_fn);
<span class="kw">let </span>service = Rc::clone(<span class="kw-2">&amp;</span><span class="self">self</span>.service);
<span class="ident">Box::pin</span>(<span class="kw">async</span> <span class="kw">move</span> {
<span class="kw">let</span> (<span class="ident">req</span>, <span class="ident">credentials</span>) <span class="op">=</span> <span class="kw">match</span> <span class="ident">Extract</span>::<span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span><span class="ident">::new</span>(<span class="ident">req</span>).<span class="kw">await</span> {
<span class="prelude-val">Ok</span>(<span class="ident">req</span>) =&gt; <span class="ident">req</span>,
<span class="prelude-val">Err</span>((<span class="ident">err</span>, <span class="ident">req</span>)) =&gt; {
<span class="kw">return</span> <span class="prelude-val">Ok</span>(<span class="ident">req</span>.<span class="ident">error_response</span>(<span class="ident">err</span>).<span class="ident">map_into_right_body</span>());
Box::pin(<span class="kw">async move </span>{
<span class="kw">let </span>(req, credentials) = <span class="kw">match </span>Extract::&lt;T&gt;::new(req).<span class="kw">await </span>{
<span class="prelude-val">Ok</span>(req) =&gt; req,
<span class="prelude-val">Err</span>((err, req)) =&gt; {
<span class="kw">return </span><span class="prelude-val">Ok</span>(req.error_response(err).map_into_right_body());
}
};
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="kw">match</span> <span class="ident">process_fn</span>(<span class="ident">req</span>, <span class="ident">credentials</span>).<span class="kw">await</span> {
<span class="prelude-val">Ok</span>(<span class="ident">req</span>) =&gt; <span class="ident">req</span>,
<span class="prelude-val">Err</span>((<span class="ident">err</span>, <span class="ident">req</span>)) =&gt; {
<span class="kw">return</span> <span class="prelude-val">Ok</span>(<span class="ident">req</span>.<span class="ident">error_response</span>(<span class="ident">err</span>).<span class="ident">map_into_right_body</span>());
<span class="kw">let </span>req = <span class="kw">match </span>process_fn(req, credentials).<span class="kw">await </span>{
<span class="prelude-val">Ok</span>(req) =&gt; req,
<span class="prelude-val">Err</span>((err, req)) =&gt; {
<span class="kw">return </span><span class="prelude-val">Ok</span>(req.error_response(err).map_into_right_body());
}
};
<span class="ident">service</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span>.<span class="ident">map</span>(<span class="op">|</span><span class="ident">res</span><span class="op">|</span> <span class="ident">res</span>.<span class="ident">map_into_left_body</span>())
service.call(req).<span class="kw">await</span>.map(|res| res.map_into_left_body())
})
}
}
<span class="kw">struct</span> <span class="ident">Extract</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> {
<span class="ident">req</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span><span class="op">&gt;</span>,
<span class="ident">fut</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">LocalBoxFuture</span><span class="op">&lt;</span><span class="lifetime">&#39;static</span>, <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">T</span>, <span class="ident">Error</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="ident">_extractor</span>: <span class="ident">PhantomData</span><span class="op">&lt;</span><span class="kw">fn</span>() -&gt; <span class="ident">T</span><span class="op">&gt;</span>,
<span class="kw">struct </span>Extract&lt;T&gt; {
req: <span class="prelude-ty">Option</span>&lt;ServiceRequest&gt;,
fut: <span class="prelude-ty">Option</span>&lt;LocalBoxFuture&lt;<span class="lifetime">&#39;static</span>, <span class="prelude-ty">Result</span>&lt;T, Error&gt;&gt;&gt;,
_extractor: PhantomData&lt;<span class="kw">fn</span>() -&gt; T&gt;,
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> <span class="ident">Extract</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> {
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">new</span>(<span class="ident">req</span>: <span class="ident">ServiceRequest</span>) -&gt; <span class="self">Self</span> {
<span class="ident">Extract</span> {
<span class="ident">req</span>: <span class="prelude-val">Some</span>(<span class="ident">req</span>),
<span class="ident">fut</span>: <span class="prelude-val">None</span>,
<span class="ident">_extractor</span>: <span class="ident">PhantomData</span>,
<span class="kw">impl</span>&lt;T&gt; Extract&lt;T&gt; {
<span class="kw">pub fn </span>new(req: ServiceRequest) -&gt; <span class="self">Self </span>{
Extract {
req: <span class="prelude-val">Some</span>(req),
fut: <span class="prelude-val">None</span>,
_extractor: PhantomData,
}
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span> <span class="ident">Future</span> <span class="kw">for</span> <span class="ident">Extract</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="ident">T</span>: <span class="ident">FromRequest</span>,
<span class="ident">T::Future</span>: <span class="lifetime">&#39;static</span>,
<span class="ident">T::Error</span>: <span class="lifetime">&#39;static</span>,
<span class="kw">impl</span>&lt;T&gt; Future <span class="kw">for </span>Extract&lt;T&gt;
<span class="kw">where
</span>T: FromRequest,
T::Future: <span class="lifetime">&#39;static</span>,
T::Error: <span class="lifetime">&#39;static</span>,
{
<span class="kw">type</span> <span class="ident">Output</span> <span class="op">=</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span>(<span class="ident">ServiceRequest</span>, <span class="ident">T</span>), (<span class="ident">Error</span>, <span class="ident">ServiceRequest</span>)<span class="op">&gt;</span>;
<span class="kw">type </span>Output = <span class="prelude-ty">Result</span>&lt;(ServiceRequest, T), (Error, ServiceRequest)&gt;;
<span class="kw">fn</span> <span class="ident">poll</span>(<span class="kw-2">mut</span> <span class="self">self</span>: <span class="ident">Pin</span><span class="op">&lt;</span><span class="kw-2">&amp;mut</span> <span class="self">Self</span><span class="op">&gt;</span>, <span class="ident">ctx</span>: <span class="kw-2">&amp;mut</span> <span class="ident">Context</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) -&gt; <span class="ident">Poll</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Output</span><span class="op">&gt;</span> {
<span class="kw">if</span> <span class="self">self</span>.<span class="ident">fut</span>.<span class="ident">is_none</span>() {
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="self">self</span>.<span class="ident">req</span>.<span class="ident">as_mut</span>().<span class="ident">expect</span>(<span class="string">&quot;Extract future was polled twice!&quot;</span>);
<span class="kw">let</span> <span class="ident">fut</span> <span class="op">=</span> <span class="ident">req</span>.<span class="ident">extract</span>::<span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>().<span class="ident">map_err</span>(<span class="ident">Into::into</span>);
<span class="self">self</span>.<span class="ident">fut</span> <span class="op">=</span> <span class="prelude-val">Some</span>(<span class="ident">Box::pin</span>(<span class="ident">fut</span>));
<span class="kw">fn </span>poll(<span class="kw-2">mut </span><span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, ctx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">&#39;_</span>&gt;) -&gt; Poll&lt;<span class="self">Self</span>::Output&gt; {
<span class="kw">if </span><span class="self">self</span>.fut.is_none() {
<span class="kw">let </span>req = <span class="self">self</span>.req.as_mut().expect(<span class="string">&quot;Extract future was polled twice!&quot;</span>);
<span class="kw">let </span>fut = req.extract::&lt;T&gt;().map_err(Into::into);
<span class="self">self</span>.fut = <span class="prelude-val">Some</span>(Box::pin(fut));
}
<span class="kw">let</span> <span class="ident">fut</span> <span class="op">=</span> <span class="self">self</span>
.<span class="ident">fut</span>
.<span class="ident">as_mut</span>()
.<span class="ident">expect</span>(<span class="string">&quot;Extraction future should be initialized at this point&quot;</span>);
<span class="kw">let </span>fut = <span class="self">self
</span>.fut
.as_mut()
.expect(<span class="string">&quot;Extraction future should be initialized at this point&quot;</span>);
<span class="kw">let</span> <span class="ident">credentials</span> <span class="op">=</span> <span class="macro">ready!</span>(<span class="ident">fut</span>.<span class="ident">as_mut</span>().<span class="ident">poll</span>(<span class="ident">ctx</span>)).<span class="ident">map_err</span>(<span class="op">|</span><span class="ident">err</span><span class="op">|</span> {
<span class="kw">let </span>credentials = <span class="macro">ready!</span>(fut.as_mut().poll(ctx)).map_err(|err| {
(
<span class="ident">err</span>,
<span class="comment">// returning request allows a proper error response to be created</span>
<span class="self">self</span>.<span class="ident">req</span>.<span class="ident">take</span>().<span class="ident">expect</span>(<span class="string">&quot;Extract future was polled twice!&quot;</span>),
err,
<span class="comment">// returning request allows a proper error response to be created
</span><span class="self">self</span>.req.take().expect(<span class="string">&quot;Extract future was polled twice!&quot;</span>),
)
})<span class="question-mark">?</span>;
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="self">self</span>.<span class="ident">req</span>.<span class="ident">take</span>().<span class="ident">expect</span>(<span class="string">&quot;Extract future was polled twice!&quot;</span>);
<span class="ident">Poll::Ready</span>(<span class="prelude-val">Ok</span>((<span class="ident">req</span>, <span class="ident">credentials</span>)))
<span class="kw">let </span>req = <span class="self">self</span>.req.take().expect(<span class="string">&quot;Extract future was polled twice!&quot;</span>);
Poll::Ready(<span class="prelude-val">Ok</span>((req, credentials)))
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="ident">actix_service::into_service</span>;
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">dev::Service</span>,
<span class="ident">error</span>::{<span class="self">self</span>, <span class="ident">ErrorForbidden</span>},
<span class="ident">http::StatusCode</span>,
<span class="ident">test::TestRequest</span>,
<span class="ident">web</span>, <span class="ident">App</span>, <span class="ident">HttpResponse</span>,
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>actix_service::into_service;
<span class="kw">use </span>actix_web::{
dev::Service,
error::{<span class="self">self</span>, ErrorForbidden},
http::StatusCode,
test::TestRequest,
web, App, HttpResponse,
};
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::extractors</span>::{<span class="ident">basic::BasicAuth</span>, <span class="ident">bearer::BearerAuth</span>};
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use </span><span class="kw">crate</span>::extractors::{basic::BasicAuth, bearer::BearerAuth};
<span class="doccomment">/// This is a test for https://github.com/actix/actix-extras/issues/10</span>
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_middleware_panic</span>() {
<span class="kw">let</span> <span class="ident">middleware</span> <span class="op">=</span> <span class="ident">AuthenticationMiddleware</span> {
<span class="ident">service</span>: <span class="ident">Rc::new</span>(<span class="ident">into_service</span>(<span class="op">|</span><span class="kw">_</span>: <span class="ident">ServiceRequest</span><span class="op">|</span> <span class="kw">async</span> <span class="kw">move</span> {
<span class="ident">actix_web::rt::time::sleep</span>(<span class="ident">std::time::Duration::from_secs</span>(<span class="number">1</span>)).<span class="kw">await</span>;
<span class="prelude-val">Err</span>::<span class="op">&lt;</span><span class="ident">ServiceResponse</span>, <span class="kw">_</span><span class="op">&gt;</span>(<span class="ident">error::ErrorBadRequest</span>(<span class="string">&quot;error&quot;</span>))
<span class="doccomment">/// This is a test for https://github.com/actix/actix-extras/issues/10
</span><span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_middleware_panic() {
<span class="kw">let </span>middleware = AuthenticationMiddleware {
service: Rc::new(into_service(|<span class="kw">_</span>: ServiceRequest| <span class="kw">async move </span>{
actix_web::rt::time::sleep(std::time::Duration::from_secs(<span class="number">1</span>)).<span class="kw">await</span>;
<span class="prelude-val">Err</span>::&lt;ServiceResponse, <span class="kw">_</span>&gt;(error::ErrorBadRequest(<span class="string">&quot;error&quot;</span>))
})),
<span class="ident">process_fn</span>: <span class="ident">Arc::new</span>(<span class="op">|</span><span class="ident">req</span>, <span class="kw">_</span>: <span class="ident">BearerAuth</span><span class="op">|</span> <span class="kw">async</span> { <span class="prelude-val">Ok</span>(<span class="ident">req</span>) }),
<span class="ident">_extractor</span>: <span class="ident">PhantomData</span>,
process_fn: Arc::new(|req, <span class="kw">_</span>: BearerAuth| <span class="kw">async </span>{ <span class="prelude-val">Ok</span>(req) }),
_extractor: PhantomData,
};
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::get</span>()
.<span class="ident">append_header</span>((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Bearer 1&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let </span>req = TestRequest::get()
.append_header((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Bearer 1&quot;</span>))
.to_srv_request();
<span class="kw">let</span> <span class="ident">f</span> <span class="op">=</span> <span class="ident">middleware</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span>;
<span class="kw">let </span>f = middleware.call(req).<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">_res</span> <span class="op">=</span> <span class="ident">futures_util::future::lazy</span>(<span class="op">|</span><span class="ident">cx</span><span class="op">|</span> <span class="ident">middleware</span>.<span class="ident">poll_ready</span>(<span class="ident">cx</span>)).<span class="kw">await</span>;
<span class="kw">let </span>_res = futures_util::future::lazy(|cx| middleware.poll_ready(cx)).<span class="kw">await</span>;
<span class="macro">assert!</span>(<span class="ident">f</span>.<span class="ident">is_err</span>());
<span class="macro">assert!</span>(f.is_err());
}
<span class="doccomment">/// This is a test for https://github.com/actix/actix-extras/issues/10</span>
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_middleware_panic_several_orders</span>() {
<span class="kw">let</span> <span class="ident">middleware</span> <span class="op">=</span> <span class="ident">AuthenticationMiddleware</span> {
<span class="ident">service</span>: <span class="ident">Rc::new</span>(<span class="ident">into_service</span>(<span class="op">|</span><span class="kw">_</span>: <span class="ident">ServiceRequest</span><span class="op">|</span> <span class="kw">async</span> <span class="kw">move</span> {
<span class="ident">actix_web::rt::time::sleep</span>(<span class="ident">std::time::Duration::from_secs</span>(<span class="number">1</span>)).<span class="kw">await</span>;
<span class="prelude-val">Err</span>::<span class="op">&lt;</span><span class="ident">ServiceResponse</span>, <span class="kw">_</span><span class="op">&gt;</span>(<span class="ident">error::ErrorBadRequest</span>(<span class="string">&quot;error&quot;</span>))
<span class="doccomment">/// This is a test for https://github.com/actix/actix-extras/issues/10
</span><span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_middleware_panic_several_orders() {
<span class="kw">let </span>middleware = AuthenticationMiddleware {
service: Rc::new(into_service(|<span class="kw">_</span>: ServiceRequest| <span class="kw">async move </span>{
actix_web::rt::time::sleep(std::time::Duration::from_secs(<span class="number">1</span>)).<span class="kw">await</span>;
<span class="prelude-val">Err</span>::&lt;ServiceResponse, <span class="kw">_</span>&gt;(error::ErrorBadRequest(<span class="string">&quot;error&quot;</span>))
})),
<span class="ident">process_fn</span>: <span class="ident">Arc::new</span>(<span class="op">|</span><span class="ident">req</span>, <span class="kw">_</span>: <span class="ident">BearerAuth</span><span class="op">|</span> <span class="kw">async</span> { <span class="prelude-val">Ok</span>(<span class="ident">req</span>) }),
<span class="ident">_extractor</span>: <span class="ident">PhantomData</span>,
process_fn: Arc::new(|req, <span class="kw">_</span>: BearerAuth| <span class="kw">async </span>{ <span class="prelude-val">Ok</span>(req) }),
_extractor: PhantomData,
};
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::get</span>()
.<span class="ident">append_header</span>((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Bearer 1&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let </span>req = TestRequest::get()
.append_header((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Bearer 1&quot;</span>))
.to_srv_request();
<span class="kw">let</span> <span class="ident">f1</span> <span class="op">=</span> <span class="ident">middleware</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span>;
<span class="kw">let </span>f1 = middleware.call(req).<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::get</span>()
.<span class="ident">append_header</span>((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Bearer 1&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let </span>req = TestRequest::get()
.append_header((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Bearer 1&quot;</span>))
.to_srv_request();
<span class="kw">let</span> <span class="ident">f2</span> <span class="op">=</span> <span class="ident">middleware</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span>;
<span class="kw">let </span>f2 = middleware.call(req).<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::get</span>()
.<span class="ident">append_header</span>((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Bearer 1&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let </span>req = TestRequest::get()
.append_header((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Bearer 1&quot;</span>))
.to_srv_request();
<span class="kw">let</span> <span class="ident">f3</span> <span class="op">=</span> <span class="ident">middleware</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span>;
<span class="kw">let </span>f3 = middleware.call(req).<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">_res</span> <span class="op">=</span> <span class="ident">futures_util::future::lazy</span>(<span class="op">|</span><span class="ident">cx</span><span class="op">|</span> <span class="ident">middleware</span>.<span class="ident">poll_ready</span>(<span class="ident">cx</span>)).<span class="kw">await</span>;
<span class="kw">let </span>_res = futures_util::future::lazy(|cx| middleware.poll_ready(cx)).<span class="kw">await</span>;
<span class="macro">assert!</span>(<span class="ident">f1</span>.<span class="ident">is_err</span>());
<span class="macro">assert!</span>(<span class="ident">f2</span>.<span class="ident">is_err</span>());
<span class="macro">assert!</span>(<span class="ident">f3</span>.<span class="ident">is_err</span>());
<span class="macro">assert!</span>(f1.is_err());
<span class="macro">assert!</span>(f2.is_err());
<span class="macro">assert!</span>(f3.is_err());
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_middleware_opt_extractor</span>() {
<span class="kw">let</span> <span class="ident">middleware</span> <span class="op">=</span> <span class="ident">AuthenticationMiddleware</span> {
<span class="ident">service</span>: <span class="ident">Rc::new</span>(<span class="ident">into_service</span>(<span class="op">|</span><span class="ident">req</span>: <span class="ident">ServiceRequest</span><span class="op">|</span> <span class="kw">async</span> <span class="kw">move</span> {
<span class="prelude-val">Ok</span>::<span class="op">&lt;</span><span class="ident">ServiceResponse</span>, <span class="kw">_</span><span class="op">&gt;</span>(<span class="ident">req</span>.<span class="ident">into_response</span>(<span class="ident">HttpResponse::Ok</span>().<span class="ident">finish</span>()))
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_middleware_opt_extractor() {
<span class="kw">let </span>middleware = AuthenticationMiddleware {
service: Rc::new(into_service(|req: ServiceRequest| <span class="kw">async move </span>{
<span class="prelude-val">Ok</span>::&lt;ServiceResponse, <span class="kw">_</span>&gt;(req.into_response(HttpResponse::Ok().finish()))
})),
<span class="ident">process_fn</span>: <span class="ident">Arc::new</span>(<span class="op">|</span><span class="ident">req</span>, <span class="ident">auth</span>: <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">BearerAuth</span><span class="op">&gt;</span><span class="op">|</span> {
<span class="macro">assert!</span>(<span class="ident">auth</span>.<span class="ident">is_none</span>());
<span class="kw">async</span> { <span class="prelude-val">Ok</span>(<span class="ident">req</span>) }
process_fn: Arc::new(|req, auth: <span class="prelude-ty">Option</span>&lt;BearerAuth&gt;| {
<span class="macro">assert!</span>(auth.is_none());
<span class="kw">async </span>{ <span class="prelude-val">Ok</span>(req) }
}),
<span class="ident">_extractor</span>: <span class="ident">PhantomData</span>,
_extractor: PhantomData,
};
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::get</span>()
.<span class="ident">append_header</span>((<span class="string">&quot;Authorization996&quot;</span>, <span class="string">&quot;Bearer 1&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let </span>req = TestRequest::get()
.append_header((<span class="string">&quot;Authorization996&quot;</span>, <span class="string">&quot;Bearer 1&quot;</span>))
.to_srv_request();
<span class="kw">let</span> <span class="ident">f</span> <span class="op">=</span> <span class="ident">middleware</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span>;
<span class="kw">let </span>f = middleware.call(req).<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">_res</span> <span class="op">=</span> <span class="ident">futures_util::future::lazy</span>(<span class="op">|</span><span class="ident">cx</span><span class="op">|</span> <span class="ident">middleware</span>.<span class="ident">poll_ready</span>(<span class="ident">cx</span>)).<span class="kw">await</span>;
<span class="kw">let </span>_res = futures_util::future::lazy(|cx| middleware.poll_ready(cx)).<span class="kw">await</span>;
<span class="macro">assert!</span>(<span class="ident">f</span>.<span class="ident">is_ok</span>());
<span class="macro">assert!</span>(f.is_ok());
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_middleware_res_extractor</span>() {
<span class="kw">let</span> <span class="ident">middleware</span> <span class="op">=</span> <span class="ident">AuthenticationMiddleware</span> {
<span class="ident">service</span>: <span class="ident">Rc::new</span>(<span class="ident">into_service</span>(<span class="op">|</span><span class="ident">req</span>: <span class="ident">ServiceRequest</span><span class="op">|</span> <span class="kw">async</span> <span class="kw">move</span> {
<span class="prelude-val">Ok</span>::<span class="op">&lt;</span><span class="ident">ServiceResponse</span>, <span class="kw">_</span><span class="op">&gt;</span>(<span class="ident">req</span>.<span class="ident">into_response</span>(<span class="ident">HttpResponse::Ok</span>().<span class="ident">finish</span>()))
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_middleware_res_extractor() {
<span class="kw">let </span>middleware = AuthenticationMiddleware {
service: Rc::new(into_service(|req: ServiceRequest| <span class="kw">async move </span>{
<span class="prelude-val">Ok</span>::&lt;ServiceResponse, <span class="kw">_</span>&gt;(req.into_response(HttpResponse::Ok().finish()))
})),
<span class="ident">process_fn</span>: <span class="ident">Arc::new</span>(
<span class="op">|</span><span class="ident">req</span>, <span class="ident">auth</span>: <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">BearerAuth</span>, <span class="op">&lt;</span><span class="ident">BearerAuth</span> <span class="kw">as</span> <span class="ident">FromRequest</span><span class="op">&gt;</span><span class="ident">::Error</span><span class="op">&gt;</span><span class="op">|</span> {
<span class="macro">assert!</span>(<span class="ident">auth</span>.<span class="ident">is_err</span>());
<span class="kw">async</span> { <span class="prelude-val">Ok</span>(<span class="ident">req</span>) }
process_fn: Arc::new(
|req, auth: <span class="prelude-ty">Result</span>&lt;BearerAuth, &lt;BearerAuth <span class="kw">as </span>FromRequest&gt;::Error&gt;| {
<span class="macro">assert!</span>(auth.is_err());
<span class="kw">async </span>{ <span class="prelude-val">Ok</span>(req) }
},
),
<span class="ident">_extractor</span>: <span class="ident">PhantomData</span>,
_extractor: PhantomData,
};
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">TestRequest::get</span>()
.<span class="ident">append_header</span>((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;BearerLOL&quot;</span>))
.<span class="ident">to_srv_request</span>();
<span class="kw">let </span>req = TestRequest::get()
.append_header((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;BearerLOL&quot;</span>))
.to_srv_request();
<span class="kw">let</span> <span class="ident">f</span> <span class="op">=</span> <span class="ident">middleware</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span>;
<span class="kw">let </span>f = middleware.call(req).<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">_res</span> <span class="op">=</span> <span class="ident">futures_util::future::lazy</span>(<span class="op">|</span><span class="ident">cx</span><span class="op">|</span> <span class="ident">middleware</span>.<span class="ident">poll_ready</span>(<span class="ident">cx</span>)).<span class="kw">await</span>;
<span class="kw">let </span>_res = futures_util::future::lazy(|cx| middleware.poll_ready(cx)).<span class="kw">await</span>;
<span class="macro">assert!</span>(<span class="ident">f</span>.<span class="ident">is_ok</span>());
<span class="macro">assert!</span>(f.is_ok());
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_middleware_works_with_app</span>() {
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">validator</span>(
<span class="ident">req</span>: <span class="ident">ServiceRequest</span>,
<span class="ident">_credentials</span>: <span class="ident">BasicAuth</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, (<span class="ident">actix_web::Error</span>, <span class="ident">ServiceRequest</span>)<span class="op">&gt;</span> {
<span class="prelude-val">Err</span>((<span class="ident">ErrorForbidden</span>(<span class="string">&quot;You are not welcome!&quot;</span>), <span class="ident">req</span>))
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_middleware_works_with_app() {
<span class="kw">async fn </span>validator(
req: ServiceRequest,
_credentials: BasicAuth,
) -&gt; <span class="prelude-ty">Result</span>&lt;ServiceRequest, (actix_web::Error, ServiceRequest)&gt; {
<span class="prelude-val">Err</span>((ErrorForbidden(<span class="string">&quot;You are not welcome!&quot;</span>), req))
}
<span class="kw">let</span> <span class="ident">middleware</span> <span class="op">=</span> <span class="ident">HttpAuthentication::basic</span>(<span class="ident">validator</span>);
<span class="kw">let </span>middleware = HttpAuthentication::basic(validator);
<span class="kw">let</span> <span class="ident">srv</span> <span class="op">=</span> <span class="ident">actix_web::test::init_service</span>(
<span class="ident">App::new</span>()
.<span class="ident">wrap</span>(<span class="ident">middleware</span>)
.<span class="ident">route</span>(<span class="string">&quot;/&quot;</span>, <span class="ident">web::get</span>().<span class="ident">to</span>(<span class="ident">HttpResponse::Ok</span>)),
<span class="kw">let </span>srv = actix_web::test::init_service(
App::new()
.wrap(middleware)
.route(<span class="string">&quot;/&quot;</span>, web::get().to(HttpResponse::Ok)),
)
.<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">actix_web::test::TestRequest::with_uri</span>(<span class="string">&quot;/&quot;</span>)
.<span class="ident">append_header</span>((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Basic DontCare&quot;</span>))
.<span class="ident">to_request</span>();
<span class="kw">let </span>req = actix_web::test::TestRequest::with_uri(<span class="string">&quot;/&quot;</span>)
.append_header((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Basic DontCare&quot;</span>))
.to_request();
<span class="kw">let</span> <span class="ident">resp</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">resp</span>.<span class="ident">status</span>(), <span class="ident">StatusCode::UNAUTHORIZED</span>);
<span class="kw">let </span>resp = srv.call(req).<span class="kw">await</span>.unwrap();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::UNAUTHORIZED);
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test_middleware_works_with_scope</span>() {
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">validator</span>(
<span class="ident">req</span>: <span class="ident">ServiceRequest</span>,
<span class="ident">_credentials</span>: <span class="ident">BasicAuth</span>,
) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">ServiceRequest</span>, (<span class="ident">actix_web::Error</span>, <span class="ident">ServiceRequest</span>)<span class="op">&gt;</span> {
<span class="prelude-val">Err</span>((<span class="ident">ErrorForbidden</span>(<span class="string">&quot;You are not welcome!&quot;</span>), <span class="ident">req</span>))
<span class="attribute">#[actix_web::test]
</span><span class="kw">async fn </span>test_middleware_works_with_scope() {
<span class="kw">async fn </span>validator(
req: ServiceRequest,
_credentials: BasicAuth,
) -&gt; <span class="prelude-ty">Result</span>&lt;ServiceRequest, (actix_web::Error, ServiceRequest)&gt; {
<span class="prelude-val">Err</span>((ErrorForbidden(<span class="string">&quot;You are not welcome!&quot;</span>), req))
}
<span class="kw">let</span> <span class="ident">middleware</span> <span class="op">=</span> <span class="ident">actix_web::middleware::Compat::new</span>(<span class="ident">HttpAuthentication::basic</span>(<span class="ident">validator</span>));
<span class="kw">let </span>middleware = actix_web::middleware::Compat::new(HttpAuthentication::basic(validator));
<span class="kw">let</span> <span class="ident">srv</span> <span class="op">=</span> <span class="ident">actix_web::test::init_service</span>(
<span class="ident">App::new</span>().<span class="ident">service</span>(
<span class="ident">web::scope</span>(<span class="string">&quot;/&quot;</span>)
.<span class="ident">wrap</span>(<span class="ident">middleware</span>)
.<span class="ident">route</span>(<span class="string">&quot;/&quot;</span>, <span class="ident">web::get</span>().<span class="ident">to</span>(<span class="ident">HttpResponse::Ok</span>)),
<span class="kw">let </span>srv = actix_web::test::init_service(
App::new().service(
web::scope(<span class="string">&quot;/&quot;</span>)
.wrap(middleware)
.route(<span class="string">&quot;/&quot;</span>, web::get().to(HttpResponse::Ok)),
),
)
.<span class="kw">await</span>;
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">actix_web::test::TestRequest::with_uri</span>(<span class="string">&quot;/&quot;</span>)
.<span class="ident">append_header</span>((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Basic DontCare&quot;</span>))
.<span class="ident">to_request</span>();
<span class="kw">let </span>req = actix_web::test::TestRequest::with_uri(<span class="string">&quot;/&quot;</span>)
.append_header((<span class="string">&quot;Authorization&quot;</span>, <span class="string">&quot;Basic DontCare&quot;</span>))
.to_request();
<span class="kw">let</span> <span class="ident">resp</span> <span class="op">=</span> <span class="ident">srv</span>.<span class="ident">call</span>(<span class="ident">req</span>).<span class="kw">await</span>.<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">resp</span>.<span class="ident">status</span>(), <span class="ident">StatusCode::UNAUTHORIZED</span>);
<span class="kw">let </span>resp = srv.call(req).<span class="kw">await</span>.unwrap();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::UNAUTHORIZED);
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>

View File

@@ -110,117 +110,117 @@
<span id="110">110</span>
<span id="111">111</span>
<span id="112">112</span>
</pre><pre class="rust"><code><span class="kw">use</span> <span class="ident">std::str</span>;
</pre><pre class="rust"><code><span class="kw">use </span>std::str;
<span class="kw">use</span> <span class="ident">actix_web::web::BytesMut</span>;
<span class="kw">use </span>actix_web::web::BytesMut;
<span class="kw">enum</span> <span class="ident">State</span> {
<span class="ident">YieldStr</span>,
<span class="ident">YieldQuote</span>,
<span class="kw">enum </span>State {
YieldStr,
YieldQuote,
}
<span class="kw">struct</span> <span class="ident">Quoted</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span> {
<span class="ident">inner</span>: <span class="ident">::std::iter::Peekable</span><span class="op">&lt;</span><span class="ident">str::Split</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span>, <span class="ident">char</span><span class="op">&gt;</span><span class="op">&gt;</span>,
<span class="ident">state</span>: <span class="ident">State</span>,
<span class="kw">struct </span>Quoted&lt;<span class="lifetime">&#39;a</span>&gt; {
inner: ::std::iter::Peekable&lt;str::Split&lt;<span class="lifetime">&#39;a</span>, char&gt;&gt;,
state: State,
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span> <span class="ident">Quoted</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span> {
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">new</span>(<span class="ident">s</span>: <span class="kw-2">&amp;</span><span class="lifetime">&#39;a</span> <span class="ident">str</span>) -&gt; <span class="ident">Quoted</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span> {
<span class="ident">Quoted</span> {
<span class="ident">inner</span>: <span class="ident">s</span>.<span class="ident">split</span>(<span class="string">&#39;&quot;&#39;</span>).<span class="ident">peekable</span>(),
<span class="ident">state</span>: <span class="ident">State::YieldStr</span>,
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;a</span>&gt; Quoted&lt;<span class="lifetime">&#39;a</span>&gt; {
<span class="kw">pub fn </span>new(s: <span class="kw-2">&amp;</span><span class="lifetime">&#39;a </span>str) -&gt; Quoted&lt;<span class="lifetime">&#39;_</span>&gt; {
Quoted {
inner: s.split(<span class="string">&#39;&quot;&#39;</span>).peekable(),
state: State::YieldStr,
}
}
}
<span class="kw">impl</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span> <span class="ident">Iterator</span> <span class="kw">for</span> <span class="ident">Quoted</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span> {
<span class="kw">type</span> <span class="ident">Item</span> <span class="op">=</span> <span class="kw-2">&amp;</span><span class="lifetime">&#39;a</span> <span class="ident">str</span>;
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;a</span>&gt; Iterator <span class="kw">for </span>Quoted&lt;<span class="lifetime">&#39;a</span>&gt; {
<span class="kw">type </span>Item = <span class="kw-2">&amp;</span><span class="lifetime">&#39;a </span>str;
<span class="kw">fn</span> <span class="ident">next</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident"><span class="self">Self</span>::Item</span><span class="op">&gt;</span> {
<span class="kw">match</span> <span class="self">self</span>.<span class="ident">state</span> {
<span class="ident">State::YieldStr</span> =&gt; <span class="kw">match</span> <span class="self">self</span>.<span class="ident">inner</span>.<span class="ident">next</span>() {
<span class="prelude-val">Some</span>(<span class="ident">val</span>) =&gt; {
<span class="self">self</span>.<span class="ident">state</span> <span class="op">=</span> <span class="ident">State::YieldQuote</span>;
<span class="prelude-val">Some</span>(<span class="ident">val</span>)
<span class="kw">fn </span>next(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt; {
<span class="kw">match </span><span class="self">self</span>.state {
State::YieldStr =&gt; <span class="kw">match </span><span class="self">self</span>.inner.next() {
<span class="prelude-val">Some</span>(val) =&gt; {
<span class="self">self</span>.state = State::YieldQuote;
<span class="prelude-val">Some</span>(val)
}
<span class="prelude-val">None</span> =&gt; <span class="prelude-val">None</span>,
<span class="prelude-val">None </span>=&gt; <span class="prelude-val">None</span>,
},
<span class="ident">State::YieldQuote</span> =&gt; <span class="kw">match</span> <span class="self">self</span>.<span class="ident">inner</span>.<span class="ident">peek</span>() {
State::YieldQuote =&gt; <span class="kw">match </span><span class="self">self</span>.inner.peek() {
<span class="prelude-val">Some</span>(<span class="kw">_</span>) =&gt; {
<span class="self">self</span>.<span class="ident">state</span> <span class="op">=</span> <span class="ident">State::YieldStr</span>;
<span class="self">self</span>.state = State::YieldStr;
<span class="prelude-val">Some</span>(<span class="string">&quot;\\\&quot;&quot;</span>)
}
<span class="prelude-val">None</span> =&gt; <span class="prelude-val">None</span>,
<span class="prelude-val">None </span>=&gt; <span class="prelude-val">None</span>,
},
}
}
}
<span class="doccomment">/// Escapes the quotes in `val`.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">put_quoted</span>(<span class="ident">buf</span>: <span class="kw-2">&amp;mut</span> <span class="ident">BytesMut</span>, <span class="ident">val</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) {
<span class="kw">for</span> <span class="ident">part</span> <span class="kw">in</span> <span class="ident">Quoted::new</span>(<span class="ident">val</span>) {
<span class="ident">buf</span>.<span class="ident">extend_from_slice</span>(<span class="ident">part</span>.<span class="ident">as_bytes</span>());
<span class="doccomment">/// Escapes the quotes in `val`.
</span><span class="kw">pub fn </span>put_quoted(buf: <span class="kw-2">&amp;mut </span>BytesMut, val: <span class="kw-2">&amp;</span>str) {
<span class="kw">for </span>part <span class="kw">in </span>Quoted::new(val) {
buf.extend_from_slice(part.as_bytes());
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="ident">std::str</span>;
<span class="attribute">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::str;
<span class="kw">use</span> <span class="ident">actix_web::web::BytesMut</span>;
<span class="kw">use </span>actix_web::web::BytesMut;
<span class="kw">use</span> <span class="ident"><span class="kw">super</span>::put_quoted</span>;
<span class="kw">use </span><span class="kw">super</span>::put_quoted;
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_quote_str</span>() {
<span class="kw">let</span> <span class="ident">input</span> <span class="op">=</span> <span class="string">&quot;a \&quot;quoted\&quot; string&quot;</span>;
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">output</span> <span class="op">=</span> <span class="ident">BytesMut::new</span>();
<span class="ident">put_quoted</span>(<span class="kw-2">&amp;mut</span> <span class="ident">output</span>, <span class="ident">input</span>);
<span class="kw">let</span> <span class="ident">result</span> <span class="op">=</span> <span class="ident">str::from_utf8</span>(<span class="kw-2">&amp;</span><span class="ident">output</span>).<span class="ident">unwrap</span>();
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_quote_str() {
<span class="kw">let </span>input = <span class="string">&quot;a \&quot;quoted\&quot; string&quot;</span>;
<span class="kw">let </span><span class="kw-2">mut </span>output = BytesMut::new();
put_quoted(<span class="kw-2">&amp;mut </span>output, input);
<span class="kw">let </span>result = str::from_utf8(<span class="kw-2">&amp;</span>output).unwrap();
<span class="macro">assert_eq!</span>(<span class="ident">result</span>, <span class="string">&quot;a \\\&quot;quoted\\\&quot; string&quot;</span>);
<span class="macro">assert_eq!</span>(result, <span class="string">&quot;a \\\&quot;quoted\\\&quot; string&quot;</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_without_quotes</span>() {
<span class="kw">let</span> <span class="ident">input</span> <span class="op">=</span> <span class="string">&quot;non-quoted string&quot;</span>;
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">output</span> <span class="op">=</span> <span class="ident">BytesMut::new</span>();
<span class="ident">put_quoted</span>(<span class="kw-2">&amp;mut</span> <span class="ident">output</span>, <span class="ident">input</span>);
<span class="kw">let</span> <span class="ident">result</span> <span class="op">=</span> <span class="ident">str::from_utf8</span>(<span class="kw-2">&amp;</span><span class="ident">output</span>).<span class="ident">unwrap</span>();
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_without_quotes() {
<span class="kw">let </span>input = <span class="string">&quot;non-quoted string&quot;</span>;
<span class="kw">let </span><span class="kw-2">mut </span>output = BytesMut::new();
put_quoted(<span class="kw-2">&amp;mut </span>output, input);
<span class="kw">let </span>result = str::from_utf8(<span class="kw-2">&amp;</span>output).unwrap();
<span class="macro">assert_eq!</span>(<span class="ident">result</span>, <span class="string">&quot;non-quoted string&quot;</span>);
<span class="macro">assert_eq!</span>(result, <span class="string">&quot;non-quoted string&quot;</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_starts_with_quote</span>() {
<span class="kw">let</span> <span class="ident">input</span> <span class="op">=</span> <span class="string">&quot;\&quot;first-quoted string&quot;</span>;
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">output</span> <span class="op">=</span> <span class="ident">BytesMut::new</span>();
<span class="ident">put_quoted</span>(<span class="kw-2">&amp;mut</span> <span class="ident">output</span>, <span class="ident">input</span>);
<span class="kw">let</span> <span class="ident">result</span> <span class="op">=</span> <span class="ident">str::from_utf8</span>(<span class="kw-2">&amp;</span><span class="ident">output</span>).<span class="ident">unwrap</span>();
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_starts_with_quote() {
<span class="kw">let </span>input = <span class="string">&quot;\&quot;first-quoted string&quot;</span>;
<span class="kw">let </span><span class="kw-2">mut </span>output = BytesMut::new();
put_quoted(<span class="kw-2">&amp;mut </span>output, input);
<span class="kw">let </span>result = str::from_utf8(<span class="kw-2">&amp;</span>output).unwrap();
<span class="macro">assert_eq!</span>(<span class="ident">result</span>, <span class="string">&quot;\\\&quot;first-quoted string&quot;</span>);
<span class="macro">assert_eq!</span>(result, <span class="string">&quot;\\\&quot;first-quoted string&quot;</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_ends_with_quote</span>() {
<span class="kw">let</span> <span class="ident">input</span> <span class="op">=</span> <span class="string">&quot;last-quoted string\&quot;&quot;</span>;
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">output</span> <span class="op">=</span> <span class="ident">BytesMut::new</span>();
<span class="ident">put_quoted</span>(<span class="kw-2">&amp;mut</span> <span class="ident">output</span>, <span class="ident">input</span>);
<span class="kw">let</span> <span class="ident">result</span> <span class="op">=</span> <span class="ident">str::from_utf8</span>(<span class="kw-2">&amp;</span><span class="ident">output</span>).<span class="ident">unwrap</span>();
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_ends_with_quote() {
<span class="kw">let </span>input = <span class="string">&quot;last-quoted string\&quot;&quot;</span>;
<span class="kw">let </span><span class="kw-2">mut </span>output = BytesMut::new();
put_quoted(<span class="kw-2">&amp;mut </span>output, input);
<span class="kw">let </span>result = str::from_utf8(<span class="kw-2">&amp;</span>output).unwrap();
<span class="macro">assert_eq!</span>(<span class="ident">result</span>, <span class="string">&quot;last-quoted string\\\&quot;&quot;</span>);
<span class="macro">assert_eq!</span>(result, <span class="string">&quot;last-quoted string\\\&quot;&quot;</span>);
}
<span class="attribute">#[<span class="ident">test</span>]</span>
<span class="kw">fn</span> <span class="ident">test_double_quote</span>() {
<span class="kw">let</span> <span class="ident">input</span> <span class="op">=</span> <span class="string">&quot;quote\&quot;\&quot;string&quot;</span>;
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">output</span> <span class="op">=</span> <span class="ident">BytesMut::new</span>();
<span class="ident">put_quoted</span>(<span class="kw-2">&amp;mut</span> <span class="ident">output</span>, <span class="ident">input</span>);
<span class="kw">let</span> <span class="ident">result</span> <span class="op">=</span> <span class="ident">str::from_utf8</span>(<span class="kw-2">&amp;</span><span class="ident">output</span>).<span class="ident">unwrap</span>();
<span class="attribute">#[test]
</span><span class="kw">fn </span>test_double_quote() {
<span class="kw">let </span>input = <span class="string">&quot;quote\&quot;\&quot;string&quot;</span>;
<span class="kw">let </span><span class="kw-2">mut </span>output = BytesMut::new();
put_quoted(<span class="kw-2">&amp;mut </span>output, input);
<span class="kw">let </span>result = str::from_utf8(<span class="kw-2">&amp;</span>output).unwrap();
<span class="macro">assert_eq!</span>(<span class="ident">result</span>, <span class="string">&quot;quote\\\&quot;\\\&quot;string&quot;</span>);
<span class="macro">assert_eq!</span>(result, <span class="string">&quot;quote\\\&quot;\\\&quot;string&quot;</span>);
}
}
</code></pre></div>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (34a6cae28 2022-08-09)" ></div></body></html>
</section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_web_httpauth" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.65.0-nightly (060e47f74 2022-08-23)" ></div></body></html>