1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-06-30 16:34:26 +02:00

Deploying to gh-pages from @ actix/actix-web@26efa64278 🚀

This commit is contained in:
github-merge-queue[bot]
2024-05-27 01:16:31 +00:00
commit a33fe13cd1
1715 changed files with 215638 additions and 0 deletions

View File

@ -0,0 +1,435 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-files/src/chunked.rs`."><title>chunked.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_files" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
cmp, fmt,
future::Future,
io,
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>actix_web::{error::Error, web::Bytes};
<span class="attr">#[cfg(feature = <span class="string">"experimental-io-uring"</span>)]
</span><span class="kw">use </span>bytes::BytesMut;
<span class="kw">use </span>futures_core::{ready, Stream};
<span class="kw">use </span>pin_project_lite::pin_project;
<span class="kw">use </span><span class="kw">super</span>::named::File;
<span class="macro">pin_project!</span> {
<span class="doccomment">/// Adapter to read a `std::file::File` in chunks.
</span><span class="attr">#[doc(hidden)]
</span><span class="kw">pub struct </span>ChunkedReadFile&lt;F, Fut&gt; {
size: u64,
offset: u64,
<span class="attr">#[pin]
</span>state: ChunkedReadFileState&lt;Fut&gt;,
counter: u64,
callback: F,
}
}
<span class="attr">#[cfg(not(feature = <span class="string">"experimental-io-uring"</span>))]
</span><span class="macro">pin_project!</span> {
<span class="attr">#[project = ChunkedReadFileStateProj]
#[project_replace = ChunkedReadFileStateProjReplace]
</span><span class="kw">enum </span>ChunkedReadFileState&lt;Fut&gt; {
File { file: <span class="prelude-ty">Option</span>&lt;File&gt;, },
Future { <span class="attr">#[pin] </span>fut: Fut },
}
}
<span class="attr">#[cfg(feature = <span class="string">"experimental-io-uring"</span>)]
</span><span class="macro">pin_project!</span> {
<span class="attr">#[project = ChunkedReadFileStateProj]
#[project_replace = ChunkedReadFileStateProjReplace]
</span><span class="kw">enum </span>ChunkedReadFileState&lt;Fut&gt; {
File { file: <span class="prelude-ty">Option</span>&lt;(File, BytesMut)&gt; },
Future { <span class="attr">#[pin] </span>fut: Fut },
}
}
<span class="kw">impl</span>&lt;F, Fut&gt; fmt::Debug <span class="kw">for </span>ChunkedReadFile&lt;F, Fut&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">'_</span>&gt;) -&gt; fmt::Result {
f.write_str(<span class="string">"ChunkedReadFile"</span>)
}
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new_chunked_read(
size: u64,
offset: u64,
file: File,
) -&gt; <span class="kw">impl </span>Stream&lt;Item = <span class="prelude-ty">Result</span>&lt;Bytes, Error&gt;&gt; {
ChunkedReadFile {
size,
offset,
<span class="attr">#[cfg(not(feature = <span class="string">"experimental-io-uring"</span>))]
</span>state: ChunkedReadFileState::File { file: <span class="prelude-val">Some</span>(file) },
<span class="attr">#[cfg(feature = <span class="string">"experimental-io-uring"</span>)]
</span>state: ChunkedReadFileState::File {
file: <span class="prelude-val">Some</span>((file, BytesMut::new())),
},
counter: <span class="number">0</span>,
callback: chunked_read_file_callback,
}
}
<span class="attr">#[cfg(not(feature = <span class="string">"experimental-io-uring"</span>))]
</span><span class="kw">async fn </span>chunked_read_file_callback(
<span class="kw-2">mut </span>file: File,
offset: u64,
max_bytes: usize,
) -&gt; <span class="prelude-ty">Result</span>&lt;(File, Bytes), Error&gt; {
<span class="kw">use </span>io::{Read <span class="kw">as _</span>, Seek <span class="kw">as _</span>};
<span class="kw">let </span>res = actix_web::web::block(<span class="kw">move </span>|| {
<span class="kw">let </span><span class="kw-2">mut </span>buf = Vec::with_capacity(max_bytes);
file.seek(io::SeekFrom::Start(offset))<span class="question-mark">?</span>;
<span class="kw">let </span>n_bytes = file.by_ref().take(max_bytes <span class="kw">as </span>u64).read_to_end(<span class="kw-2">&amp;mut </span>buf)<span class="question-mark">?</span>;
<span class="kw">if </span>n_bytes == <span class="number">0 </span>{
<span class="prelude-val">Err</span>(io::Error::from(io::ErrorKind::UnexpectedEof))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>((file, Bytes::from(buf)))
}
})
.<span class="kw">await</span><span class="question-mark">??</span>;
<span class="prelude-val">Ok</span>(res)
}
<span class="attr">#[cfg(feature = <span class="string">"experimental-io-uring"</span>)]
</span><span class="kw">async fn </span>chunked_read_file_callback(
file: File,
offset: u64,
max_bytes: usize,
<span class="kw-2">mut </span>bytes_mut: BytesMut,
) -&gt; io::Result&lt;(File, Bytes, BytesMut)&gt; {
bytes_mut.reserve(max_bytes);
<span class="kw">let </span>(res, <span class="kw-2">mut </span>bytes_mut) = file.read_at(bytes_mut, offset).<span class="kw">await</span>;
<span class="kw">let </span>n_bytes = res<span class="question-mark">?</span>;
<span class="kw">if </span>n_bytes == <span class="number">0 </span>{
<span class="kw">return </span><span class="prelude-val">Err</span>(io::ErrorKind::UnexpectedEof.into());
}
<span class="kw">let </span>bytes = bytes_mut.split_to(n_bytes).freeze();
<span class="prelude-val">Ok</span>((file, bytes, bytes_mut))
}
<span class="attr">#[cfg(feature = <span class="string">"experimental-io-uring"</span>)]
</span><span class="kw">impl</span>&lt;F, Fut&gt; Stream <span class="kw">for </span>ChunkedReadFile&lt;F, Fut&gt;
<span class="kw">where
</span>F: Fn(File, u64, usize, BytesMut) -&gt; Fut,
Fut: Future&lt;Output = io::Result&lt;(File, Bytes, BytesMut)&gt;&gt;,
{
<span class="kw">type </span>Item = <span class="prelude-ty">Result</span>&lt;Bytes, Error&gt;;
<span class="kw">fn </span>poll_next(<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;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt;&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>this = <span class="self">self</span>.as_mut().project();
<span class="kw">match </span>this.state.as_mut().project() {
ChunkedReadFileStateProj::File { file } =&gt; {
<span class="kw">let </span>size = <span class="kw-2">*</span>this.size;
<span class="kw">let </span>offset = <span class="kw-2">*</span>this.offset;
<span class="kw">let </span>counter = <span class="kw-2">*</span>this.counter;
<span class="kw">if </span>size == counter {
Poll::Ready(<span class="prelude-val">None</span>)
} <span class="kw">else </span>{
<span class="kw">let </span>max_bytes = cmp::min(size.saturating_sub(counter), <span class="number">65_536</span>) <span class="kw">as </span>usize;
<span class="kw">let </span>(file, bytes_mut) = file
.take()
.expect(<span class="string">"ChunkedReadFile polled after completion"</span>);
<span class="kw">let </span>fut = (this.callback)(file, offset, max_bytes, bytes_mut);
this.state
.project_replace(ChunkedReadFileState::Future { fut });
<span class="self">self</span>.poll_next(cx)
}
}
ChunkedReadFileStateProj::Future { fut } =&gt; {
<span class="kw">let </span>(file, bytes, bytes_mut) = <span class="macro">ready!</span>(fut.poll(cx))<span class="question-mark">?</span>;
this.state.project_replace(ChunkedReadFileState::File {
file: <span class="prelude-val">Some</span>((file, bytes_mut)),
});
<span class="kw-2">*</span>this.offset += bytes.len() <span class="kw">as </span>u64;
<span class="kw-2">*</span>this.counter += bytes.len() <span class="kw">as </span>u64;
Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(bytes)))
}
}
}
}
<span class="attr">#[cfg(not(feature = <span class="string">"experimental-io-uring"</span>))]
</span><span class="kw">impl</span>&lt;F, Fut&gt; Stream <span class="kw">for </span>ChunkedReadFile&lt;F, Fut&gt;
<span class="kw">where
</span>F: Fn(File, u64, usize) -&gt; Fut,
Fut: Future&lt;Output = <span class="prelude-ty">Result</span>&lt;(File, Bytes), Error&gt;&gt;,
{
<span class="kw">type </span>Item = <span class="prelude-ty">Result</span>&lt;Bytes, Error&gt;;
<span class="kw">fn </span>poll_next(<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;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt;&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>this = <span class="self">self</span>.as_mut().project();
<span class="kw">match </span>this.state.as_mut().project() {
ChunkedReadFileStateProj::File { file } =&gt; {
<span class="kw">let </span>size = <span class="kw-2">*</span>this.size;
<span class="kw">let </span>offset = <span class="kw-2">*</span>this.offset;
<span class="kw">let </span>counter = <span class="kw-2">*</span>this.counter;
<span class="kw">if </span>size == counter {
Poll::Ready(<span class="prelude-val">None</span>)
} <span class="kw">else </span>{
<span class="kw">let </span>max_bytes = cmp::min(size.saturating_sub(counter), <span class="number">65_536</span>) <span class="kw">as </span>usize;
<span class="kw">let </span>file = file
.take()
.expect(<span class="string">"ChunkedReadFile polled after completion"</span>);
<span class="kw">let </span>fut = (this.callback)(file, offset, max_bytes);
this.state
.project_replace(ChunkedReadFileState::Future { fut });
<span class="self">self</span>.poll_next(cx)
}
}
ChunkedReadFileStateProj::Future { fut } =&gt; {
<span class="kw">let </span>(file, bytes) = <span class="macro">ready!</span>(fut.poll(cx))<span class="question-mark">?</span>;
this.state
.project_replace(ChunkedReadFileState::File { file: <span class="prelude-val">Some</span>(file) });
<span class="kw-2">*</span>this.offset += bytes.len() <span class="kw">as </span>u64;
<span class="kw-2">*</span>this.counter += bytes.len() <span class="kw">as </span>u64;
Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(bytes)))
}
}
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,253 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-files/src/directory.rs`."><title>directory.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_files" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
fmt::Write,
fs::DirEntry,
io,
path::{Path, PathBuf},
};
<span class="kw">use </span>actix_web::{dev::ServiceResponse, HttpRequest, HttpResponse};
<span class="kw">use </span>percent_encoding::{utf8_percent_encode, CONTROLS};
<span class="kw">use </span>v_htmlescape::escape <span class="kw">as </span>escape_html_entity;
<span class="doccomment">/// A directory; responds with the generated directory listing.
</span><span class="attr">#[derive(Debug)]
</span><span class="kw">pub struct </span>Directory {
<span class="doccomment">/// Base directory.
</span><span class="kw">pub </span>base: PathBuf,
<span class="doccomment">/// Path of subdirectory to generate listing for.
</span><span class="kw">pub </span>path: PathBuf,
}
<span class="kw">impl </span>Directory {
<span class="doccomment">/// Create a new directory
</span><span class="kw">pub fn </span>new(base: PathBuf, path: PathBuf) -&gt; Directory {
Directory { base, path }
}
<span class="doccomment">/// Is this entry visible from this directory?
</span><span class="kw">pub fn </span>is_visible(<span class="kw-2">&amp;</span><span class="self">self</span>, entry: <span class="kw-2">&amp;</span>io::Result&lt;DirEntry&gt;) -&gt; bool {
<span class="kw">if let </span><span class="prelude-val">Ok</span>(<span class="kw-2">ref </span>entry) = <span class="kw-2">*</span>entry {
<span class="kw">if let </span><span class="prelude-val">Some</span>(name) = entry.file_name().to_str() {
<span class="kw">if </span>name.starts_with(<span class="string">'.'</span>) {
<span class="kw">return </span><span class="bool-val">false</span>;
}
}
<span class="kw">if let </span><span class="prelude-val">Ok</span>(<span class="kw-2">ref </span>md) = entry.metadata() {
<span class="kw">let </span>ft = md.file_type();
<span class="kw">return </span>ft.is_dir() || ft.is_file() || ft.is_symlink();
}
}
<span class="bool-val">false
</span>}
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">type </span>DirectoryRenderer =
<span class="kw">dyn </span>Fn(<span class="kw-2">&amp;</span>Directory, <span class="kw-2">&amp;</span>HttpRequest) -&gt; <span class="prelude-ty">Result</span>&lt;ServiceResponse, io::Error&gt;;
<span class="doccomment">/// Returns percent encoded file URL path.
</span><span class="macro">macro_rules!</span> encode_file_url {
(<span class="macro-nonterminal">$path</span>:ident) =&gt; {
utf8_percent_encode(<span class="kw-2">&amp;</span><span class="macro-nonterminal">$path</span>, CONTROLS)
};
}
<span class="doccomment">/// Returns HTML entity encoded formatter.
///
/// ```plain
/// " =&gt; &amp;quot;
/// &amp; =&gt; &amp;amp;
/// ' =&gt; &amp;#x27;
/// &lt; =&gt; &amp;lt;
/// &gt; =&gt; &amp;gt;
/// / =&gt; &amp;#x2f;
/// ```
</span><span class="macro">macro_rules!</span> encode_file_name {
(<span class="macro-nonterminal">$entry</span>:ident) =&gt; {
escape_html_entity(<span class="kw-2">&amp;</span><span class="macro-nonterminal">$entry</span>.file_name().to_string_lossy())
};
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>directory_listing(
dir: <span class="kw-2">&amp;</span>Directory,
req: <span class="kw-2">&amp;</span>HttpRequest,
) -&gt; <span class="prelude-ty">Result</span>&lt;ServiceResponse, io::Error&gt; {
<span class="kw">let </span>index_of = <span class="macro">format!</span>(<span class="string">"Index of {}"</span>, req.path());
<span class="kw">let </span><span class="kw-2">mut </span>body = String::new();
<span class="kw">let </span>base = Path::new(req.path());
<span class="kw">for </span>entry <span class="kw">in </span>dir.path.read_dir()<span class="question-mark">? </span>{
<span class="kw">if </span>dir.is_visible(<span class="kw-2">&amp;</span>entry) {
<span class="kw">let </span>entry = entry.unwrap();
<span class="kw">let </span>p = <span class="kw">match </span>entry.path().strip_prefix(<span class="kw-2">&amp;</span>dir.path) {
<span class="prelude-val">Ok</span>(p) <span class="kw">if </span><span class="macro">cfg!</span>(windows) =&gt; base.join(p).to_string_lossy().replace(<span class="string">'\\'</span>, <span class="string">"/"</span>),
<span class="prelude-val">Ok</span>(p) =&gt; base.join(p).to_string_lossy().into_owned(),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="kw">continue</span>,
};
<span class="comment">// if file is a directory, add '/' to the end of the name
</span><span class="kw">if let </span><span class="prelude-val">Ok</span>(metadata) = entry.metadata() {
<span class="kw">if </span>metadata.is_dir() {
<span class="kw">let _ </span>= <span class="macro">write!</span>(
body,
<span class="string">"&lt;li&gt;&lt;a href=\"{}\"&gt;{}/&lt;/a&gt;&lt;/li&gt;"</span>,
<span class="macro">encode_file_url!</span>(p),
<span class="macro">encode_file_name!</span>(entry),
);
} <span class="kw">else </span>{
<span class="kw">let _ </span>= <span class="macro">write!</span>(
body,
<span class="string">"&lt;li&gt;&lt;a href=\"{}\"&gt;{}&lt;/a&gt;&lt;/li&gt;"</span>,
<span class="macro">encode_file_url!</span>(p),
<span class="macro">encode_file_name!</span>(entry),
);
}
} <span class="kw">else </span>{
<span class="kw">continue</span>;
}
}
}
<span class="kw">let </span>html = <span class="macro">format!</span>(
<span class="string">"&lt;html&gt;\
&lt;head&gt;&lt;title&gt;{}&lt;/title&gt;&lt;/head&gt;\
&lt;body&gt;&lt;h1&gt;{}&lt;/h1&gt;\
&lt;ul&gt;\
{}\
&lt;/ul&gt;&lt;/body&gt;\n&lt;/html&gt;"</span>,
index_of, index_of, body
);
<span class="prelude-val">Ok</span>(ServiceResponse::new(
req.clone(),
HttpResponse::Ok()
.content_type(<span class="string">"text/html; charset=utf-8"</span>)
.body(html),
))
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,105 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-files/src/encoding.rs`."><title>encoding.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_files" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>mime::Mime;
<span class="doccomment">/// Transforms MIME `text/*` types into their UTF-8 equivalent, if supported.
///
/// MIME types that are converted
/// - application/javascript
/// - text/html
/// - text/css
/// - text/plain
/// - text/csv
/// - text/tab-separated-values
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>equiv_utf8_text(ct: Mime) -&gt; Mime {
<span class="comment">// use (roughly) order of file-type popularity for a web server
</span><span class="kw">if </span>ct == mime::APPLICATION_JAVASCRIPT {
<span class="kw">return </span>mime::APPLICATION_JAVASCRIPT_UTF_8;
}
<span class="kw">if </span>ct == mime::TEXT_HTML {
<span class="kw">return </span>mime::TEXT_HTML_UTF_8;
}
<span class="kw">if </span>ct == mime::TEXT_CSS {
<span class="kw">return </span>mime::TEXT_CSS_UTF_8;
}
<span class="kw">if </span>ct == mime::TEXT_PLAIN {
<span class="kw">return </span>mime::TEXT_PLAIN_UTF_8;
}
<span class="kw">if </span>ct == mime::TEXT_CSV {
<span class="kw">return </span>mime::TEXT_CSV_UTF_8;
}
<span class="kw">if </span>ct == mime::TEXT_TAB_SEPARATED_VALUES {
<span class="kw">return </span>mime::TEXT_TAB_SEPARATED_VALUES_UTF_8;
}
ct
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>test_equiv_utf8_text() {
<span class="macro">assert_eq!</span>(equiv_utf8_text(mime::TEXT_PLAIN), mime::TEXT_PLAIN_UTF_8);
<span class="macro">assert_eq!</span>(equiv_utf8_text(mime::TEXT_XML), mime::TEXT_XML);
<span class="macro">assert_eq!</span>(equiv_utf8_text(mime::IMAGE_PNG), mime::IMAGE_PNG);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,99 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-files/src/error.rs`."><title>error.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_files" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>actix_web::{http::StatusCode, ResponseError};
<span class="kw">use </span>derive_more::Display;
<span class="doccomment">/// Errors which can occur when serving static files.
</span><span class="attr">#[derive(Debug, PartialEq, Eq, Display)]
</span><span class="kw">pub enum </span>FilesError {
<span class="doccomment">/// Path is not a directory.
</span><span class="attr">#[allow(dead_code)]
#[display(fmt = <span class="string">"path is not a directory. Unable to serve static files"</span>)]
</span>IsNotDirectory,
<span class="doccomment">/// Cannot render directory.
</span><span class="attr">#[display(fmt = <span class="string">"unable to render directory without index file"</span>)]
</span>IsDirectory,
}
<span class="kw">impl </span>ResponseError <span class="kw">for </span>FilesError {
<span class="doccomment">/// Returns `404 Not Found`.
</span><span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
StatusCode::NOT_FOUND
}
}
<span class="attr">#[derive(Debug, PartialEq, Eq, Display)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>UriSegmentError {
<span class="doccomment">/// Segment started with the wrapped invalid character.
</span><span class="attr">#[display(fmt = <span class="string">"segment started with invalid character: ('{_0}')"</span>)]
</span>BadStart(char),
<span class="doccomment">/// Segment contained the wrapped invalid character.
</span><span class="attr">#[display(fmt = <span class="string">"segment contained invalid character ('{_0}')"</span>)]
</span>BadChar(char),
<span class="doccomment">/// Segment ended with the wrapped invalid character.
</span><span class="attr">#[display(fmt = <span class="string">"segment ended with invalid character: ('{_0}')"</span>)]
</span>BadEnd(char),
<span class="doccomment">/// Path is not a valid UTF-8 string after percent-decoding.
</span><span class="attr">#[display(fmt = <span class="string">"path is not a valid UTF-8 string after percent-decoding"</span>)]
</span>NotValidUtf8,
}
<span class="kw">impl </span>ResponseError <span class="kw">for </span>UriSegmentError {
<span class="doccomment">/// Returns `400 Bad Request`.
</span><span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
StatusCode::BAD_REQUEST
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,861 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-files/src/files.rs`."><title>files.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_files" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
<a href="#339" id="339">339</a>
<a href="#340" id="340">340</a>
<a href="#341" id="341">341</a>
<a href="#342" id="342">342</a>
<a href="#343" id="343">343</a>
<a href="#344" id="344">344</a>
<a href="#345" id="345">345</a>
<a href="#346" id="346">346</a>
<a href="#347" id="347">347</a>
<a href="#348" id="348">348</a>
<a href="#349" id="349">349</a>
<a href="#350" id="350">350</a>
<a href="#351" id="351">351</a>
<a href="#352" id="352">352</a>
<a href="#353" id="353">353</a>
<a href="#354" id="354">354</a>
<a href="#355" id="355">355</a>
<a href="#356" id="356">356</a>
<a href="#357" id="357">357</a>
<a href="#358" id="358">358</a>
<a href="#359" id="359">359</a>
<a href="#360" id="360">360</a>
<a href="#361" id="361">361</a>
<a href="#362" id="362">362</a>
<a href="#363" id="363">363</a>
<a href="#364" id="364">364</a>
<a href="#365" id="365">365</a>
<a href="#366" id="366">366</a>
<a href="#367" id="367">367</a>
<a href="#368" id="368">368</a>
<a href="#369" id="369">369</a>
<a href="#370" id="370">370</a>
<a href="#371" id="371">371</a>
<a href="#372" id="372">372</a>
<a href="#373" id="373">373</a>
<a href="#374" id="374">374</a>
<a href="#375" id="375">375</a>
<a href="#376" id="376">376</a>
<a href="#377" id="377">377</a>
<a href="#378" id="378">378</a>
<a href="#379" id="379">379</a>
<a href="#380" id="380">380</a>
<a href="#381" id="381">381</a>
<a href="#382" id="382">382</a>
<a href="#383" id="383">383</a>
<a href="#384" id="384">384</a>
<a href="#385" id="385">385</a>
<a href="#386" id="386">386</a>
<a href="#387" id="387">387</a>
<a href="#388" id="388">388</a>
<a href="#389" id="389">389</a>
<a href="#390" id="390">390</a>
<a href="#391" id="391">391</a>
<a href="#392" id="392">392</a>
<a href="#393" id="393">393</a>
<a href="#394" id="394">394</a>
<a href="#395" id="395">395</a>
<a href="#396" id="396">396</a>
<a href="#397" id="397">397</a>
<a href="#398" id="398">398</a>
<a href="#399" id="399">399</a>
<a href="#400" id="400">400</a>
<a href="#401" id="401">401</a>
<a href="#402" id="402">402</a>
<a href="#403" id="403">403</a>
<a href="#404" id="404">404</a>
<a href="#405" id="405">405</a>
<a href="#406" id="406">406</a>
<a href="#407" id="407">407</a>
<a href="#408" id="408">408</a>
<a href="#409" id="409">409</a>
<a href="#410" id="410">410</a>
<a href="#411" id="411">411</a>
<a href="#412" id="412">412</a>
<a href="#413" id="413">413</a>
<a href="#414" id="414">414</a>
<a href="#415" id="415">415</a>
<a href="#416" id="416">416</a>
<a href="#417" id="417">417</a>
<a href="#418" id="418">418</a>
<a href="#419" id="419">419</a>
<a href="#420" id="420">420</a>
<a href="#421" id="421">421</a>
<a href="#422" id="422">422</a>
<a href="#423" id="423">423</a>
<a href="#424" id="424">424</a>
<a href="#425" id="425">425</a>
<a href="#426" id="426">426</a>
<a href="#427" id="427">427</a>
<a href="#428" id="428">428</a>
<a href="#429" id="429">429</a>
<a href="#430" id="430">430</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
cell::RefCell,
fmt, io,
path::{Path, PathBuf},
rc::Rc,
};
<span class="kw">use </span>actix_service::{boxed, IntoServiceFactory, ServiceFactory, ServiceFactoryExt};
<span class="kw">use </span>actix_web::{
dev::{
AppService, HttpServiceFactory, RequestHead, ResourceDef, ServiceRequest, ServiceResponse,
},
error::Error,
guard::Guard,
http::header::DispositionType,
HttpRequest,
};
<span class="kw">use </span>futures_core::future::LocalBoxFuture;
<span class="kw">use crate</span>::{
directory_listing, named,
service::{FilesService, FilesServiceInner},
Directory, DirectoryRenderer, HttpNewService, MimeOverride, PathFilter,
};
<span class="doccomment">/// Static files handling service.
///
/// `Files` service must be registered with `App::service()` method.
///
/// # Examples
/// ```
/// use actix_web::App;
/// use actix_files::Files;
///
/// let app = App::new()
/// .service(Files::new("/static", "."));
/// ```
</span><span class="kw">pub struct </span>Files {
mount_path: String,
directory: PathBuf,
index: <span class="prelude-ty">Option</span>&lt;String&gt;,
show_index: bool,
redirect_to_slash: bool,
default: Rc&lt;RefCell&lt;<span class="prelude-ty">Option</span>&lt;Rc&lt;HttpNewService&gt;&gt;&gt;&gt;,
renderer: Rc&lt;DirectoryRenderer&gt;,
mime_override: <span class="prelude-ty">Option</span>&lt;Rc&lt;MimeOverride&gt;&gt;,
path_filter: <span class="prelude-ty">Option</span>&lt;Rc&lt;PathFilter&gt;&gt;,
file_flags: named::Flags,
use_guards: <span class="prelude-ty">Option</span>&lt;Rc&lt;<span class="kw">dyn </span>Guard&gt;&gt;,
guards: Vec&lt;Rc&lt;<span class="kw">dyn </span>Guard&gt;&gt;,
hidden_files: bool,
}
<span class="kw">impl </span>fmt::Debug <span class="kw">for </span>Files {
<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">'_</span>&gt;) -&gt; fmt::Result {
f.write_str(<span class="string">"Files"</span>)
}
}
<span class="kw">impl </span>Clone <span class="kw">for </span>Files {
<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>{
directory: <span class="self">self</span>.directory.clone(),
index: <span class="self">self</span>.index.clone(),
show_index: <span class="self">self</span>.show_index,
redirect_to_slash: <span class="self">self</span>.redirect_to_slash,
default: <span class="self">self</span>.default.clone(),
renderer: <span class="self">self</span>.renderer.clone(),
file_flags: <span class="self">self</span>.file_flags,
mount_path: <span class="self">self</span>.mount_path.clone(),
mime_override: <span class="self">self</span>.mime_override.clone(),
path_filter: <span class="self">self</span>.path_filter.clone(),
use_guards: <span class="self">self</span>.use_guards.clone(),
guards: <span class="self">self</span>.guards.clone(),
hidden_files: <span class="self">self</span>.hidden_files,
}
}
}
<span class="kw">impl </span>Files {
<span class="doccomment">/// Create new `Files` instance for a specified base directory.
///
/// # Argument Order
/// The first argument (`mount_path`) is the root URL at which the static files are served.
/// For example, `/assets` will serve files at `example.com/assets/...`.
///
/// The second argument (`serve_from`) is the location on disk at which files are loaded.
/// This can be a relative path. For example, `./` would serve files from the current
/// working directory.
///
/// # Implementation Notes
/// If the mount path is set as the root path `/`, services registered after this one will
/// be inaccessible. Register more specific handlers and services first.
///
/// `Files` utilizes the existing Tokio thread-pool for blocking filesystem operations.
/// The number of running threads is adjusted over time as needed, up to a maximum of 512 times
/// the number of server [workers](actix_web::HttpServer::workers), by default.
</span><span class="kw">pub fn </span>new&lt;T: Into&lt;PathBuf&gt;&gt;(mount_path: <span class="kw-2">&amp;</span>str, serve_from: T) -&gt; Files {
<span class="kw">let </span>orig_dir = serve_from.into();
<span class="kw">let </span>dir = <span class="kw">match </span>orig_dir.canonicalize() {
<span class="prelude-val">Ok</span>(canon_dir) =&gt; canon_dir,
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; {
<span class="macro">log::error!</span>(<span class="string">"Specified path is not a directory: {:?}"</span>, orig_dir);
PathBuf::new()
}
};
Files {
mount_path: mount_path.trim_end_matches(<span class="string">'/'</span>).to_owned(),
directory: dir,
index: <span class="prelude-val">None</span>,
show_index: <span class="bool-val">false</span>,
redirect_to_slash: <span class="bool-val">false</span>,
default: Rc::new(RefCell::new(<span class="prelude-val">None</span>)),
renderer: Rc::new(directory_listing),
mime_override: <span class="prelude-val">None</span>,
path_filter: <span class="prelude-val">None</span>,
file_flags: named::Flags::default(),
use_guards: <span class="prelude-val">None</span>,
guards: Vec::new(),
hidden_files: <span class="bool-val">false</span>,
}
}
<span class="doccomment">/// Show files listing for directories.
///
/// By default show files listing is disabled.
///
/// When used with [`Files::index_file()`], files listing is shown as a fallback
/// when the index file is not found.
</span><span class="kw">pub fn </span>show_files_listing(<span class="kw-2">mut </span><span class="self">self</span>) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.show_index = <span class="bool-val">true</span>;
<span class="self">self
</span>}
<span class="doccomment">/// Redirects to a slash-ended path when browsing a directory.
///
/// By default never redirect.
</span><span class="kw">pub fn </span>redirect_to_slash_directory(<span class="kw-2">mut </span><span class="self">self</span>) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.redirect_to_slash = <span class="bool-val">true</span>;
<span class="self">self
</span>}
<span class="doccomment">/// Set custom directory renderer.
</span><span class="kw">pub fn </span>files_listing_renderer&lt;F&gt;(<span class="kw-2">mut </span><span class="self">self</span>, f: F) -&gt; <span class="self">Self
</span><span class="kw">where
for</span>&lt;<span class="lifetime">'r</span>, <span class="lifetime">'s</span>&gt; F:
Fn(<span class="kw-2">&amp;</span><span class="lifetime">'r </span>Directory, <span class="kw-2">&amp;</span><span class="lifetime">'s </span>HttpRequest) -&gt; <span class="prelude-ty">Result</span>&lt;ServiceResponse, io::Error&gt; + <span class="lifetime">'static</span>,
{
<span class="self">self</span>.renderer = Rc::new(f);
<span class="self">self
</span>}
<span class="doccomment">/// Specifies MIME override callback.
</span><span class="kw">pub fn </span>mime_override&lt;F&gt;(<span class="kw-2">mut </span><span class="self">self</span>, f: F) -&gt; <span class="self">Self
</span><span class="kw">where
</span>F: Fn(<span class="kw-2">&amp;</span>mime::Name&lt;<span class="lifetime">'_</span>&gt;) -&gt; DispositionType + <span class="lifetime">'static</span>,
{
<span class="self">self</span>.mime_override = <span class="prelude-val">Some</span>(Rc::new(f));
<span class="self">self
</span>}
<span class="doccomment">/// Sets path filtering closure.
///
/// The path provided to the closure is relative to `serve_from` path.
/// You can safely join this path with the `serve_from` path to get the real path.
/// However, the real path may not exist since the filter is called before checking path existence.
///
/// When a path doesn't pass the filter, [`Files::default_handler`] is called if set, otherwise,
/// `404 Not Found` is returned.
///
/// # Examples
/// ```
/// use std::path::Path;
/// use actix_files::Files;
///
/// // prevent searching subdirectories and following symlinks
/// let files_service = Files::new("/", "./static").path_filter(|path, _| {
/// path.components().count() == 1
/// &amp;&amp; Path::new("./static")
/// .join(path)
/// .symlink_metadata()
/// .map(|m| !m.file_type().is_symlink())
/// .unwrap_or(false)
/// });
/// ```
</span><span class="kw">pub fn </span>path_filter&lt;F&gt;(<span class="kw-2">mut </span><span class="self">self</span>, f: F) -&gt; <span class="self">Self
</span><span class="kw">where
</span>F: Fn(<span class="kw-2">&amp;</span>Path, <span class="kw-2">&amp;</span>RequestHead) -&gt; bool + <span class="lifetime">'static</span>,
{
<span class="self">self</span>.path_filter = <span class="prelude-val">Some</span>(Rc::new(f));
<span class="self">self
</span>}
<span class="doccomment">/// Set index file
///
/// Shows specific index file for directories instead of
/// showing files listing.
///
/// If the index file is not found, files listing is shown as a fallback if
/// [`Files::show_files_listing()`] is set.
</span><span class="kw">pub fn </span>index_file&lt;T: Into&lt;String&gt;&gt;(<span class="kw-2">mut </span><span class="self">self</span>, index: T) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.index = <span class="prelude-val">Some</span>(index.into());
<span class="self">self
</span>}
<span class="doccomment">/// Specifies whether to use ETag or not.
///
/// Default is true.
</span><span class="kw">pub fn </span>use_etag(<span class="kw-2">mut </span><span class="self">self</span>, value: bool) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.file_flags.set(named::Flags::ETAG, value);
<span class="self">self
</span>}
<span class="doccomment">/// Specifies whether to use Last-Modified or not.
///
/// Default is true.
</span><span class="kw">pub fn </span>use_last_modified(<span class="kw-2">mut </span><span class="self">self</span>, value: bool) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.file_flags.set(named::Flags::LAST_MD, value);
<span class="self">self
</span>}
<span class="doccomment">/// Specifies whether text responses should signal a UTF-8 encoding.
///
/// Default is false (but will default to true in a future version).
</span><span class="kw">pub fn </span>prefer_utf8(<span class="kw-2">mut </span><span class="self">self</span>, value: bool) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.file_flags.set(named::Flags::PREFER_UTF8, value);
<span class="self">self
</span>}
<span class="doccomment">/// Adds a routing guard.
///
/// Use this to allow multiple chained file services that respond to strictly different
/// properties of a request. Due to the way routing works, if a guard check returns true and the
/// request starts being handled by the file service, it will not be able to back-out and try
/// the next service, you will simply get a 404 (or 405) error response.
///
/// To allow `POST` requests to retrieve files, see [`Files::method_guard()`].
///
/// # Examples
/// ```
/// use actix_web::{guard::Header, App};
/// use actix_files::Files;
///
/// App::new().service(
/// Files::new("/","/my/site/files")
/// .guard(Header("Host", "example.com"))
/// );
/// ```
</span><span class="kw">pub fn </span>guard&lt;G: Guard + <span class="lifetime">'static</span>&gt;(<span class="kw-2">mut </span><span class="self">self</span>, guard: G) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.guards.push(Rc::new(guard));
<span class="self">self
</span>}
<span class="doccomment">/// Specifies guard to check before fetching directory listings or files.
///
/// Note that this guard has no effect on routing; it's main use is to guard on the request's
/// method just before serving the file, only allowing `GET` and `HEAD` requests by default.
/// See [`Files::guard`] for routing guards.
</span><span class="kw">pub fn </span>method_guard&lt;G: Guard + <span class="lifetime">'static</span>&gt;(<span class="kw-2">mut </span><span class="self">self</span>, guard: G) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.use_guards = <span class="prelude-val">Some</span>(Rc::new(guard));
<span class="self">self
</span>}
<span class="doccomment">/// See [`Files::method_guard`].
</span><span class="attr">#[doc(hidden)]
#[deprecated(since = <span class="string">"0.6.0"</span>, note = <span class="string">"Renamed to `method_guard`."</span>)]
</span><span class="kw">pub fn </span>use_guards&lt;G: Guard + <span class="lifetime">'static</span>&gt;(<span class="self">self</span>, guard: G) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.method_guard(guard)
}
<span class="doccomment">/// Disable `Content-Disposition` header.
///
/// By default Content-Disposition` header is enabled.
</span><span class="kw">pub fn </span>disable_content_disposition(<span class="kw-2">mut </span><span class="self">self</span>) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.file_flags.remove(named::Flags::CONTENT_DISPOSITION);
<span class="self">self
</span>}
<span class="doccomment">/// Sets default handler which is used when no matched file could be found.
///
/// # Examples
/// Setting a fallback static file handler:
/// ```
/// use actix_files::{Files, NamedFile};
/// use actix_web::dev::{ServiceRequest, ServiceResponse, fn_service};
///
/// # fn run() -&gt; Result&lt;(), actix_web::Error&gt; {
/// let files = Files::new("/", "./static")
/// .index_file("index.html")
/// .default_handler(fn_service(|req: ServiceRequest| async {
/// let (req, _) = req.into_parts();
/// let file = NamedFile::open_async("./static/404.html").await?;
/// let res = file.into_response(&amp;req);
/// Ok(ServiceResponse::new(req, res))
/// }));
/// # Ok(())
/// # }
/// ```
</span><span class="kw">pub fn </span>default_handler&lt;F, U&gt;(<span class="kw-2">mut </span><span class="self">self</span>, f: F) -&gt; <span class="self">Self
</span><span class="kw">where
</span>F: IntoServiceFactory&lt;U, ServiceRequest&gt;,
U: ServiceFactory&lt;ServiceRequest, Config = (), Response = ServiceResponse, Error = Error&gt;
+ <span class="lifetime">'static</span>,
{
<span class="comment">// create and configure default resource
</span><span class="self">self</span>.default = Rc::new(RefCell::new(<span class="prelude-val">Some</span>(Rc::new(boxed::factory(
f.into_factory().map_init_err(|<span class="kw">_</span>| ()),
)))));
<span class="self">self
</span>}
<span class="doccomment">/// Enables serving hidden files and directories, allowing a leading dots in url fragments.
</span><span class="kw">pub fn </span>use_hidden_files(<span class="kw-2">mut </span><span class="self">self</span>) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.hidden_files = <span class="bool-val">true</span>;
<span class="self">self
</span>}
}
<span class="kw">impl </span>HttpServiceFactory <span class="kw">for </span>Files {
<span class="kw">fn </span>register(<span class="kw-2">mut </span><span class="self">self</span>, config: <span class="kw-2">&amp;mut </span>AppService) {
<span class="kw">let </span>guards = <span class="kw">if </span><span class="self">self</span>.guards.is_empty() {
<span class="prelude-val">None
</span>} <span class="kw">else </span>{
<span class="kw">let </span>guards = std::mem::take(<span class="kw-2">&amp;mut </span><span class="self">self</span>.guards);
<span class="prelude-val">Some</span>(
guards
.into_iter()
.map(|guard| -&gt; Box&lt;<span class="kw">dyn </span>Guard&gt; { Box::new(guard) })
.collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;(),
)
};
<span class="kw">if </span><span class="self">self</span>.default.borrow().is_none() {
<span class="kw-2">*</span><span class="self">self</span>.default.borrow_mut() = <span class="prelude-val">Some</span>(config.default_service());
}
<span class="kw">let </span>rdef = <span class="kw">if </span>config.is_root() {
ResourceDef::root_prefix(<span class="kw-2">&amp;</span><span class="self">self</span>.mount_path)
} <span class="kw">else </span>{
ResourceDef::prefix(<span class="kw-2">&amp;</span><span class="self">self</span>.mount_path)
};
config.register_service(rdef, guards, <span class="self">self</span>, <span class="prelude-val">None</span>)
}
}
<span class="kw">impl </span>ServiceFactory&lt;ServiceRequest&gt; <span class="kw">for </span>Files {
<span class="kw">type </span>Response = ServiceResponse;
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Config = ();
<span class="kw">type </span>Service = FilesService;
<span class="kw">type </span>InitError = ();
<span class="kw">type </span>Future = LocalBoxFuture&lt;<span class="lifetime">'static</span>, <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Service, <span class="self">Self</span>::InitError&gt;&gt;;
<span class="kw">fn </span>new_service(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: ()) -&gt; <span class="self">Self</span>::Future {
<span class="kw">let </span><span class="kw-2">mut </span>inner = FilesServiceInner {
directory: <span class="self">self</span>.directory.clone(),
index: <span class="self">self</span>.index.clone(),
show_index: <span class="self">self</span>.show_index,
redirect_to_slash: <span class="self">self</span>.redirect_to_slash,
default: <span class="prelude-val">None</span>,
renderer: <span class="self">self</span>.renderer.clone(),
mime_override: <span class="self">self</span>.mime_override.clone(),
path_filter: <span class="self">self</span>.path_filter.clone(),
file_flags: <span class="self">self</span>.file_flags,
guards: <span class="self">self</span>.use_guards.clone(),
hidden_files: <span class="self">self</span>.hidden_files,
};
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>default) = <span class="kw-2">*</span><span class="self">self</span>.default.borrow() {
<span class="kw">let </span>fut = default.new_service(());
Box::pin(<span class="kw">async </span>{
<span class="kw">match </span>fut.<span class="kw">await </span>{
<span class="prelude-val">Ok</span>(default) =&gt; {
inner.default = <span class="prelude-val">Some</span>(default);
<span class="prelude-val">Ok</span>(FilesService(Rc::new(inner)))
}
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(()),
}
})
} <span class="kw">else </span>{
Box::pin(<span class="kw">async move </span>{ <span class="prelude-val">Ok</span>(FilesService(Rc::new(inner))) })
}
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>actix_web::{
http::StatusCode,
test::{<span class="self">self</span>, TestRequest},
App, HttpResponse,
};
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[actix_web::test]
</span><span class="kw">async fn </span>custom_files_listing_renderer() {
<span class="kw">let </span>srv = test::init_service(
App::new().service(
Files::new(<span class="string">"/"</span>, <span class="string">"./tests"</span>)
.show_files_listing()
.files_listing_renderer(|dir, req| {
<span class="prelude-val">Ok</span>(ServiceResponse::new(
req.clone(),
HttpResponse::Ok().body(dir.path.to_str().unwrap().to_owned()),
))
}),
),
)
.<span class="kw">await</span>;
<span class="kw">let </span>req = TestRequest::with_uri(<span class="string">"/"</span>).to_request();
<span class="kw">let </span>res = test::call_service(<span class="kw-2">&amp;</span>srv, req).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="kw">let </span>body = test::read_body(res).<span class="kw">await</span>;
<span class="kw">let </span>body_str = std::str::from_utf8(<span class="kw-2">&amp;</span>body).unwrap();
<span class="kw">let </span>actual_path = Path::new(<span class="kw-2">&amp;</span>body_str);
<span class="kw">let </span>expected_path = Path::new(<span class="string">"actix-files/tests"</span>);
<span class="macro">assert!</span>(
actual_path.ends_with(expected_path),
<span class="string">"body {:?} does not end with {:?}"</span>,
actual_path,
expected_path
);
}
}
</code></pre></div></section></main></body></html>

2079
src/actix_files/lib.rs.html Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,377 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-files/src/path_buf.rs`."><title>path_buf.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_files" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
path::{Component, Path, PathBuf},
str::FromStr,
};
<span class="kw">use </span>actix_utils::future::{ready, Ready};
<span class="kw">use </span>actix_web::{dev::Payload, FromRequest, HttpRequest};
<span class="kw">use </span><span class="kw">crate</span>::error::UriSegmentError;
<span class="attr">#[derive(Debug, PartialEq, Eq)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>PathBufWrap(PathBuf);
<span class="kw">impl </span>FromStr <span class="kw">for </span>PathBufWrap {
<span class="kw">type </span><span class="prelude-val">Err </span>= UriSegmentError;
<span class="kw">fn </span>from_str(path: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, <span class="self">Self</span>::Err&gt; {
<span class="self">Self</span>::parse_path(path, <span class="bool-val">false</span>)
}
}
<span class="kw">impl </span>PathBufWrap {
<span class="doccomment">/// Parse a path, giving the choice of allowing hidden files to be considered valid segments.
///
/// Path traversal is guarded by this method.
</span><span class="kw">pub fn </span>parse_path(path: <span class="kw-2">&amp;</span>str, hidden_files: bool) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, UriSegmentError&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>buf = PathBuf::new();
<span class="comment">// equivalent to `path.split('/').count()`
</span><span class="kw">let </span><span class="kw-2">mut </span>segment_count = path.matches(<span class="string">'/'</span>).count() + <span class="number">1</span>;
<span class="comment">// we can decode the whole path here (instead of per-segment decoding)
// because we will reject `%2F` in paths using `segment_count`.
</span><span class="kw">let </span>path = percent_encoding::percent_decode_str(path)
.decode_utf8()
.map_err(|<span class="kw">_</span>| UriSegmentError::NotValidUtf8)<span class="question-mark">?</span>;
<span class="comment">// disallow decoding `%2F` into `/`
</span><span class="kw">if </span>segment_count != path.matches(<span class="string">'/'</span>).count() + <span class="number">1 </span>{
<span class="kw">return </span><span class="prelude-val">Err</span>(UriSegmentError::BadChar(<span class="string">'/'</span>));
}
<span class="kw">for </span>segment <span class="kw">in </span>path.split(<span class="string">'/'</span>) {
<span class="kw">if </span>segment == <span class="string">".." </span>{
segment_count -= <span class="number">1</span>;
buf.pop();
} <span class="kw">else if </span>!hidden_files &amp;&amp; segment.starts_with(<span class="string">'.'</span>) {
<span class="kw">return </span><span class="prelude-val">Err</span>(UriSegmentError::BadStart(<span class="string">'.'</span>));
} <span class="kw">else if </span>segment.starts_with(<span class="string">'*'</span>) {
<span class="kw">return </span><span class="prelude-val">Err</span>(UriSegmentError::BadStart(<span class="string">'*'</span>));
} <span class="kw">else if </span>segment.ends_with(<span class="string">':'</span>) {
<span class="kw">return </span><span class="prelude-val">Err</span>(UriSegmentError::BadEnd(<span class="string">':'</span>));
} <span class="kw">else if </span>segment.ends_with(<span class="string">'&gt;'</span>) {
<span class="kw">return </span><span class="prelude-val">Err</span>(UriSegmentError::BadEnd(<span class="string">'&gt;'</span>));
} <span class="kw">else if </span>segment.ends_with(<span class="string">'&lt;'</span>) {
<span class="kw">return </span><span class="prelude-val">Err</span>(UriSegmentError::BadEnd(<span class="string">'&lt;'</span>));
} <span class="kw">else if </span>segment.is_empty() {
segment_count -= <span class="number">1</span>;
<span class="kw">continue</span>;
} <span class="kw">else if </span><span class="macro">cfg!</span>(windows) &amp;&amp; segment.contains(<span class="string">'\\'</span>) {
<span class="kw">return </span><span class="prelude-val">Err</span>(UriSegmentError::BadChar(<span class="string">'\\'</span>));
} <span class="kw">else if </span><span class="macro">cfg!</span>(windows) &amp;&amp; segment.contains(<span class="string">':'</span>) {
<span class="kw">return </span><span class="prelude-val">Err</span>(UriSegmentError::BadChar(<span class="string">':'</span>));
} <span class="kw">else </span>{
buf.push(segment)
}
}
<span class="comment">// make sure we agree with stdlib parser
</span><span class="kw">for </span>(i, component) <span class="kw">in </span>buf.components().enumerate() {
<span class="macro">assert!</span>(
<span class="macro">matches!</span>(component, Component::Normal(<span class="kw">_</span>)),
<span class="string">"component `{:?}` is not normal"</span>,
component
);
<span class="macro">assert!</span>(i &lt; segment_count);
}
<span class="prelude-val">Ok</span>(PathBufWrap(buf))
}
}
<span class="kw">impl </span>AsRef&lt;Path&gt; <span class="kw">for </span>PathBufWrap {
<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>Path {
<span class="self">self</span>.<span class="number">0</span>.as_ref()
}
}
<span class="kw">impl </span>FromRequest <span class="kw">for </span>PathBufWrap {
<span class="kw">type </span>Error = UriSegmentError;
<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">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(req.match_info().unprocessed().parse())
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>test_path_buf() {
<span class="macro">assert_eq!</span>(
PathBufWrap::from_str(<span class="string">"/test/.tt"</span>).map(|t| t.<span class="number">0</span>),
<span class="prelude-val">Err</span>(UriSegmentError::BadStart(<span class="string">'.'</span>))
);
<span class="macro">assert_eq!</span>(
PathBufWrap::from_str(<span class="string">"/test/*tt"</span>).map(|t| t.<span class="number">0</span>),
<span class="prelude-val">Err</span>(UriSegmentError::BadStart(<span class="string">'*'</span>))
);
<span class="macro">assert_eq!</span>(
PathBufWrap::from_str(<span class="string">"/test/tt:"</span>).map(|t| t.<span class="number">0</span>),
<span class="prelude-val">Err</span>(UriSegmentError::BadEnd(<span class="string">':'</span>))
);
<span class="macro">assert_eq!</span>(
PathBufWrap::from_str(<span class="string">"/test/tt&lt;"</span>).map(|t| t.<span class="number">0</span>),
<span class="prelude-val">Err</span>(UriSegmentError::BadEnd(<span class="string">'&lt;'</span>))
);
<span class="macro">assert_eq!</span>(
PathBufWrap::from_str(<span class="string">"/test/tt&gt;"</span>).map(|t| t.<span class="number">0</span>),
<span class="prelude-val">Err</span>(UriSegmentError::BadEnd(<span class="string">'&gt;'</span>))
);
<span class="macro">assert_eq!</span>(
PathBufWrap::from_str(<span class="string">"/seg1/seg2/"</span>).unwrap().<span class="number">0</span>,
PathBuf::from_iter(<span class="macro">vec!</span>[<span class="string">"seg1"</span>, <span class="string">"seg2"</span>])
);
<span class="macro">assert_eq!</span>(
PathBufWrap::from_str(<span class="string">"/seg1/../seg2/"</span>).unwrap().<span class="number">0</span>,
PathBuf::from_iter(<span class="macro">vec!</span>[<span class="string">"seg2"</span>])
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_path() {
<span class="macro">assert_eq!</span>(
PathBufWrap::parse_path(<span class="string">"/test/.tt"</span>, <span class="bool-val">false</span>).map(|t| t.<span class="number">0</span>),
<span class="prelude-val">Err</span>(UriSegmentError::BadStart(<span class="string">'.'</span>))
);
<span class="macro">assert_eq!</span>(
PathBufWrap::parse_path(<span class="string">"/test/.tt"</span>, <span class="bool-val">true</span>).unwrap().<span class="number">0</span>,
PathBuf::from_iter(<span class="macro">vec!</span>[<span class="string">"test"</span>, <span class="string">".tt"</span>])
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>path_traversal() {
<span class="macro">assert_eq!</span>(
PathBufWrap::parse_path(<span class="string">"/../README.md"</span>, <span class="bool-val">false</span>).unwrap().<span class="number">0</span>,
PathBuf::from_iter(<span class="macro">vec!</span>[<span class="string">"README.md"</span>])
);
<span class="macro">assert_eq!</span>(
PathBufWrap::parse_path(<span class="string">"/../README.md"</span>, <span class="bool-val">true</span>).unwrap().<span class="number">0</span>,
PathBuf::from_iter(<span class="macro">vec!</span>[<span class="string">"README.md"</span>])
);
<span class="macro">assert_eq!</span>(
PathBufWrap::parse_path(<span class="string">"/../../../../../../../../../../etc/passwd"</span>, <span class="bool-val">false</span>)
.unwrap()
.<span class="number">0</span>,
PathBuf::from_iter(<span class="macro">vec!</span>[<span class="string">"etc/passwd"</span>])
);
}
<span class="attr">#[test]
#[cfg_attr(windows, should_panic)]
</span><span class="kw">fn </span>windows_drive_traversal() {
<span class="comment">// detect issues in windows that could lead to path traversal
// see &lt;https://github.com/SergioBenitez/Rocket/issues/1949
</span><span class="macro">assert_eq!</span>(
PathBufWrap::parse_path(<span class="string">"C:test.txt"</span>, <span class="bool-val">false</span>).unwrap().<span class="number">0</span>,
PathBuf::from_iter(<span class="macro">vec!</span>[<span class="string">"C:test.txt"</span>])
);
<span class="macro">assert_eq!</span>(
PathBufWrap::parse_path(<span class="string">"C:../whatever"</span>, <span class="bool-val">false</span>).unwrap().<span class="number">0</span>,
PathBuf::from_iter(<span class="macro">vec!</span>[<span class="string">"C:../whatever"</span>])
);
<span class="macro">assert_eq!</span>(
PathBufWrap::parse_path(<span class="string">":test.txt"</span>, <span class="bool-val">false</span>).unwrap().<span class="number">0</span>,
PathBuf::from_iter(<span class="macro">vec!</span>[<span class="string">":test.txt"</span>])
);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,677 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-files/src/range.rs`."><title>range.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_files" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::fmt;
<span class="kw">use </span>derive_more::Error;
<span class="doccomment">/// Copy of `http_range::HttpRangeParseError`.
</span><span class="attr">#[derive(Debug, Clone)]
</span><span class="kw">enum </span>HttpRangeParseError {
InvalidRange,
NoOverlap,
}
<span class="kw">impl </span>From&lt;http_range::HttpRangeParseError&gt; <span class="kw">for </span>HttpRangeParseError {
<span class="kw">fn </span>from(err: http_range::HttpRangeParseError) -&gt; <span class="self">Self </span>{
<span class="kw">match </span>err {
http_range::HttpRangeParseError::InvalidRange =&gt; <span class="self">Self</span>::InvalidRange,
http_range::HttpRangeParseError::NoOverlap =&gt; <span class="self">Self</span>::NoOverlap,
}
}
}
<span class="attr">#[derive(Debug, Clone, Error)]
#[non_exhaustive]
</span><span class="kw">pub struct </span>ParseRangeErr(<span class="attr">#[error(not(source))] </span>HttpRangeParseError);
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>ParseRangeErr {
<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">'_</span>&gt;) -&gt; fmt::Result {
f.write_str(<span class="string">"invalid Range header: "</span>)<span class="question-mark">?</span>;
f.write_str(<span class="kw">match </span><span class="self">self</span>.<span class="number">0 </span>{
HttpRangeParseError::InvalidRange =&gt; <span class="string">"invalid syntax"</span>,
HttpRangeParseError::NoOverlap =&gt; <span class="string">"range starts after end of content"</span>,
})
}
}
<span class="doccomment">/// HTTP Range header representation.
</span><span class="attr">#[derive(Debug, Clone, Copy)]
</span><span class="kw">pub struct </span>HttpRange {
<span class="doccomment">/// Start of range.
</span><span class="kw">pub </span>start: u64,
<span class="doccomment">/// Length of range.
</span><span class="kw">pub </span>length: u64,
}
<span class="kw">impl </span>HttpRange {
<span class="doccomment">/// Parses Range HTTP header string as per RFC 2616.
///
/// `header` is HTTP Range header (e.g. `bytes=bytes=0-9`).
/// `size` is full size of response (file).
</span><span class="kw">pub fn </span>parse(header: <span class="kw-2">&amp;</span>str, size: u64) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;HttpRange&gt;, ParseRangeErr&gt; {
<span class="kw">let </span>ranges =
http_range::HttpRange::parse(header, size).map_err(|err| ParseRangeErr(err.into()))<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(ranges
.iter()
.map(|range| HttpRange {
start: range.start,
length: range.length,
})
.collect())
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">struct </span>T(<span class="kw-2">&amp;</span><span class="lifetime">'static </span>str, u64, Vec&lt;HttpRange&gt;);
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse() {
<span class="kw">let </span>tests = <span class="macro">vec!</span>[
T(<span class="string">""</span>, <span class="number">0</span>, <span class="macro">vec!</span>[]),
T(<span class="string">""</span>, <span class="number">1000</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"foo"</span>, <span class="number">0</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes="</span>, <span class="number">0</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes=7"</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes= 7 "</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes=1-"</span>, <span class="number">0</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes=5-4"</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes=0-2,5-4"</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes=2-5,4-3"</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes=--5,4--3"</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes=A-"</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes=A- "</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes=A-Z"</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes= -Z"</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes=5-Z"</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes=Ran-dom, garbage"</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes=0x01-0x02"</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes= "</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(<span class="string">"bytes= , , , "</span>, <span class="number">10</span>, <span class="macro">vec!</span>[]),
T(
<span class="string">"bytes=0-9"</span>,
<span class="number">10</span>,
<span class="macro">vec!</span>[HttpRange {
start: <span class="number">0</span>,
length: <span class="number">10</span>,
}],
),
T(
<span class="string">"bytes=0-"</span>,
<span class="number">10</span>,
<span class="macro">vec!</span>[HttpRange {
start: <span class="number">0</span>,
length: <span class="number">10</span>,
}],
),
T(
<span class="string">"bytes=5-"</span>,
<span class="number">10</span>,
<span class="macro">vec!</span>[HttpRange {
start: <span class="number">5</span>,
length: <span class="number">5</span>,
}],
),
T(
<span class="string">"bytes=0-20"</span>,
<span class="number">10</span>,
<span class="macro">vec!</span>[HttpRange {
start: <span class="number">0</span>,
length: <span class="number">10</span>,
}],
),
T(
<span class="string">"bytes=15-,0-5"</span>,
<span class="number">10</span>,
<span class="macro">vec!</span>[HttpRange {
start: <span class="number">0</span>,
length: <span class="number">6</span>,
}],
),
T(
<span class="string">"bytes=1-2,5-"</span>,
<span class="number">10</span>,
<span class="macro">vec!</span>[
HttpRange {
start: <span class="number">1</span>,
length: <span class="number">2</span>,
},
HttpRange {
start: <span class="number">5</span>,
length: <span class="number">5</span>,
},
],
),
T(
<span class="string">"bytes=-2 , 7-"</span>,
<span class="number">11</span>,
<span class="macro">vec!</span>[
HttpRange {
start: <span class="number">9</span>,
length: <span class="number">2</span>,
},
HttpRange {
start: <span class="number">7</span>,
length: <span class="number">4</span>,
},
],
),
T(
<span class="string">"bytes=0-0 ,2-2, 7-"</span>,
<span class="number">11</span>,
<span class="macro">vec!</span>[
HttpRange {
start: <span class="number">0</span>,
length: <span class="number">1</span>,
},
HttpRange {
start: <span class="number">2</span>,
length: <span class="number">1</span>,
},
HttpRange {
start: <span class="number">7</span>,
length: <span class="number">4</span>,
},
],
),
T(
<span class="string">"bytes=-5"</span>,
<span class="number">10</span>,
<span class="macro">vec!</span>[HttpRange {
start: <span class="number">5</span>,
length: <span class="number">5</span>,
}],
),
T(
<span class="string">"bytes=-15"</span>,
<span class="number">10</span>,
<span class="macro">vec!</span>[HttpRange {
start: <span class="number">0</span>,
length: <span class="number">10</span>,
}],
),
T(
<span class="string">"bytes=0-499"</span>,
<span class="number">10000</span>,
<span class="macro">vec!</span>[HttpRange {
start: <span class="number">0</span>,
length: <span class="number">500</span>,
}],
),
T(
<span class="string">"bytes=500-999"</span>,
<span class="number">10000</span>,
<span class="macro">vec!</span>[HttpRange {
start: <span class="number">500</span>,
length: <span class="number">500</span>,
}],
),
T(
<span class="string">"bytes=-500"</span>,
<span class="number">10000</span>,
<span class="macro">vec!</span>[HttpRange {
start: <span class="number">9500</span>,
length: <span class="number">500</span>,
}],
),
T(
<span class="string">"bytes=9500-"</span>,
<span class="number">10000</span>,
<span class="macro">vec!</span>[HttpRange {
start: <span class="number">9500</span>,
length: <span class="number">500</span>,
}],
),
T(
<span class="string">"bytes=0-0,-1"</span>,
<span class="number">10000</span>,
<span class="macro">vec!</span>[
HttpRange {
start: <span class="number">0</span>,
length: <span class="number">1</span>,
},
HttpRange {
start: <span class="number">9999</span>,
length: <span class="number">1</span>,
},
],
),
T(
<span class="string">"bytes=500-600,601-999"</span>,
<span class="number">10000</span>,
<span class="macro">vec!</span>[
HttpRange {
start: <span class="number">500</span>,
length: <span class="number">101</span>,
},
HttpRange {
start: <span class="number">601</span>,
length: <span class="number">399</span>,
},
],
),
T(
<span class="string">"bytes=500-700,601-999"</span>,
<span class="number">10000</span>,
<span class="macro">vec!</span>[
HttpRange {
start: <span class="number">500</span>,
length: <span class="number">201</span>,
},
HttpRange {
start: <span class="number">601</span>,
length: <span class="number">399</span>,
},
],
),
<span class="comment">// Match Apache laxity:
</span>T(
<span class="string">"bytes= 1 -2 , 4- 5, 7 - 8 , ,,"</span>,
<span class="number">11</span>,
<span class="macro">vec!</span>[
HttpRange {
start: <span class="number">1</span>,
length: <span class="number">2</span>,
},
HttpRange {
start: <span class="number">4</span>,
length: <span class="number">2</span>,
},
HttpRange {
start: <span class="number">7</span>,
length: <span class="number">2</span>,
},
],
),
];
<span class="kw">for </span>t <span class="kw">in </span>tests {
<span class="kw">let </span>header = t.<span class="number">0</span>;
<span class="kw">let </span>size = t.<span class="number">1</span>;
<span class="kw">let </span>expected = t.<span class="number">2</span>;
<span class="kw">let </span>res = HttpRange::parse(header, size);
<span class="kw">if </span>res.is_err() {
<span class="kw">if </span>expected.is_empty() {
<span class="kw">continue</span>;
} <span class="kw">else </span>{
<span class="macro">panic!</span>(
<span class="string">"parse({}, {}) returned error {:?}"</span>,
header,
size,
res.unwrap_err()
);
}
}
<span class="kw">let </span>got = res.unwrap();
<span class="kw">if </span>got.len() != expected.len() {
<span class="macro">panic!</span>(
<span class="string">"len(parseRange({}, {})) = {}, want {}"</span>,
header,
size,
got.len(),
expected.len()
);
}
<span class="kw">for </span>i <span class="kw">in </span><span class="number">0</span>..expected.len() {
<span class="kw">if </span>got[i].start != expected[i].start {
<span class="macro">panic!</span>(
<span class="string">"parseRange({}, {})[{}].start = {}, want {}"</span>,
header, size, i, got[i].start, expected[i].start
)
}
<span class="kw">if </span>got[i].length != expected[i].length {
<span class="macro">panic!</span>(
<span class="string">"parseRange({}, {})[{}].length = {}, want {}"</span>,
header, size, i, got[i].length, expected[i].length
)
}
}
}
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,377 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-files/src/service.rs`."><title>service.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_files" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{fmt, io, ops::Deref, path::PathBuf, rc::Rc};
<span class="kw">use </span>actix_web::{
body::BoxBody,
dev::{<span class="self">self</span>, Service, ServiceRequest, ServiceResponse},
error::Error,
guard::Guard,
http::{header, Method},
HttpResponse,
};
<span class="kw">use </span>futures_core::future::LocalBoxFuture;
<span class="kw">use crate</span>::{
named, Directory, DirectoryRenderer, FilesError, HttpService, MimeOverride, NamedFile,
PathBufWrap, PathFilter,
};
<span class="doccomment">/// Assembled file serving service.
</span><span class="attr">#[derive(Clone)]
</span><span class="kw">pub struct </span>FilesService(<span class="kw">pub</span>(<span class="kw">crate</span>) Rc&lt;FilesServiceInner&gt;);
<span class="kw">impl </span>Deref <span class="kw">for </span>FilesService {
<span class="kw">type </span>Target = FilesServiceInner;
<span class="kw">fn </span>deref(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="self">Self</span>::Target {
<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0
</span>}
}
<span class="kw">pub struct </span>FilesServiceInner {
<span class="kw">pub</span>(<span class="kw">crate</span>) directory: PathBuf,
<span class="kw">pub</span>(<span class="kw">crate</span>) index: <span class="prelude-ty">Option</span>&lt;String&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) show_index: bool,
<span class="kw">pub</span>(<span class="kw">crate</span>) redirect_to_slash: bool,
<span class="kw">pub</span>(<span class="kw">crate</span>) default: <span class="prelude-ty">Option</span>&lt;HttpService&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) renderer: Rc&lt;DirectoryRenderer&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) mime_override: <span class="prelude-ty">Option</span>&lt;Rc&lt;MimeOverride&gt;&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) path_filter: <span class="prelude-ty">Option</span>&lt;Rc&lt;PathFilter&gt;&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) file_flags: named::Flags,
<span class="kw">pub</span>(<span class="kw">crate</span>) guards: <span class="prelude-ty">Option</span>&lt;Rc&lt;<span class="kw">dyn </span>Guard&gt;&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) hidden_files: bool,
}
<span class="kw">impl </span>fmt::Debug <span class="kw">for </span>FilesServiceInner {
<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">'_</span>&gt;) -&gt; fmt::Result {
f.write_str(<span class="string">"FilesServiceInner"</span>)
}
}
<span class="kw">impl </span>FilesService {
<span class="kw">async fn </span>handle_err(
<span class="kw-2">&amp;</span><span class="self">self</span>,
err: io::Error,
req: ServiceRequest,
) -&gt; <span class="prelude-ty">Result</span>&lt;ServiceResponse, Error&gt; {
<span class="macro">log::debug!</span>(<span class="string">"error handling {}: {}"</span>, req.path(), err);
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>default) = <span class="self">self</span>.default {
default.call(req).<span class="kw">await
</span>} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(req.error_response(err))
}
}
<span class="kw">fn </span>serve_named_file(<span class="kw-2">&amp;</span><span class="self">self</span>, req: ServiceRequest, <span class="kw-2">mut </span>named_file: NamedFile) -&gt; ServiceResponse {
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>mime_override) = <span class="self">self</span>.mime_override {
<span class="kw">let </span>new_disposition = mime_override(<span class="kw-2">&amp;</span>named_file.content_type.type_());
named_file.content_disposition.disposition = new_disposition;
}
named_file.flags = <span class="self">self</span>.file_flags;
<span class="kw">let </span>(req, <span class="kw">_</span>) = req.into_parts();
<span class="kw">let </span>res = named_file.into_response(<span class="kw-2">&amp;</span>req);
ServiceResponse::new(req, res)
}
<span class="kw">fn </span>show_index(<span class="kw-2">&amp;</span><span class="self">self</span>, req: ServiceRequest, path: PathBuf) -&gt; ServiceResponse {
<span class="kw">let </span>dir = Directory::new(<span class="self">self</span>.directory.clone(), path);
<span class="kw">let </span>(req, <span class="kw">_</span>) = req.into_parts();
(<span class="self">self</span>.renderer)(<span class="kw-2">&amp;</span>dir, <span class="kw-2">&amp;</span>req).unwrap_or_else(|e| ServiceResponse::from_err(e, req))
}
}
<span class="kw">impl </span>fmt::Debug <span class="kw">for </span>FilesService {
<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">'_</span>&gt;) -&gt; fmt::Result {
f.write_str(<span class="string">"FilesService"</span>)
}
}
<span class="kw">impl </span>Service&lt;ServiceRequest&gt; <span class="kw">for </span>FilesService {
<span class="kw">type </span>Response = ServiceResponse&lt;BoxBody&gt;;
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Future = LocalBoxFuture&lt;<span class="lifetime">'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">dev::always_ready!</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>is_method_valid = <span class="kw">if let </span><span class="prelude-val">Some</span>(guard) = <span class="kw-2">&amp;</span><span class="self">self</span>.guards {
<span class="comment">// execute user defined guards
</span>(<span class="kw-2">**</span>guard).check(<span class="kw-2">&amp;</span>req.guard_ctx())
} <span class="kw">else </span>{
<span class="comment">// default behavior
</span><span class="macro">matches!</span>(<span class="kw-2">*</span>req.method(), Method::HEAD | Method::GET)
};
<span class="kw">let </span>this = <span class="self">self</span>.clone();
Box::pin(<span class="kw">async move </span>{
<span class="kw">if </span>!is_method_valid {
<span class="kw">return </span><span class="prelude-val">Ok</span>(req.into_response(
HttpResponse::MethodNotAllowed()
.insert_header(header::ContentType(mime::TEXT_PLAIN_UTF_8))
.body(<span class="string">"Request did not meet this resource's requirements."</span>),
));
}
<span class="kw">let </span>path_on_disk =
<span class="kw">match </span>PathBufWrap::parse_path(req.match_info().unprocessed(), this.hidden_files) {
<span class="prelude-val">Ok</span>(item) =&gt; item,
<span class="prelude-val">Err</span>(err) =&gt; <span class="kw">return </span><span class="prelude-val">Ok</span>(req.error_response(err)),
};
<span class="kw">if let </span><span class="prelude-val">Some</span>(filter) = <span class="kw-2">&amp;</span>this.path_filter {
<span class="kw">if </span>!filter(path_on_disk.as_ref(), req.head()) {
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>default) = this.default {
<span class="kw">return </span>default.call(req).<span class="kw">await</span>;
} <span class="kw">else </span>{
<span class="kw">return </span><span class="prelude-val">Ok</span>(req.into_response(HttpResponse::NotFound().finish()));
}
}
}
<span class="comment">// full file path
</span><span class="kw">let </span>path = this.directory.join(<span class="kw-2">&amp;</span>path_on_disk);
<span class="kw">if let </span><span class="prelude-val">Err</span>(err) = path.canonicalize() {
<span class="kw">return </span>this.handle_err(err, req).<span class="kw">await</span>;
}
<span class="kw">if </span>path.is_dir() {
<span class="kw">if </span>this.redirect_to_slash
&amp;&amp; !req.path().ends_with(<span class="string">'/'</span>)
&amp;&amp; (this.index.is_some() || this.show_index)
{
<span class="kw">let </span>redirect_to = <span class="macro">format!</span>(<span class="string">"{}/"</span>, req.path());
<span class="kw">return </span><span class="prelude-val">Ok</span>(req.into_response(
HttpResponse::Found()
.insert_header((header::LOCATION, redirect_to))
.finish(),
));
}
<span class="kw">match </span>this.index {
<span class="prelude-val">Some</span>(<span class="kw-2">ref </span>index) =&gt; {
<span class="kw">let </span>named_path = path.join(index);
<span class="kw">match </span>NamedFile::open_async(named_path).<span class="kw">await </span>{
<span class="prelude-val">Ok</span>(named_file) =&gt; <span class="prelude-val">Ok</span>(this.serve_named_file(req, named_file)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) <span class="kw">if </span>this.show_index =&gt; <span class="prelude-val">Ok</span>(this.show_index(req, path)),
<span class="prelude-val">Err</span>(err) =&gt; this.handle_err(err, req).<span class="kw">await</span>,
}
}
<span class="prelude-val">None </span><span class="kw">if </span>this.show_index =&gt; <span class="prelude-val">Ok</span>(this.show_index(req, path)),
<span class="prelude-val">None </span>=&gt; <span class="prelude-val">Ok</span>(ServiceResponse::from_err(
FilesError::IsDirectory,
req.into_parts().<span class="number">0</span>,
)),
}
} <span class="kw">else </span>{
<span class="kw">match </span>NamedFile::open_async(<span class="kw-2">&amp;</span>path).<span class="kw">await </span>{
<span class="prelude-val">Ok</span>(<span class="kw-2">mut </span>named_file) =&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>mime_override) = this.mime_override {
<span class="kw">let </span>new_disposition = mime_override(<span class="kw-2">&amp;</span>named_file.content_type.type_());
named_file.content_disposition.disposition = new_disposition;
}
named_file.flags = this.file_flags;
<span class="kw">let </span>(req, <span class="kw">_</span>) = req.into_parts();
<span class="kw">let </span>res = named_file.into_response(<span class="kw-2">&amp;</span>req);
<span class="prelude-val">Ok</span>(ServiceResponse::new(req, res))
}
<span class="prelude-val">Err</span>(err) =&gt; this.handle_err(err, req).<span class="kw">await</span>,
}
}
})
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,429 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/body/body_stream.rs`."><title>body_stream.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
error::Error <span class="kw">as </span>StdError,
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use </span>futures_core::{ready, Stream};
<span class="kw">use </span>pin_project_lite::pin_project;
<span class="kw">use super</span>::{BodySize, MessageBody};
<span class="macro">pin_project!</span> {
<span class="doccomment">/// Streaming response wrapper.
///
/// Response does not contain `Content-Length` header and appropriate transfer encoding is used.
</span><span class="kw">pub struct </span>BodyStream&lt;S&gt; {
<span class="attr">#[pin]
</span>stream: S,
}
}
<span class="comment">// TODO: from_infallible method
</span><span class="kw">impl</span>&lt;S, E&gt; BodyStream&lt;S&gt;
<span class="kw">where
</span>S: Stream&lt;Item = <span class="prelude-ty">Result</span>&lt;Bytes, E&gt;&gt;,
E: Into&lt;Box&lt;<span class="kw">dyn </span>StdError&gt;&gt; + <span class="lifetime">'static</span>,
{
<span class="attr">#[inline]
</span><span class="kw">pub fn </span>new(stream: S) -&gt; <span class="self">Self </span>{
BodyStream { stream }
}
}
<span class="kw">impl</span>&lt;S, E&gt; MessageBody <span class="kw">for </span>BodyStream&lt;S&gt;
<span class="kw">where
</span>S: Stream&lt;Item = <span class="prelude-ty">Result</span>&lt;Bytes, E&gt;&gt;,
E: Into&lt;Box&lt;<span class="kw">dyn </span>StdError&gt;&gt; + <span class="lifetime">'static</span>,
{
<span class="kw">type </span>Error = E;
<span class="attr">#[inline]
</span><span class="kw">fn </span>size(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; BodySize {
BodySize::Stream
}
<span class="doccomment">/// Attempts to pull out the next value of the underlying [`Stream`].
///
/// Empty values are skipped to prevent [`BodyStream`]'s transmission being ended on a
/// zero-length chunk, but rather proceed until the underlying [`Stream`] ends.
</span><span class="kw">fn </span>poll_next(
<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;,
cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="self">Self</span>::Error&gt;&gt;&gt; {
<span class="kw">loop </span>{
<span class="kw">let </span>stream = <span class="self">self</span>.as_mut().project().stream;
<span class="kw">let </span>chunk = <span class="kw">match </span><span class="macro">ready!</span>(stream.poll_next(cx)) {
<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(<span class="kw-2">ref </span>bytes)) <span class="kw">if </span>bytes.is_empty() =&gt; <span class="kw">continue</span>,
opt =&gt; opt,
};
<span class="kw">return </span>Poll::Ready(chunk);
}
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::{convert::Infallible, time::Duration};
<span class="kw">use </span>actix_rt::{
pin,
time::{sleep, Sleep},
};
<span class="kw">use </span>actix_utils::future::poll_fn;
<span class="kw">use </span>derive_more::{Display, Error};
<span class="kw">use </span>futures_core::ready;
<span class="kw">use </span>futures_util::{stream, FutureExt <span class="kw">as _</span>};
<span class="kw">use </span>pin_project_lite::pin_project;
<span class="kw">use </span>static_assertions::{assert_impl_all, assert_not_impl_any};
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use </span><span class="kw">crate</span>::body::to_bytes;
<span class="macro">assert_impl_all!</span>(BodyStream&lt;stream::Empty&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="kw">crate</span>::Error&gt;&gt;&gt;: MessageBody);
<span class="macro">assert_impl_all!</span>(BodyStream&lt;stream::Empty&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str&gt;&gt;&gt;: MessageBody);
<span class="macro">assert_impl_all!</span>(BodyStream&lt;stream::Repeat&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str&gt;&gt;&gt;: MessageBody);
<span class="macro">assert_impl_all!</span>(BodyStream&lt;stream::Empty&lt;<span class="prelude-ty">Result</span>&lt;Bytes, Infallible&gt;&gt;&gt;: MessageBody);
<span class="macro">assert_impl_all!</span>(BodyStream&lt;stream::Repeat&lt;<span class="prelude-ty">Result</span>&lt;Bytes, Infallible&gt;&gt;&gt;: MessageBody);
<span class="macro">assert_not_impl_any!</span>(BodyStream&lt;stream::Empty&lt;Bytes&gt;&gt;: MessageBody);
<span class="macro">assert_not_impl_any!</span>(BodyStream&lt;stream::Repeat&lt;Bytes&gt;&gt;: MessageBody);
<span class="comment">// crate::Error is not Clone
</span><span class="macro">assert_not_impl_any!</span>(BodyStream&lt;stream::Repeat&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="kw">crate</span>::Error&gt;&gt;&gt;: MessageBody);
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>skips_empty_chunks() {
<span class="kw">let </span>body = BodyStream::new(stream::iter(
[<span class="string">"1"</span>, <span class="string">""</span>, <span class="string">"2"</span>]
.iter()
.map(|<span class="kw-2">&amp;</span>v| <span class="prelude-val">Ok</span>::&lt;<span class="kw">_</span>, Infallible&gt;(Bytes::from(v))),
));
<span class="macro">pin!</span>(body);
<span class="macro">assert_eq!</span>(
poll_fn(|cx| body.as_mut().poll_next(cx))
.<span class="kw">await
</span>.unwrap()
.ok(),
<span class="prelude-val">Some</span>(Bytes::from(<span class="string">"1"</span>)),
);
<span class="macro">assert_eq!</span>(
poll_fn(|cx| body.as_mut().poll_next(cx))
.<span class="kw">await
</span>.unwrap()
.ok(),
<span class="prelude-val">Some</span>(Bytes::from(<span class="string">"2"</span>)),
);
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>read_to_bytes() {
<span class="kw">let </span>body = BodyStream::new(stream::iter(
[<span class="string">"1"</span>, <span class="string">""</span>, <span class="string">"2"</span>]
.iter()
.map(|<span class="kw-2">&amp;</span>v| <span class="prelude-val">Ok</span>::&lt;<span class="kw">_</span>, Infallible&gt;(Bytes::from(v))),
));
<span class="macro">assert_eq!</span>(to_bytes(body).<span class="kw">await</span>.ok(), <span class="prelude-val">Some</span>(Bytes::from(<span class="string">"12"</span>)));
}
<span class="attr">#[derive(Debug, Display, Error)]
#[display(fmt = <span class="string">"stream error"</span>)]
</span><span class="kw">struct </span>StreamErr;
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>stream_immediate_error() {
<span class="kw">let </span>body = BodyStream::new(stream::once(<span class="kw">async </span>{ <span class="prelude-val">Err</span>(StreamErr) }));
<span class="macro">assert!</span>(<span class="macro">matches!</span>(to_bytes(body).<span class="kw">await</span>, <span class="prelude-val">Err</span>(StreamErr)));
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>stream_string_error() {
<span class="comment">// `&amp;'static str` does not impl `Error`
// but it does impl `Into&lt;Box&lt;dyn Error&gt;&gt;`
</span><span class="kw">let </span>body = BodyStream::new(stream::once(<span class="kw">async </span>{ <span class="prelude-val">Err</span>(<span class="string">"stringy error"</span>) }));
<span class="macro">assert!</span>(<span class="macro">matches!</span>(to_bytes(body).<span class="kw">await</span>, <span class="prelude-val">Err</span>(<span class="string">"stringy error"</span>)));
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>stream_boxed_error() {
<span class="comment">// `Box&lt;dyn Error&gt;` does not impl `Error`
// but it does impl `Into&lt;Box&lt;dyn Error&gt;&gt;`
</span><span class="kw">let </span>body = BodyStream::new(stream::once(<span class="kw">async </span>{
<span class="prelude-val">Err</span>(Box::&lt;<span class="kw">dyn </span>StdError&gt;::from(<span class="string">"stringy error"</span>))
}));
<span class="macro">assert_eq!</span>(
to_bytes(body).<span class="kw">await</span>.unwrap_err().to_string(),
<span class="string">"stringy error"
</span>);
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>stream_delayed_error() {
<span class="kw">let </span>body = BodyStream::new(stream::iter(<span class="macro">vec!</span>[<span class="prelude-val">Ok</span>(Bytes::from(<span class="string">"1"</span>)), <span class="prelude-val">Err</span>(StreamErr)]));
<span class="macro">assert!</span>(<span class="macro">matches!</span>(to_bytes(body).<span class="kw">await</span>, <span class="prelude-val">Err</span>(StreamErr)));
<span class="macro">pin_project!</span> {
<span class="attr">#[derive(Debug)]
#[project = TimeDelayStreamProj]
</span><span class="kw">enum </span>TimeDelayStream {
Start,
Sleep { delay: Pin&lt;Box&lt;Sleep&gt;&gt; },
Done,
}
}
<span class="kw">impl </span>Stream <span class="kw">for </span>TimeDelayStream {
<span class="kw">type </span>Item = <span class="prelude-ty">Result</span>&lt;Bytes, StreamErr&gt;;
<span class="kw">fn </span>poll_next(
<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;,
cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt;&gt; {
<span class="kw">match </span><span class="self">self</span>.as_mut().get_mut() {
TimeDelayStream::Start =&gt; {
<span class="kw">let </span>sleep = sleep(Duration::from_millis(<span class="number">1</span>));
<span class="self">self</span>.as_mut().set(TimeDelayStream::Sleep {
delay: Box::pin(sleep),
});
cx.waker().wake_by_ref();
Poll::Pending
}
TimeDelayStream::Sleep { <span class="kw-2">ref mut </span>delay } =&gt; {
<span class="macro">ready!</span>(delay.poll_unpin(cx));
<span class="self">self</span>.set(TimeDelayStream::Done);
cx.waker().wake_by_ref();
Poll::Pending
}
TimeDelayStream::Done =&gt; Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(StreamErr))),
}
}
}
<span class="kw">let </span>body = BodyStream::new(TimeDelayStream::Start);
<span class="macro">assert!</span>(<span class="macro">matches!</span>(to_bytes(body).<span class="kw">await</span>, <span class="prelude-val">Err</span>(StreamErr)));
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,243 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/body/boxed.rs`."><title>boxed.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
error::Error <span class="kw">as </span>StdError,
fmt,
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use super</span>::{BodySize, MessageBody, MessageBodyMapErr};
<span class="kw">use </span><span class="kw">crate</span>::body;
<span class="doccomment">/// A boxed message body with boxed errors.
</span><span class="attr">#[derive(Debug)]
</span><span class="kw">pub struct </span>BoxBody(BoxBodyInner);
<span class="kw">enum </span>BoxBodyInner {
<span class="prelude-val">None</span>(body::None),
Bytes(Bytes),
Stream(Pin&lt;Box&lt;<span class="kw">dyn </span>MessageBody&lt;Error = Box&lt;<span class="kw">dyn </span>StdError&gt;&gt;&gt;&gt;),
}
<span class="kw">impl </span>fmt::Debug <span class="kw">for </span>BoxBodyInner {
<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">'_</span>&gt;) -&gt; fmt::Result {
<span class="kw">match </span><span class="self">self </span>{
<span class="self">Self</span>::None(arg0) =&gt; f.debug_tuple(<span class="string">"None"</span>).field(arg0).finish(),
<span class="self">Self</span>::Bytes(arg0) =&gt; f.debug_tuple(<span class="string">"Bytes"</span>).field(arg0).finish(),
<span class="self">Self</span>::Stream(<span class="kw">_</span>) =&gt; f.debug_tuple(<span class="string">"Stream"</span>).field(<span class="kw-2">&amp;</span><span class="string">"dyn MessageBody"</span>).finish(),
}
}
}
<span class="kw">impl </span>BoxBody {
<span class="doccomment">/// Boxes body type, erasing type information.
///
/// If the body type to wrap is unknown or generic it is better to use [`MessageBody::boxed`] to
/// avoid double boxing.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>new&lt;B&gt;(body: B) -&gt; <span class="self">Self
</span><span class="kw">where
</span>B: MessageBody + <span class="lifetime">'static</span>,
{
<span class="kw">match </span>body.size() {
BodySize::None =&gt; <span class="self">Self</span>(BoxBodyInner::None(body::None)),
<span class="kw">_ </span>=&gt; <span class="kw">match </span>body.try_into_bytes() {
<span class="prelude-val">Ok</span>(bytes) =&gt; <span class="self">Self</span>(BoxBodyInner::Bytes(bytes)),
<span class="prelude-val">Err</span>(body) =&gt; {
<span class="kw">let </span>body = MessageBodyMapErr::new(body, Into::into);
<span class="self">Self</span>(BoxBodyInner::Stream(Box::pin(body)))
}
},
}
}
<span class="doccomment">/// Returns a mutable pinned reference to the inner message body type.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>as_pin_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt; {
Pin::new(<span class="self">self</span>)
}
}
<span class="kw">impl </span>MessageBody <span class="kw">for </span>BoxBody {
<span class="kw">type </span>Error = Box&lt;<span class="kw">dyn </span>StdError&gt;;
<span class="attr">#[inline]
</span><span class="kw">fn </span>size(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; BodySize {
<span class="kw">match </span><span class="kw-2">&amp;</span><span class="self">self</span>.<span class="number">0 </span>{
BoxBodyInner::None(none) =&gt; none.size(),
BoxBodyInner::Bytes(bytes) =&gt; bytes.size(),
BoxBodyInner::Stream(stream) =&gt; stream.size(),
}
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>poll_next(
<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;,
cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="self">Self</span>::Error&gt;&gt;&gt; {
<span class="kw">match </span><span class="kw-2">&amp;mut </span><span class="self">self</span>.<span class="number">0 </span>{
BoxBodyInner::None(body) =&gt; Pin::new(body).poll_next(cx).map_err(|err| <span class="kw">match </span>err {}),
BoxBodyInner::Bytes(body) =&gt; Pin::new(body).poll_next(cx).map_err(|err| <span class="kw">match </span>err {}),
BoxBodyInner::Stream(body) =&gt; Pin::new(body).poll_next(cx),
}
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_into_bytes(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Bytes, <span class="self">Self</span>&gt; {
<span class="kw">match </span><span class="self">self</span>.<span class="number">0 </span>{
BoxBodyInner::None(body) =&gt; <span class="prelude-val">Ok</span>(body.try_into_bytes().unwrap()),
BoxBodyInner::Bytes(body) =&gt; <span class="prelude-val">Ok</span>(body.try_into_bytes().unwrap()),
<span class="kw">_ </span>=&gt; <span class="prelude-val">Err</span>(<span class="self">self</span>),
}
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>boxed(<span class="self">self</span>) -&gt; BoxBody {
<span class="self">self
</span>}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>static_assertions::{assert_impl_all, assert_not_impl_any};
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use </span><span class="kw">crate</span>::body::to_bytes;
<span class="macro">assert_impl_all!</span>(BoxBody: fmt::Debug, MessageBody, Unpin);
<span class="macro">assert_not_impl_any!</span>(BoxBody: Send, Sync);
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>nested_boxed_body() {
<span class="kw">let </span>body = Bytes::from_static(<span class="kw-2">&amp;</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]);
<span class="kw">let </span>boxed_body = BoxBody::new(BoxBody::new(body));
<span class="macro">assert_eq!</span>(
to_bytes(boxed_body).<span class="kw">await</span>.unwrap(),
Bytes::from(<span class="macro">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]),
);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,245 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/body/either.rs`."><title>either.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use </span>pin_project_lite::pin_project;
<span class="kw">use super</span>::{BodySize, BoxBody, MessageBody};
<span class="kw">use </span><span class="kw">crate</span>::Error;
<span class="macro">pin_project!</span> {
<span class="doccomment">/// An "either" type specialized for body types.
///
/// It is common, in middleware especially, to conditionally return an inner service's unknown/
/// generic body `B` type or return early with a new response. This type's "right" variant
/// defaults to `BoxBody` since error responses are the common case.
///
/// For example, middleware will often have `type Response = ServiceResponse&lt;EitherBody&lt;B&gt;&gt;`.
/// This means that the inner service's response body type maps to the `Left` variant and the
/// middleware's own error responses use the default `Right` variant of `BoxBody`. Of course,
/// there's no reason it couldn't use `EitherBody&lt;B, String&gt;` instead if its alternative
/// responses have a known type.
</span><span class="attr">#[project = EitherBodyProj]
#[derive(Debug, Clone)]
</span><span class="kw">pub enum </span>EitherBody&lt;L, R = BoxBody&gt; {
<span class="doccomment">/// A body of type `L`.
</span>Left { <span class="attr">#[pin] </span>body: L },
<span class="doccomment">/// A body of type `R`.
</span>Right { <span class="attr">#[pin] </span>body: R },
}
}
<span class="kw">impl</span>&lt;L&gt; EitherBody&lt;L, BoxBody&gt; {
<span class="doccomment">/// Creates new `EitherBody` left variant with a boxed right variant.
///
/// If the expected `R` type will be inferred and is not `BoxBody` then use the
/// [`left`](Self::left) constructor instead.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>new(body: L) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::Left { body }
}
}
<span class="kw">impl</span>&lt;L, R&gt; EitherBody&lt;L, R&gt; {
<span class="doccomment">/// Creates new `EitherBody` using left variant.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>left(body: L) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::Left { body }
}
<span class="doccomment">/// Creates new `EitherBody` using right variant.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>right(body: R) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::Right { body }
}
}
<span class="kw">impl</span>&lt;L, R&gt; MessageBody <span class="kw">for </span>EitherBody&lt;L, R&gt;
<span class="kw">where
</span>L: MessageBody + <span class="lifetime">'static</span>,
R: MessageBody + <span class="lifetime">'static</span>,
{
<span class="kw">type </span>Error = Error;
<span class="attr">#[inline]
</span><span class="kw">fn </span>size(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; BodySize {
<span class="kw">match </span><span class="self">self </span>{
EitherBody::Left { body } =&gt; body.size(),
EitherBody::Right { body } =&gt; body.size(),
}
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>poll_next(
<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;,
cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="self">Self</span>::Error&gt;&gt;&gt; {
<span class="kw">match </span><span class="self">self</span>.project() {
EitherBodyProj::Left { body } =&gt; body
.poll_next(cx)
.map_err(|err| Error::new_body().with_cause(err)),
EitherBodyProj::Right { body } =&gt; body
.poll_next(cx)
.map_err(|err| Error::new_body().with_cause(err)),
}
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_into_bytes(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Bytes, <span class="self">Self</span>&gt; {
<span class="kw">match </span><span class="self">self </span>{
EitherBody::Left { body } =&gt; body
.try_into_bytes()
.map_err(|body| EitherBody::Left { body }),
EitherBody::Right { body } =&gt; body
.try_into_bytes()
.map_err(|body| EitherBody::Right { body }),
}
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>boxed(<span class="self">self</span>) -&gt; BoxBody {
<span class="kw">match </span><span class="self">self </span>{
EitherBody::Left { body } =&gt; body.boxed(),
EitherBody::Right { body } =&gt; body.boxed(),
}
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>type_parameter_inference() {
<span class="kw">let </span>_body: EitherBody&lt;(), <span class="kw">_</span>&gt; = EitherBody::new(());
<span class="kw">let </span>_body: EitherBody&lt;<span class="kw">_</span>, ()&gt; = EitherBody::left(());
<span class="kw">let </span>_body: EitherBody&lt;(), <span class="kw">_</span>&gt; = EitherBody::right(());
}
}
</code></pre></div></section></main></body></html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/body/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Traits and structures to aid consuming and writing HTTP payloads.
//!
//! "Body" and "payload" are used somewhat interchangeably in this documentation.
</span><span class="comment">// Though the spec kinda reads like "payload" is the possibly-transfer-encoded part of the message
// and the "body" is the intended possibly-decoded version of that.
</span><span class="kw">mod </span>body_stream;
<span class="kw">mod </span>boxed;
<span class="kw">mod </span>either;
<span class="kw">mod </span>message_body;
<span class="kw">mod </span>none;
<span class="kw">mod </span>size;
<span class="kw">mod </span>sized_stream;
<span class="kw">mod </span>utils;
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">use </span><span class="self">self</span>::message_body::MessageBodyMapErr;
<span class="kw">pub use </span><span class="self">self</span>::{
body_stream::BodyStream,
boxed::BoxBody,
either::EitherBody,
message_body::MessageBody,
none::None,
size::BodySize,
sized_stream::SizedStream,
utils::{to_bytes, to_bytes_limited, BodyLimitExceeded},
};
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,103 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/body/none.rs`."><title>none.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
convert::Infallible,
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use super</span>::{BodySize, MessageBody};
<span class="doccomment">/// Body type for responses that forbid payloads.
///
/// This is distinct from an "empty" response which _would_ contain a `Content-Length` header.
/// For an "empty" body, use `()` or `Bytes::new()`.
///
/// For example, the HTTP spec forbids a payload to be sent with a `204 No Content` response.
/// In this case, the payload (or lack thereof) is implicit from the status code, so a
/// `Content-Length` header is not required.
</span><span class="attr">#[derive(Debug, Clone, Copy, Default)]
#[non_exhaustive]
</span><span class="kw">pub struct </span><span class="prelude-val">None</span>;
<span class="kw">impl </span><span class="prelude-val">None </span>{
<span class="doccomment">/// Constructs new "none" body.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>new() -&gt; <span class="self">Self </span>{
<span class="prelude-val">None
</span>}
}
<span class="kw">impl </span>MessageBody <span class="kw">for </span><span class="prelude-val">None </span>{
<span class="kw">type </span>Error = Infallible;
<span class="attr">#[inline]
</span><span class="kw">fn </span>size(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; BodySize {
BodySize::None
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>poll_next(
<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;,
_cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="self">Self</span>::Error&gt;&gt;&gt; {
Poll::Ready(Option::None)
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_into_bytes(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Bytes, <span class="self">Self</span>&gt; {
<span class="prelude-val">Ok</span>(Bytes::new())
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,83 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/body/size.rs`."><title>size.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
</pre></div><pre class="rust"><code><span class="doccomment">/// Body size hint.
</span><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq)]
</span><span class="kw">pub enum </span>BodySize {
<span class="doccomment">/// Implicitly empty body.
///
/// Will omit the Content-Length header. Used for responses to certain methods (e.g., `HEAD`) or
/// with particular status codes (e.g., 204 No Content). Consumers that read this as a body size
/// hint are allowed to make optimizations that skip reading or writing the payload.
</span><span class="prelude-val">None</span>,
<span class="doccomment">/// Known size body.
///
/// Will write `Content-Length: N` header.
</span>Sized(u64),
<span class="doccomment">/// Unknown size body.
///
/// Will not write Content-Length header. Can be used with chunked Transfer-Encoding.
</span>Stream,
}
<span class="kw">impl </span>BodySize {
<span class="doccomment">/// Equivalent to `BodySize::Sized(0)`;
</span><span class="kw">pub const </span>ZERO: <span class="self">Self </span>= <span class="self">Self</span>::Sized(<span class="number">0</span>);
<span class="doccomment">/// Returns true if size hint indicates omitted or empty body.
///
/// Streams will return false because it cannot be known without reading the stream.
///
/// ```
/// # use actix_http::body::BodySize;
/// assert!(BodySize::None.is_eof());
/// assert!(BodySize::Sized(0).is_eof());
///
/// assert!(!BodySize::Sized(64).is_eof());
/// assert!(!BodySize::Stream.is_eof());
/// ```
</span><span class="kw">pub fn </span>is_eof(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="macro">matches!</span>(<span class="self">self</span>, BodySize::None | BodySize::Sized(<span class="number">0</span>))
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,343 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/body/sized_stream.rs`."><title>sized_stream.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
error::Error <span class="kw">as </span>StdError,
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use </span>futures_core::{ready, Stream};
<span class="kw">use </span>pin_project_lite::pin_project;
<span class="kw">use super</span>::{BodySize, MessageBody};
<span class="macro">pin_project!</span> {
<span class="doccomment">/// Known sized streaming response wrapper.
///
/// This body implementation should be used if total size of stream is known. Data is sent as-is
/// without using chunked transfer encoding.
</span><span class="kw">pub struct </span>SizedStream&lt;S&gt; {
size: u64,
<span class="attr">#[pin]
</span>stream: S,
}
}
<span class="kw">impl</span>&lt;S, E&gt; SizedStream&lt;S&gt;
<span class="kw">where
</span>S: Stream&lt;Item = <span class="prelude-ty">Result</span>&lt;Bytes, E&gt;&gt;,
E: Into&lt;Box&lt;<span class="kw">dyn </span>StdError&gt;&gt; + <span class="lifetime">'static</span>,
{
<span class="attr">#[inline]
</span><span class="kw">pub fn </span>new(size: u64, stream: S) -&gt; <span class="self">Self </span>{
SizedStream { size, stream }
}
}
<span class="comment">// TODO: from_infallible method
</span><span class="kw">impl</span>&lt;S, E&gt; MessageBody <span class="kw">for </span>SizedStream&lt;S&gt;
<span class="kw">where
</span>S: Stream&lt;Item = <span class="prelude-ty">Result</span>&lt;Bytes, E&gt;&gt;,
E: Into&lt;Box&lt;<span class="kw">dyn </span>StdError&gt;&gt; + <span class="lifetime">'static</span>,
{
<span class="kw">type </span>Error = E;
<span class="attr">#[inline]
</span><span class="kw">fn </span>size(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; BodySize {
BodySize::Sized(<span class="self">self</span>.size)
}
<span class="doccomment">/// Attempts to pull out the next value of the underlying [`Stream`].
///
/// Empty values are skipped to prevent [`SizedStream`]'s transmission being
/// ended on a zero-length chunk, but rather proceed until the underlying
/// [`Stream`] ends.
</span><span class="kw">fn </span>poll_next(
<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;,
cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="self">Self</span>::Error&gt;&gt;&gt; {
<span class="kw">loop </span>{
<span class="kw">let </span>stream = <span class="self">self</span>.as_mut().project().stream;
<span class="kw">let </span>chunk = <span class="kw">match </span><span class="macro">ready!</span>(stream.poll_next(cx)) {
<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(<span class="kw-2">ref </span>bytes)) <span class="kw">if </span>bytes.is_empty() =&gt; <span class="kw">continue</span>,
val =&gt; val,
};
<span class="kw">return </span>Poll::Ready(chunk);
}
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::convert::Infallible;
<span class="kw">use </span>actix_rt::pin;
<span class="kw">use </span>actix_utils::future::poll_fn;
<span class="kw">use </span>futures_util::stream;
<span class="kw">use </span>static_assertions::{assert_impl_all, assert_not_impl_any};
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use </span><span class="kw">crate</span>::body::to_bytes;
<span class="macro">assert_impl_all!</span>(SizedStream&lt;stream::Empty&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="kw">crate</span>::Error&gt;&gt;&gt;: MessageBody);
<span class="macro">assert_impl_all!</span>(SizedStream&lt;stream::Empty&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str&gt;&gt;&gt;: MessageBody);
<span class="macro">assert_impl_all!</span>(SizedStream&lt;stream::Repeat&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str&gt;&gt;&gt;: MessageBody);
<span class="macro">assert_impl_all!</span>(SizedStream&lt;stream::Empty&lt;<span class="prelude-ty">Result</span>&lt;Bytes, Infallible&gt;&gt;&gt;: MessageBody);
<span class="macro">assert_impl_all!</span>(SizedStream&lt;stream::Repeat&lt;<span class="prelude-ty">Result</span>&lt;Bytes, Infallible&gt;&gt;&gt;: MessageBody);
<span class="macro">assert_not_impl_any!</span>(SizedStream&lt;stream::Empty&lt;Bytes&gt;&gt;: MessageBody);
<span class="macro">assert_not_impl_any!</span>(SizedStream&lt;stream::Repeat&lt;Bytes&gt;&gt;: MessageBody);
<span class="comment">// crate::Error is not Clone
</span><span class="macro">assert_not_impl_any!</span>(SizedStream&lt;stream::Repeat&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="kw">crate</span>::Error&gt;&gt;&gt;: MessageBody);
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>skips_empty_chunks() {
<span class="kw">let </span>body = SizedStream::new(
<span class="number">2</span>,
stream::iter(
[<span class="string">"1"</span>, <span class="string">""</span>, <span class="string">"2"</span>]
.iter()
.map(|<span class="kw-2">&amp;</span>v| <span class="prelude-val">Ok</span>::&lt;<span class="kw">_</span>, Infallible&gt;(Bytes::from(v))),
),
);
<span class="macro">pin!</span>(body);
<span class="macro">assert_eq!</span>(
poll_fn(|cx| body.as_mut().poll_next(cx))
.<span class="kw">await
</span>.unwrap()
.ok(),
<span class="prelude-val">Some</span>(Bytes::from(<span class="string">"1"</span>)),
);
<span class="macro">assert_eq!</span>(
poll_fn(|cx| body.as_mut().poll_next(cx))
.<span class="kw">await
</span>.unwrap()
.ok(),
<span class="prelude-val">Some</span>(Bytes::from(<span class="string">"2"</span>)),
);
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>read_to_bytes() {
<span class="kw">let </span>body = SizedStream::new(
<span class="number">2</span>,
stream::iter(
[<span class="string">"1"</span>, <span class="string">""</span>, <span class="string">"2"</span>]
.iter()
.map(|<span class="kw-2">&amp;</span>v| <span class="prelude-val">Ok</span>::&lt;<span class="kw">_</span>, Infallible&gt;(Bytes::from(v))),
),
);
<span class="macro">assert_eq!</span>(to_bytes(body).<span class="kw">await</span>.ok(), <span class="prelude-val">Some</span>(Bytes::from(<span class="string">"12"</span>)));
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>stream_string_error() {
<span class="comment">// `&amp;'static str` does not impl `Error`
// but it does impl `Into&lt;Box&lt;dyn Error&gt;&gt;`
</span><span class="kw">let </span>body = SizedStream::new(<span class="number">0</span>, stream::once(<span class="kw">async </span>{ <span class="prelude-val">Err</span>(<span class="string">"stringy error"</span>) }));
<span class="macro">assert_eq!</span>(to_bytes(body).<span class="kw">await</span>, <span class="prelude-val">Ok</span>(Bytes::new()));
<span class="kw">let </span>body = SizedStream::new(<span class="number">1</span>, stream::once(<span class="kw">async </span>{ <span class="prelude-val">Err</span>(<span class="string">"stringy error"</span>) }));
<span class="macro">assert!</span>(<span class="macro">matches!</span>(to_bytes(body).<span class="kw">await</span>, <span class="prelude-val">Err</span>(<span class="string">"stringy error"</span>)));
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>stream_boxed_error() {
<span class="comment">// `Box&lt;dyn Error&gt;` does not impl `Error`
// but it does impl `Into&lt;Box&lt;dyn Error&gt;&gt;`
</span><span class="kw">let </span>body = SizedStream::new(
<span class="number">0</span>,
stream::once(<span class="kw">async </span>{ <span class="prelude-val">Err</span>(Box::&lt;<span class="kw">dyn </span>StdError&gt;::from(<span class="string">"stringy error"</span>)) }),
);
<span class="macro">assert_eq!</span>(to_bytes(body).<span class="kw">await</span>.unwrap(), Bytes::new());
<span class="kw">let </span>body = SizedStream::new(
<span class="number">1</span>,
stream::once(<span class="kw">async </span>{ <span class="prelude-val">Err</span>(Box::&lt;<span class="kw">dyn </span>StdError&gt;::from(<span class="string">"stringy error"</span>)) }),
);
<span class="macro">assert_eq!</span>(
to_bytes(body).<span class="kw">await</span>.unwrap_err().to_string(),
<span class="string">"stringy error"
</span>);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,397 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/body/utils.rs`."><title>utils.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::task::Poll;
<span class="kw">use </span>actix_rt::pin;
<span class="kw">use </span>actix_utils::future::poll_fn;
<span class="kw">use </span>bytes::{Bytes, BytesMut};
<span class="kw">use </span>derive_more::{Display, Error};
<span class="kw">use </span>futures_core::ready;
<span class="kw">use super</span>::{BodySize, MessageBody};
<span class="doccomment">/// Collects all the bytes produced by `body`.
///
/// Any errors produced by the body stream are returned immediately.
///
/// Consider using [`to_bytes_limited`] instead to protect against memory exhaustion.
///
/// # Examples
///
/// ```
/// use actix_http::body::{self, to_bytes};
/// use bytes::Bytes;
///
/// # actix_rt::System::new().block_on(async {
/// let body = body::None::new();
/// let bytes = to_bytes(body).await.unwrap();
/// assert!(bytes.is_empty());
///
/// let body = Bytes::from_static(b"123");
/// let bytes = to_bytes(body).await.unwrap();
/// assert_eq!(bytes, "123");
/// # });
/// ```
</span><span class="kw">pub async fn </span>to_bytes&lt;B: MessageBody&gt;(body: B) -&gt; <span class="prelude-ty">Result</span>&lt;Bytes, B::Error&gt; {
to_bytes_limited(body, usize::MAX)
.<span class="kw">await
</span>.expect(<span class="string">"body should never yield more than usize::MAX bytes"</span>)
}
<span class="doccomment">/// Error type returned from [`to_bytes_limited`] when body produced exceeds limit.
</span><span class="attr">#[derive(Debug, Display, Error)]
#[display(fmt = <span class="string">"limit exceeded while collecting body bytes"</span>)]
#[non_exhaustive]
</span><span class="kw">pub struct </span>BodyLimitExceeded;
<span class="doccomment">/// Collects the bytes produced by `body`, up to `limit` bytes.
///
/// If a chunk read from `poll_next` causes the total number of bytes read to exceed `limit`, an
/// `Err(BodyLimitExceeded)` is returned.
///
/// Any errors produced by the body stream are returned immediately as `Ok(Err(B::Error))`.
///
/// # Examples
///
/// ```
/// use actix_http::body::{self, to_bytes_limited};
/// use bytes::Bytes;
///
/// # actix_rt::System::new().block_on(async {
/// let body = body::None::new();
/// let bytes = to_bytes_limited(body, 10).await.unwrap().unwrap();
/// assert!(bytes.is_empty());
///
/// let body = Bytes::from_static(b"123");
/// let bytes = to_bytes_limited(body, 10).await.unwrap().unwrap();
/// assert_eq!(bytes, "123");
///
/// let body = Bytes::from_static(b"123");
/// assert!(to_bytes_limited(body, 2).await.is_err());
/// # });
/// ```
</span><span class="kw">pub async fn </span>to_bytes_limited&lt;B: MessageBody&gt;(
body: B,
limit: usize,
) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Result</span>&lt;Bytes, B::Error&gt;, BodyLimitExceeded&gt; {
<span class="doccomment">/// Sensible default (32kB) for initial, bounded allocation when collecting body bytes.
</span><span class="kw">const </span>INITIAL_ALLOC_BYTES: usize = <span class="number">32 </span>* <span class="number">1024</span>;
<span class="kw">let </span>cap = <span class="kw">match </span>body.size() {
BodySize::None | BodySize::Sized(<span class="number">0</span>) =&gt; <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">Ok</span>(Bytes::new())),
BodySize::Sized(size) <span class="kw">if </span>size <span class="kw">as </span>usize &gt; limit =&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(BodyLimitExceeded),
BodySize::Sized(size) =&gt; (size <span class="kw">as </span>usize).min(INITIAL_ALLOC_BYTES),
BodySize::Stream =&gt; INITIAL_ALLOC_BYTES,
};
<span class="kw">let </span><span class="kw-2">mut </span>exceeded_limit = <span class="bool-val">false</span>;
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::with_capacity(cap);
<span class="macro">pin!</span>(body);
<span class="kw">match </span>poll_fn(|cx| <span class="kw">loop </span>{
<span class="kw">let </span>body = body.as_mut();
<span class="kw">match </span><span class="macro">ready!</span>(body.poll_next(cx)) {
<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(bytes)) =&gt; {
<span class="comment">// if limit is exceeded...
</span><span class="kw">if </span>buf.len() + bytes.len() &gt; limit {
<span class="comment">// ...set flag to true and break out of poll_fn
</span>exceeded_limit = <span class="bool-val">true</span>;
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">Ok</span>(()));
}
buf.extend_from_slice(<span class="kw-2">&amp;</span>bytes)
}
<span class="prelude-val">None </span>=&gt; <span class="kw">return </span>Poll::Ready(<span class="prelude-val">Ok</span>(())),
<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err)) =&gt; <span class="kw">return </span>Poll::Ready(<span class="prelude-val">Err</span>(err)),
}
})
.<span class="kw">await
</span>{
<span class="comment">// propagate error returned from body poll
</span><span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">Err</span>(err)),
<span class="comment">// limit was exceeded while reading body
</span><span class="prelude-val">Ok</span>(()) <span class="kw">if </span>exceeded_limit =&gt; <span class="prelude-val">Err</span>(BodyLimitExceeded),
<span class="comment">// otherwise return body buffer
</span><span class="prelude-val">Ok</span>(()) =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">Ok</span>(buf.freeze())),
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::io;
<span class="kw">use </span>futures_util::{stream, StreamExt <span class="kw">as _</span>};
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use crate</span>::{
body::{BodyStream, SizedStream},
Error,
};
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>to_bytes_complete() {
<span class="kw">let </span>bytes = to_bytes(()).<span class="kw">await</span>.unwrap();
<span class="macro">assert!</span>(bytes.is_empty());
<span class="kw">let </span>body = Bytes::from_static(<span class="string">b"123"</span>);
<span class="kw">let </span>bytes = to_bytes(body).<span class="kw">await</span>.unwrap();
<span class="macro">assert_eq!</span>(bytes, <span class="string">b"123"</span>[..]);
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>to_bytes_streams() {
<span class="kw">let </span>stream = stream::iter(<span class="macro">vec!</span>[Bytes::from_static(<span class="string">b"123"</span>), Bytes::from_static(<span class="string">b"abc"</span>)])
.map(<span class="prelude-val">Ok</span>::&lt;<span class="kw">_</span>, Error&gt;);
<span class="kw">let </span>body = BodyStream::new(stream);
<span class="kw">let </span>bytes = to_bytes(body).<span class="kw">await</span>.unwrap();
<span class="macro">assert_eq!</span>(bytes, <span class="string">b"123abc"</span>[..]);
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>to_bytes_limited_complete() {
<span class="kw">let </span>bytes = to_bytes_limited((), <span class="number">0</span>).<span class="kw">await</span>.unwrap().unwrap();
<span class="macro">assert!</span>(bytes.is_empty());
<span class="kw">let </span>bytes = to_bytes_limited((), <span class="number">1</span>).<span class="kw">await</span>.unwrap().unwrap();
<span class="macro">assert!</span>(bytes.is_empty());
<span class="macro">assert!</span>(to_bytes_limited(Bytes::from_static(<span class="string">b"12"</span>), <span class="number">0</span>)
.<span class="kw">await
</span>.is_err());
<span class="macro">assert!</span>(to_bytes_limited(Bytes::from_static(<span class="string">b"12"</span>), <span class="number">1</span>)
.<span class="kw">await
</span>.is_err());
<span class="macro">assert!</span>(to_bytes_limited(Bytes::from_static(<span class="string">b"12"</span>), <span class="number">2</span>).<span class="kw">await</span>.is_ok());
<span class="macro">assert!</span>(to_bytes_limited(Bytes::from_static(<span class="string">b"12"</span>), <span class="number">3</span>).<span class="kw">await</span>.is_ok());
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>to_bytes_limited_streams() {
<span class="comment">// hinting a larger body fails
</span><span class="kw">let </span>body = SizedStream::new(<span class="number">8</span>, stream::empty().map(<span class="prelude-val">Ok</span>::&lt;<span class="kw">_</span>, Error&gt;));
<span class="macro">assert!</span>(to_bytes_limited(body, <span class="number">3</span>).<span class="kw">await</span>.is_err());
<span class="comment">// hinting a smaller body is okay
</span><span class="kw">let </span>body = SizedStream::new(<span class="number">3</span>, stream::empty().map(<span class="prelude-val">Ok</span>::&lt;<span class="kw">_</span>, Error&gt;));
<span class="macro">assert!</span>(to_bytes_limited(body, <span class="number">3</span>).<span class="kw">await</span>.unwrap().unwrap().is_empty());
<span class="comment">// hinting a smaller body then returning a larger one fails
</span><span class="kw">let </span>stream = stream::iter(<span class="macro">vec!</span>[Bytes::from_static(<span class="string">b"1234"</span>)]).map(<span class="prelude-val">Ok</span>::&lt;<span class="kw">_</span>, Error&gt;);
<span class="kw">let </span>body = SizedStream::new(<span class="number">3</span>, stream);
<span class="macro">assert!</span>(to_bytes_limited(body, <span class="number">3</span>).<span class="kw">await</span>.is_err());
<span class="kw">let </span>stream = stream::iter(<span class="macro">vec!</span>[Bytes::from_static(<span class="string">b"123"</span>), Bytes::from_static(<span class="string">b"abc"</span>)])
.map(<span class="prelude-val">Ok</span>::&lt;<span class="kw">_</span>, Error&gt;);
<span class="kw">let </span>body = BodyStream::new(stream);
<span class="macro">assert!</span>(to_bytes_limited(body, <span class="number">3</span>).<span class="kw">await</span>.is_err());
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>to_body_limit_error() {
<span class="kw">let </span>err_stream = stream::once(<span class="kw">async </span>{ <span class="prelude-val">Err</span>(io::Error::new(io::ErrorKind::Other, <span class="string">""</span>)) });
<span class="kw">let </span>body = SizedStream::new(<span class="number">8</span>, err_stream);
<span class="comment">// not too big, but propagates error from body stream
</span><span class="macro">assert!</span>(to_bytes_limited(body, <span class="number">10</span>).<span class="kw">await</span>.unwrap().is_err());
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,517 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/builder.rs`."><title>builder.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{fmt, marker::PhantomData, net, rc::Rc, time::Duration};
<span class="kw">use </span>actix_codec::Framed;
<span class="kw">use </span>actix_service::{IntoServiceFactory, Service, ServiceFactory};
<span class="kw">use crate</span>::{
body::{BoxBody, MessageBody},
h1::{<span class="self">self</span>, ExpectHandler, H1Service, UpgradeHandler},
service::HttpService,
ConnectCallback, Extensions, KeepAlive, Request, Response, ServiceConfig,
};
<span class="doccomment">/// An HTTP service builder.
///
/// This type can construct an instance of [`HttpService`] through a builder-like pattern.
</span><span class="kw">pub struct </span>HttpServiceBuilder&lt;T, S, X = ExpectHandler, U = UpgradeHandler&gt; {
keep_alive: KeepAlive,
client_request_timeout: Duration,
client_disconnect_timeout: Duration,
secure: bool,
local_addr: <span class="prelude-ty">Option</span>&lt;net::SocketAddr&gt;,
expect: X,
upgrade: <span class="prelude-ty">Option</span>&lt;U&gt;,
on_connect_ext: <span class="prelude-ty">Option</span>&lt;Rc&lt;ConnectCallback&lt;T&gt;&gt;&gt;,
_phantom: PhantomData&lt;S&gt;,
}
<span class="kw">impl</span>&lt;T, S&gt; Default <span class="kw">for </span>HttpServiceBuilder&lt;T, S, ExpectHandler, UpgradeHandler&gt;
<span class="kw">where
</span>S: ServiceFactory&lt;Request, Config = ()&gt;,
S::Error: Into&lt;Response&lt;BoxBody&gt;&gt; + <span class="lifetime">'static</span>,
S::InitError: fmt::Debug,
&lt;S::Service <span class="kw">as </span>Service&lt;Request&gt;&gt;::Future: <span class="lifetime">'static</span>,
{
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
HttpServiceBuilder {
<span class="comment">// ServiceConfig parts (make sure defaults match)
</span>keep_alive: KeepAlive::default(),
client_request_timeout: Duration::from_secs(<span class="number">5</span>),
client_disconnect_timeout: Duration::ZERO,
secure: <span class="bool-val">false</span>,
local_addr: <span class="prelude-val">None</span>,
<span class="comment">// dispatcher parts
</span>expect: ExpectHandler,
upgrade: <span class="prelude-val">None</span>,
on_connect_ext: <span class="prelude-val">None</span>,
_phantom: PhantomData,
}
}
}
<span class="kw">impl</span>&lt;T, S, X, U&gt; HttpServiceBuilder&lt;T, S, X, U&gt;
<span class="kw">where
</span>S: ServiceFactory&lt;Request, Config = ()&gt;,
S::Error: Into&lt;Response&lt;BoxBody&gt;&gt; + <span class="lifetime">'static</span>,
S::InitError: fmt::Debug,
&lt;S::Service <span class="kw">as </span>Service&lt;Request&gt;&gt;::Future: <span class="lifetime">'static</span>,
X: ServiceFactory&lt;Request, Config = (), Response = Request&gt;,
X::Error: Into&lt;Response&lt;BoxBody&gt;&gt;,
X::InitError: fmt::Debug,
U: ServiceFactory&lt;(Request, Framed&lt;T, h1::Codec&gt;), Config = (), Response = ()&gt;,
U::Error: fmt::Display,
U::InitError: fmt::Debug,
{
<span class="doccomment">/// Set connection keep-alive setting.
///
/// Applies to HTTP/1.1 keep-alive and HTTP/2 ping-pong.
///
/// By default keep-alive is 5 seconds.
</span><span class="kw">pub fn </span>keep_alive&lt;W: Into&lt;KeepAlive&gt;&gt;(<span class="kw-2">mut </span><span class="self">self</span>, val: W) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.keep_alive = val.into();
<span class="self">self
</span>}
<span class="doccomment">/// Set connection secure state
</span><span class="kw">pub fn </span>secure(<span class="kw-2">mut </span><span class="self">self</span>) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.secure = <span class="bool-val">true</span>;
<span class="self">self
</span>}
<span class="doccomment">/// Set the local address that this service is bound to.
</span><span class="kw">pub fn </span>local_addr(<span class="kw-2">mut </span><span class="self">self</span>, addr: net::SocketAddr) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.local_addr = <span class="prelude-val">Some</span>(addr);
<span class="self">self
</span>}
<span class="doccomment">/// Set client request timeout (for first request).
///
/// Defines a timeout for reading client request header. If the client does not transmit the
/// request head within this duration, the connection is terminated with a `408 Request Timeout`
/// response error.
///
/// A duration of zero disables the timeout.
///
/// By default, the client timeout is 5 seconds.
</span><span class="kw">pub fn </span>client_request_timeout(<span class="kw-2">mut </span><span class="self">self</span>, dur: Duration) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.client_request_timeout = dur;
<span class="self">self
</span>}
<span class="attr">#[doc(hidden)]
#[deprecated(since = <span class="string">"3.0.0"</span>, note = <span class="string">"Renamed to `client_request_timeout`."</span>)]
</span><span class="kw">pub fn </span>client_timeout(<span class="self">self</span>, dur: Duration) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.client_request_timeout(dur)
}
<span class="doccomment">/// Set client connection disconnect timeout.
///
/// Defines a timeout for disconnect connection. If a disconnect procedure does not complete
/// within this time, the request get dropped. This timeout affects secure connections.
///
/// A duration of zero disables the timeout.
///
/// By default, the disconnect timeout is disabled.
</span><span class="kw">pub fn </span>client_disconnect_timeout(<span class="kw-2">mut </span><span class="self">self</span>, dur: Duration) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.client_disconnect_timeout = dur;
<span class="self">self
</span>}
<span class="attr">#[doc(hidden)]
#[deprecated(since = <span class="string">"3.0.0"</span>, note = <span class="string">"Renamed to `client_disconnect_timeout`."</span>)]
</span><span class="kw">pub fn </span>client_disconnect(<span class="self">self</span>, dur: Duration) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.client_disconnect_timeout(dur)
}
<span class="doccomment">/// Provide service for `EXPECT: 100-Continue` support.
///
/// Service get called with request that contains `EXPECT` header.
/// Service must return request in case of success, in that case
/// request will be forwarded to main service.
</span><span class="kw">pub fn </span>expect&lt;F, X1&gt;(<span class="self">self</span>, expect: F) -&gt; HttpServiceBuilder&lt;T, S, X1, U&gt;
<span class="kw">where
</span>F: IntoServiceFactory&lt;X1, Request&gt;,
X1: ServiceFactory&lt;Request, Config = (), Response = Request&gt;,
X1::Error: Into&lt;Response&lt;BoxBody&gt;&gt;,
X1::InitError: fmt::Debug,
{
HttpServiceBuilder {
keep_alive: <span class="self">self</span>.keep_alive,
client_request_timeout: <span class="self">self</span>.client_request_timeout,
client_disconnect_timeout: <span class="self">self</span>.client_disconnect_timeout,
secure: <span class="self">self</span>.secure,
local_addr: <span class="self">self</span>.local_addr,
expect: expect.into_factory(),
upgrade: <span class="self">self</span>.upgrade,
on_connect_ext: <span class="self">self</span>.on_connect_ext,
_phantom: PhantomData,
}
}
<span class="doccomment">/// Provide service for custom `Connection: UPGRADE` support.
///
/// If service is provided then normal requests handling get halted
/// and this service get called with original request and framed object.
</span><span class="kw">pub fn </span>upgrade&lt;F, U1&gt;(<span class="self">self</span>, upgrade: F) -&gt; HttpServiceBuilder&lt;T, S, X, U1&gt;
<span class="kw">where
</span>F: IntoServiceFactory&lt;U1, (Request, Framed&lt;T, h1::Codec&gt;)&gt;,
U1: ServiceFactory&lt;(Request, Framed&lt;T, h1::Codec&gt;), Config = (), Response = ()&gt;,
U1::Error: fmt::Display,
U1::InitError: fmt::Debug,
{
HttpServiceBuilder {
keep_alive: <span class="self">self</span>.keep_alive,
client_request_timeout: <span class="self">self</span>.client_request_timeout,
client_disconnect_timeout: <span class="self">self</span>.client_disconnect_timeout,
secure: <span class="self">self</span>.secure,
local_addr: <span class="self">self</span>.local_addr,
expect: <span class="self">self</span>.expect,
upgrade: <span class="prelude-val">Some</span>(upgrade.into_factory()),
on_connect_ext: <span class="self">self</span>.on_connect_ext,
_phantom: PhantomData,
}
}
<span class="doccomment">/// Sets the callback to be run on connection establishment.
///
/// Has mutable access to a data container that will be merged into request extensions.
/// This enables transport layer data (like client certificates) to be accessed in middleware
/// and handlers.
</span><span class="kw">pub fn </span>on_connect_ext&lt;F&gt;(<span class="kw-2">mut </span><span class="self">self</span>, f: F) -&gt; <span class="self">Self
</span><span class="kw">where
</span>F: Fn(<span class="kw-2">&amp;</span>T, <span class="kw-2">&amp;mut </span>Extensions) + <span class="lifetime">'static</span>,
{
<span class="self">self</span>.on_connect_ext = <span class="prelude-val">Some</span>(Rc::new(f));
<span class="self">self
</span>}
<span class="doccomment">/// Finish service configuration and create a service for the HTTP/1 protocol.
</span><span class="kw">pub fn </span>h1&lt;F, B&gt;(<span class="self">self</span>, service: F) -&gt; H1Service&lt;T, S, B, X, U&gt;
<span class="kw">where
</span>B: MessageBody,
F: IntoServiceFactory&lt;S, Request&gt;,
S::Error: Into&lt;Response&lt;BoxBody&gt;&gt;,
S::InitError: fmt::Debug,
S::Response: Into&lt;Response&lt;B&gt;&gt;,
{
<span class="kw">let </span>cfg = ServiceConfig::new(
<span class="self">self</span>.keep_alive,
<span class="self">self</span>.client_request_timeout,
<span class="self">self</span>.client_disconnect_timeout,
<span class="self">self</span>.secure,
<span class="self">self</span>.local_addr,
);
H1Service::with_config(cfg, service.into_factory())
.expect(<span class="self">self</span>.expect)
.upgrade(<span class="self">self</span>.upgrade)
.on_connect_ext(<span class="self">self</span>.on_connect_ext)
}
<span class="doccomment">/// Finish service configuration and create a service for the HTTP/2 protocol.
</span><span class="attr">#[cfg(feature = <span class="string">"http2"</span>)]
</span><span class="kw">pub fn </span>h2&lt;F, B&gt;(<span class="self">self</span>, service: F) -&gt; <span class="kw">crate</span>::h2::H2Service&lt;T, S, B&gt;
<span class="kw">where
</span>F: IntoServiceFactory&lt;S, Request&gt;,
S::Error: Into&lt;Response&lt;BoxBody&gt;&gt; + <span class="lifetime">'static</span>,
S::InitError: fmt::Debug,
S::Response: Into&lt;Response&lt;B&gt;&gt; + <span class="lifetime">'static</span>,
B: MessageBody + <span class="lifetime">'static</span>,
{
<span class="kw">let </span>cfg = ServiceConfig::new(
<span class="self">self</span>.keep_alive,
<span class="self">self</span>.client_request_timeout,
<span class="self">self</span>.client_disconnect_timeout,
<span class="self">self</span>.secure,
<span class="self">self</span>.local_addr,
);
<span class="kw">crate</span>::h2::H2Service::with_config(cfg, service.into_factory())
.on_connect_ext(<span class="self">self</span>.on_connect_ext)
}
<span class="doccomment">/// Finish service configuration and create `HttpService` instance.
</span><span class="kw">pub fn </span>finish&lt;F, B&gt;(<span class="self">self</span>, service: F) -&gt; HttpService&lt;T, S, B, X, U&gt;
<span class="kw">where
</span>F: IntoServiceFactory&lt;S, Request&gt;,
S::Error: Into&lt;Response&lt;BoxBody&gt;&gt; + <span class="lifetime">'static</span>,
S::InitError: fmt::Debug,
S::Response: Into&lt;Response&lt;B&gt;&gt; + <span class="lifetime">'static</span>,
B: MessageBody + <span class="lifetime">'static</span>,
{
<span class="kw">let </span>cfg = ServiceConfig::new(
<span class="self">self</span>.keep_alive,
<span class="self">self</span>.client_request_timeout,
<span class="self">self</span>.client_disconnect_timeout,
<span class="self">self</span>.secure,
<span class="self">self</span>.local_addr,
);
HttpService::with_config(cfg, service.into_factory())
.expect(<span class="self">self</span>.expect)
.upgrade(<span class="self">self</span>.upgrade)
.on_connect_ext(<span class="self">self</span>.on_connect_ext)
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,473 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/config.rs`."><title>config.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
net,
rc::Rc,
time::{Duration, Instant},
};
<span class="kw">use </span>bytes::BytesMut;
<span class="kw">use crate</span>::{date::DateService, KeepAlive};
<span class="doccomment">/// HTTP service configuration.
</span><span class="attr">#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>ServiceConfig(Rc&lt;Inner&gt;);
<span class="attr">#[derive(Debug)]
</span><span class="kw">struct </span>Inner {
keep_alive: KeepAlive,
client_request_timeout: Duration,
client_disconnect_timeout: Duration,
secure: bool,
local_addr: <span class="prelude-ty">Option</span>&lt;std::net::SocketAddr&gt;,
date_service: DateService,
}
<span class="kw">impl </span>Default <span class="kw">for </span>ServiceConfig {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(
KeepAlive::default(),
Duration::from_secs(<span class="number">5</span>),
Duration::ZERO,
<span class="bool-val">false</span>,
<span class="prelude-val">None</span>,
)
}
}
<span class="kw">impl </span>ServiceConfig {
<span class="doccomment">/// Create instance of `ServiceConfig`.
</span><span class="kw">pub fn </span>new(
keep_alive: KeepAlive,
client_request_timeout: Duration,
client_disconnect_timeout: Duration,
secure: bool,
local_addr: <span class="prelude-ty">Option</span>&lt;net::SocketAddr&gt;,
) -&gt; ServiceConfig {
ServiceConfig(Rc::new(Inner {
keep_alive: keep_alive.normalize(),
client_request_timeout,
client_disconnect_timeout,
secure,
local_addr,
date_service: DateService::new(),
}))
}
<span class="doccomment">/// Returns `true` if connection is secure (i.e., using TLS / HTTPS).
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>secure(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.<span class="number">0</span>.secure
}
<span class="doccomment">/// Returns the local address that this server is bound to.
///
/// Returns `None` for connections via UDS (Unix Domain Socket).
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>local_addr(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;net::SocketAddr&gt; {
<span class="self">self</span>.<span class="number">0</span>.local_addr
}
<span class="doccomment">/// Connection keep-alive setting.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>keep_alive(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; KeepAlive {
<span class="self">self</span>.<span class="number">0</span>.keep_alive
}
<span class="doccomment">/// Creates a time object representing the deadline for this connection's keep-alive period, if
/// enabled.
///
/// When [`KeepAlive::Os`] or [`KeepAlive::Disabled`] is set, this will return `None`.
</span><span class="kw">pub fn </span>keep_alive_deadline(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;Instant&gt; {
<span class="kw">match </span><span class="self">self</span>.keep_alive() {
KeepAlive::Timeout(dur) =&gt; <span class="prelude-val">Some</span>(<span class="self">self</span>.now() + dur),
KeepAlive::Os =&gt; <span class="prelude-val">None</span>,
KeepAlive::Disabled =&gt; <span class="prelude-val">None</span>,
}
}
<span class="doccomment">/// Creates a time object representing the deadline for the client to finish sending the head of
/// its first request.
///
/// Returns `None` if this `ServiceConfig was` constructed with `client_request_timeout: 0`.
</span><span class="kw">pub fn </span>client_request_deadline(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;Instant&gt; {
<span class="kw">let </span>timeout = <span class="self">self</span>.<span class="number">0</span>.client_request_timeout;
(timeout != Duration::ZERO).then(|| <span class="self">self</span>.now() + timeout)
}
<span class="doccomment">/// Creates a time object representing the deadline for the client to disconnect.
</span><span class="kw">pub fn </span>client_disconnect_deadline(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;Instant&gt; {
<span class="kw">let </span>timeout = <span class="self">self</span>.<span class="number">0</span>.client_disconnect_timeout;
(timeout != Duration::ZERO).then(|| <span class="self">self</span>.now() + timeout)
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>now(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Instant {
<span class="self">self</span>.<span class="number">0</span>.date_service.now()
}
<span class="doccomment">/// Writes date header to `dst` buffer.
///
/// Low-level method that utilizes the built-in efficient date service, requiring fewer syscalls
/// than normal. Note that a CRLF (`\r\n`) is included in what is written.
</span><span class="attr">#[doc(hidden)]
</span><span class="kw">pub fn </span>write_date_header(<span class="kw-2">&amp;</span><span class="self">self</span>, dst: <span class="kw-2">&amp;mut </span>BytesMut, camel_case: bool) {
<span class="kw">let </span><span class="kw-2">mut </span>buf: [u8; <span class="number">37</span>] = [<span class="number">0</span>; <span class="number">37</span>];
buf[..<span class="number">6</span>].copy_from_slice(<span class="kw">if </span>camel_case { <span class="string">b"Date: " </span>} <span class="kw">else </span>{ <span class="string">b"date: " </span>});
<span class="self">self</span>.<span class="number">0
</span>.date_service
.with_date(|date| buf[<span class="number">6</span>..<span class="number">35</span>].copy_from_slice(<span class="kw-2">&amp;</span>date.bytes));
buf[<span class="number">35</span>..].copy_from_slice(<span class="string">b"\r\n"</span>);
dst.extend_from_slice(<span class="kw-2">&amp;</span>buf);
}
<span class="attr">#[allow(unused)] </span><span class="comment">// used with `http2` feature flag
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>write_date_header_value(<span class="kw-2">&amp;</span><span class="self">self</span>, dst: <span class="kw-2">&amp;mut </span>BytesMut) {
<span class="self">self</span>.<span class="number">0
</span>.date_service
.with_date(|date| dst.extend_from_slice(<span class="kw-2">&amp;</span>date.bytes));
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>actix_rt::{
task::yield_now,
time::{sleep, sleep_until},
};
<span class="kw">use </span>memchr::memmem;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use crate</span>::{date::DATE_VALUE_LENGTH, notify_on_drop};
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>test_date_service_update() {
<span class="kw">let </span>settings =
ServiceConfig::new(KeepAlive::Os, Duration::ZERO, Duration::ZERO, <span class="bool-val">false</span>, <span class="prelude-val">None</span>);
yield_now().<span class="kw">await</span>;
<span class="kw">let </span><span class="kw-2">mut </span>buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + <span class="number">10</span>);
settings.write_date_header(<span class="kw-2">&amp;mut </span>buf1, <span class="bool-val">false</span>);
<span class="kw">let </span>now1 = settings.now();
sleep_until((Instant::now() + Duration::from_secs(<span class="number">2</span>)).into()).<span class="kw">await</span>;
yield_now().<span class="kw">await</span>;
<span class="kw">let </span>now2 = settings.now();
<span class="kw">let </span><span class="kw-2">mut </span>buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + <span class="number">10</span>);
settings.write_date_header(<span class="kw-2">&amp;mut </span>buf2, <span class="bool-val">false</span>);
<span class="macro">assert_ne!</span>(now1, now2);
<span class="macro">assert_ne!</span>(buf1, buf2);
drop(settings);
<span class="comment">// Ensure the task will drop eventually
</span><span class="kw">let </span><span class="kw-2">mut </span>times = <span class="number">0</span>;
<span class="kw">while </span>!notify_on_drop::is_dropped() {
sleep(Duration::from_millis(<span class="number">100</span>)).<span class="kw">await</span>;
times += <span class="number">1</span>;
<span class="macro">assert!</span>(times &lt; <span class="number">10</span>, <span class="string">"Timeout waiting for task drop"</span>);
}
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>test_date_service_drop() {
<span class="kw">let </span>service = Rc::new(DateService::new());
<span class="comment">// yield so date service have a chance to register the spawned timer update task.
</span>yield_now().<span class="kw">await</span>;
<span class="kw">let </span>clone1 = service.clone();
<span class="kw">let </span>clone2 = service.clone();
<span class="kw">let </span>clone3 = service.clone();
drop(clone1);
<span class="macro">assert!</span>(!notify_on_drop::is_dropped());
drop(clone2);
<span class="macro">assert!</span>(!notify_on_drop::is_dropped());
drop(clone3);
<span class="macro">assert!</span>(!notify_on_drop::is_dropped());
drop(service);
<span class="comment">// Ensure the task will drop eventually
</span><span class="kw">let </span><span class="kw-2">mut </span>times = <span class="number">0</span>;
<span class="kw">while </span>!notify_on_drop::is_dropped() {
sleep(Duration::from_millis(<span class="number">100</span>)).<span class="kw">await</span>;
times += <span class="number">1</span>;
<span class="macro">assert!</span>(times &lt; <span class="number">10</span>, <span class="string">"Timeout waiting for task drop"</span>);
}
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_date_len() {
<span class="macro">assert_eq!</span>(DATE_VALUE_LENGTH, <span class="string">"Sun, 06 Nov 1994 08:49:37 GMT"</span>.len());
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>test_date() {
<span class="kw">let </span>settings = ServiceConfig::default();
<span class="kw">let </span><span class="kw-2">mut </span>buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + <span class="number">10</span>);
settings.write_date_header(<span class="kw-2">&amp;mut </span>buf1, <span class="bool-val">false</span>);
<span class="kw">let </span><span class="kw-2">mut </span>buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + <span class="number">10</span>);
settings.write_date_header(<span class="kw-2">&amp;mut </span>buf2, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(buf1, buf2);
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>test_date_camel_case() {
<span class="kw">let </span>settings = ServiceConfig::default();
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + <span class="number">10</span>);
settings.write_date_header(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>);
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>buf, <span class="string">b"date:"</span>).is_some());
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + <span class="number">10</span>);
settings.write_date_header(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">true</span>);
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>buf, <span class="string">b"Date:"</span>).is_some());
}
}
</code></pre></div></section></main></body></html>

185
src/actix_http/date.rs.html Normal file
View File

@ -0,0 +1,185 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/date.rs`."><title>date.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
cell::Cell,
fmt::{<span class="self">self</span>, Write},
rc::Rc,
time::{Duration, Instant, SystemTime},
};
<span class="kw">use </span>actix_rt::{task::JoinHandle, time::interval};
<span class="doccomment">/// "Thu, 01 Jan 1970 00:00:00 GMT".len()
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>DATE_VALUE_LENGTH: usize = <span class="number">29</span>;
<span class="attr">#[derive(Clone, Copy)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>Date {
<span class="kw">pub</span>(<span class="kw">crate</span>) bytes: [u8; DATE_VALUE_LENGTH],
pos: usize,
}
<span class="kw">impl </span>Date {
<span class="kw">fn </span>new() -&gt; Date {
<span class="kw">let </span><span class="kw-2">mut </span>date = Date {
bytes: [<span class="number">0</span>; DATE_VALUE_LENGTH],
pos: <span class="number">0</span>,
};
date.update();
date
}
<span class="kw">fn </span>update(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="self">self</span>.pos = <span class="number">0</span>;
<span class="macro">write!</span>(<span class="self">self</span>, <span class="string">"{}"</span>, httpdate::HttpDate::from(SystemTime::now())).unwrap();
}
}
<span class="kw">impl </span>fmt::Write <span class="kw">for </span>Date {
<span class="kw">fn </span>write_str(<span class="kw-2">&amp;mut </span><span class="self">self</span>, s: <span class="kw-2">&amp;</span>str) -&gt; fmt::Result {
<span class="kw">let </span>len = s.len();
<span class="self">self</span>.bytes[<span class="self">self</span>.pos..<span class="self">self</span>.pos + len].copy_from_slice(s.as_bytes());
<span class="self">self</span>.pos += len;
<span class="prelude-val">Ok</span>(())
}
}
<span class="doccomment">/// Service for update Date and Instant periodically at 500 millis interval.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>DateService {
current: Rc&lt;Cell&lt;(Date, Instant)&gt;&gt;,
handle: JoinHandle&lt;()&gt;,
}
<span class="kw">impl </span>DateService {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new() -&gt; <span class="self">Self </span>{
<span class="comment">// shared date and timer for DateService and update async task.
</span><span class="kw">let </span>current = Rc::new(Cell::new((Date::new(), Instant::now())));
<span class="kw">let </span>current_clone = Rc::clone(<span class="kw-2">&amp;</span>current);
<span class="comment">// spawn an async task sleep for 500 millis and update current date/timer in a loop.
// handle is used to stop the task on DateService drop.
</span><span class="kw">let </span>handle = actix_rt::spawn(<span class="kw">async move </span>{
<span class="attr">#[cfg(test)]
</span><span class="kw">let </span>_notify = <span class="kw">crate</span>::notify_on_drop::NotifyOnDrop::new();
<span class="kw">let </span><span class="kw-2">mut </span>interval = interval(Duration::from_millis(<span class="number">500</span>));
<span class="kw">loop </span>{
<span class="kw">let </span>now = interval.tick().<span class="kw">await</span>;
<span class="kw">let </span>date = Date::new();
current_clone.set((date, now.into_std()));
}
});
DateService { current, handle }
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>now(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Instant {
<span class="self">self</span>.current.get().<span class="number">1
</span>}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>with_date&lt;F: FnMut(<span class="kw-2">&amp;</span>Date)&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw-2">mut </span>f: F) {
f(<span class="kw-2">&amp;</span><span class="self">self</span>.current.get().<span class="number">0</span>);
}
}
<span class="kw">impl </span>fmt::Debug <span class="kw">for </span>DateService {
<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">'_</span>&gt;) -&gt; fmt::Result {
f.debug_struct(<span class="string">"DateService"</span>).finish_non_exhaustive()
}
}
<span class="kw">impl </span>Drop <span class="kw">for </span>DateService {
<span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="comment">// stop the timer update async task on drop.
</span><span class="self">self</span>.handle.abort();
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,605 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/encoding/decoder.rs`."><title>decoder.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Stream decoders.
</span><span class="kw">use </span>std::{
future::Future,
io::{<span class="self">self</span>, Write <span class="kw">as _</span>},
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>actix_rt::task::{spawn_blocking, JoinHandle};
<span class="kw">use </span>bytes::Bytes;
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span><span class="kw">use </span>flate2::write::{GzDecoder, ZlibDecoder};
<span class="kw">use </span>futures_core::{ready, Stream};
<span class="attr">#[cfg(feature = <span class="string">"compress-zstd"</span>)]
</span><span class="kw">use </span>zstd::stream::write::Decoder <span class="kw">as </span>ZstdDecoder;
<span class="kw">use crate</span>::{
encoding::Writer,
error::PayloadError,
header::{ContentEncoding, HeaderMap, CONTENT_ENCODING},
};
<span class="kw">const </span>MAX_CHUNK_SIZE_DECODE_IN_PLACE: usize = <span class="number">2049</span>;
<span class="macro">pin_project_lite::pin_project!</span> {
<span class="kw">pub struct </span>Decoder&lt;S&gt; {
decoder: <span class="prelude-ty">Option</span>&lt;ContentDecoder&gt;,
<span class="attr">#[pin]
</span>stream: S,
eof: bool,
fut: <span class="prelude-ty">Option</span>&lt;JoinHandle&lt;<span class="prelude-ty">Result</span>&lt;(<span class="prelude-ty">Option</span>&lt;Bytes&gt;, ContentDecoder), io::Error&gt;&gt;&gt;,
}
}
<span class="kw">impl</span>&lt;S&gt; Decoder&lt;S&gt;
<span class="kw">where
</span>S: Stream&lt;Item = <span class="prelude-ty">Result</span>&lt;Bytes, PayloadError&gt;&gt;,
{
<span class="doccomment">/// Construct a decoder.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>new(stream: S, encoding: ContentEncoding) -&gt; Decoder&lt;S&gt; {
<span class="kw">let </span>decoder = <span class="kw">match </span>encoding {
<span class="attr">#[cfg(feature = <span class="string">"compress-brotli"</span>)]
</span>ContentEncoding::Brotli =&gt; <span class="prelude-val">Some</span>(ContentDecoder::Brotli(Box::new(
brotli::DecompressorWriter::new(Writer::new(), <span class="number">8_096</span>),
))),
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentEncoding::Deflate =&gt; <span class="prelude-val">Some</span>(ContentDecoder::Deflate(Box::new(ZlibDecoder::new(
Writer::new(),
)))),
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentEncoding::Gzip =&gt; <span class="prelude-val">Some</span>(ContentDecoder::Gzip(Box::new(GzDecoder::new(
Writer::new(),
)))),
<span class="attr">#[cfg(feature = <span class="string">"compress-zstd"</span>)]
</span>ContentEncoding::Zstd =&gt; <span class="prelude-val">Some</span>(ContentDecoder::Zstd(Box::new(
ZstdDecoder::new(Writer::new()).expect(
<span class="string">"Failed to create zstd decoder. This is a bug. \
Please report it to the actix-web repository."</span>,
),
))),
<span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
};
Decoder {
decoder,
stream,
fut: <span class="prelude-val">None</span>,
eof: <span class="bool-val">false</span>,
}
}
<span class="doccomment">/// Construct decoder based on headers.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>from_headers(stream: S, headers: <span class="kw-2">&amp;</span>HeaderMap) -&gt; Decoder&lt;S&gt; {
<span class="comment">// check content-encoding
</span><span class="kw">let </span>encoding = headers
.get(<span class="kw-2">&amp;</span>CONTENT_ENCODING)
.and_then(|val| val.to_str().ok())
.and_then(|x| x.parse().ok())
.unwrap_or(ContentEncoding::Identity);
<span class="self">Self</span>::new(stream, encoding)
}
}
<span class="kw">impl</span>&lt;S&gt; Stream <span class="kw">for </span>Decoder&lt;S&gt;
<span class="kw">where
</span>S: Stream&lt;Item = <span class="prelude-ty">Result</span>&lt;Bytes, PayloadError&gt;&gt;,
{
<span class="kw">type </span>Item = <span class="prelude-ty">Result</span>&lt;Bytes, PayloadError&gt;;
<span class="kw">fn </span>poll_next(<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt;&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>this = <span class="self">self</span>.project();
<span class="kw">loop </span>{
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref mut </span>fut) = this.fut {
<span class="kw">let </span>(chunk, decoder) = <span class="macro">ready!</span>(Pin::new(fut).poll(cx)).map_err(|<span class="kw">_</span>| {
PayloadError::Io(io::Error::new(
io::ErrorKind::Other,
<span class="string">"Blocking task was cancelled unexpectedly"</span>,
))
})<span class="question-mark">??</span>;
<span class="kw-2">*</span>this.decoder = <span class="prelude-val">Some</span>(decoder);
this.fut.take();
<span class="kw">if let </span><span class="prelude-val">Some</span>(chunk) = chunk {
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(chunk)));
}
}
<span class="kw">if </span><span class="kw-2">*</span>this.eof {
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">None</span>);
}
<span class="kw">match </span><span class="macro">ready!</span>(this.stream.as_mut().poll_next(cx)) {
<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err)) =&gt; <span class="kw">return </span>Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err))),
<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(chunk)) =&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">mut </span>decoder) = this.decoder.take() {
<span class="kw">if </span>chunk.len() &lt; MAX_CHUNK_SIZE_DECODE_IN_PLACE {
<span class="kw">let </span>chunk = decoder.feed_data(chunk)<span class="question-mark">?</span>;
<span class="kw-2">*</span>this.decoder = <span class="prelude-val">Some</span>(decoder);
<span class="kw">if let </span><span class="prelude-val">Some</span>(chunk) = chunk {
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(chunk)));
}
} <span class="kw">else </span>{
<span class="kw-2">*</span>this.fut = <span class="prelude-val">Some</span>(spawn_blocking(<span class="kw">move </span>|| {
<span class="kw">let </span>chunk = decoder.feed_data(chunk)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>((chunk, decoder))
}));
}
<span class="kw">continue</span>;
} <span class="kw">else </span>{
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(chunk)));
}
}
<span class="prelude-val">None </span>=&gt; {
<span class="kw-2">*</span>this.eof = <span class="bool-val">true</span>;
<span class="kw">return if let </span><span class="prelude-val">Some</span>(<span class="kw-2">mut </span>decoder) = this.decoder.take() {
<span class="kw">match </span>decoder.feed_eof() {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(res)) =&gt; Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(res))),
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>) =&gt; Poll::Ready(<span class="prelude-val">None</span>),
<span class="prelude-val">Err</span>(err) =&gt; Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err.into()))),
}
} <span class="kw">else </span>{
Poll::Ready(<span class="prelude-val">None</span>)
};
}
}
}
}
}
<span class="kw">enum </span>ContentDecoder {
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>Deflate(Box&lt;ZlibDecoder&lt;Writer&gt;&gt;),
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>Gzip(Box&lt;GzDecoder&lt;Writer&gt;&gt;),
<span class="attr">#[cfg(feature = <span class="string">"compress-brotli"</span>)]
</span>Brotli(Box&lt;brotli::DecompressorWriter&lt;Writer&gt;&gt;),
<span class="comment">// We need explicit 'static lifetime here because ZstdDecoder need lifetime
// argument, and we use `spawn_blocking` in `Decoder::poll_next` that require `FnOnce() -&gt; R + Send + 'static`
</span><span class="attr">#[cfg(feature = <span class="string">"compress-zstd"</span>)]
</span>Zstd(Box&lt;ZstdDecoder&lt;<span class="lifetime">'static</span>, Writer&gt;&gt;),
}
<span class="kw">impl </span>ContentDecoder {
<span class="kw">fn </span>feed_eof(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; io::Result&lt;<span class="prelude-ty">Option</span>&lt;Bytes&gt;&gt; {
<span class="kw">match </span><span class="self">self </span>{
<span class="attr">#[cfg(feature = <span class="string">"compress-brotli"</span>)]
</span>ContentDecoder::Brotli(<span class="kw-2">ref mut </span>decoder) =&gt; <span class="kw">match </span>decoder.flush() {
<span class="prelude-val">Ok</span>(()) =&gt; {
<span class="kw">let </span>b = decoder.get_mut().take();
<span class="kw">if </span>!b.is_empty() {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(b))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
}
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
},
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentDecoder::Gzip(<span class="kw-2">ref mut </span>decoder) =&gt; <span class="kw">match </span>decoder.try_finish() {
<span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; {
<span class="kw">let </span>b = decoder.get_mut().take();
<span class="kw">if </span>!b.is_empty() {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(b))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
}
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
},
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentDecoder::Deflate(<span class="kw-2">ref mut </span>decoder) =&gt; <span class="kw">match </span>decoder.try_finish() {
<span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; {
<span class="kw">let </span>b = decoder.get_mut().take();
<span class="kw">if </span>!b.is_empty() {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(b))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
}
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
},
<span class="attr">#[cfg(feature = <span class="string">"compress-zstd"</span>)]
</span>ContentDecoder::Zstd(<span class="kw-2">ref mut </span>decoder) =&gt; <span class="kw">match </span>decoder.flush() {
<span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; {
<span class="kw">let </span>b = decoder.get_mut().take();
<span class="kw">if </span>!b.is_empty() {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(b))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
}
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
},
}
}
<span class="kw">fn </span>feed_data(<span class="kw-2">&amp;mut </span><span class="self">self</span>, data: Bytes) -&gt; io::Result&lt;<span class="prelude-ty">Option</span>&lt;Bytes&gt;&gt; {
<span class="kw">match </span><span class="self">self </span>{
<span class="attr">#[cfg(feature = <span class="string">"compress-brotli"</span>)]
</span>ContentDecoder::Brotli(<span class="kw-2">ref mut </span>decoder) =&gt; <span class="kw">match </span>decoder.write_all(<span class="kw-2">&amp;</span>data) {
<span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; {
decoder.flush()<span class="question-mark">?</span>;
<span class="kw">let </span>b = decoder.get_mut().take();
<span class="kw">if </span>!b.is_empty() {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(b))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
}
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
},
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentDecoder::Gzip(<span class="kw-2">ref mut </span>decoder) =&gt; <span class="kw">match </span>decoder.write_all(<span class="kw-2">&amp;</span>data) {
<span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; {
decoder.flush()<span class="question-mark">?</span>;
<span class="kw">let </span>b = decoder.get_mut().take();
<span class="kw">if </span>!b.is_empty() {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(b))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
}
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
},
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentDecoder::Deflate(<span class="kw-2">ref mut </span>decoder) =&gt; <span class="kw">match </span>decoder.write_all(<span class="kw-2">&amp;</span>data) {
<span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; {
decoder.flush()<span class="question-mark">?</span>;
<span class="kw">let </span>b = decoder.get_mut().take();
<span class="kw">if </span>!b.is_empty() {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(b))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
}
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
},
<span class="attr">#[cfg(feature = <span class="string">"compress-zstd"</span>)]
</span>ContentDecoder::Zstd(<span class="kw-2">ref mut </span>decoder) =&gt; <span class="kw">match </span>decoder.write_all(<span class="kw-2">&amp;</span>data) {
<span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; {
decoder.flush()<span class="question-mark">?</span>;
<span class="kw">let </span>b = decoder.get_mut().take();
<span class="kw">if </span>!b.is_empty() {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(b))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
}
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
},
}
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,879 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/encoding/encoder.rs`."><title>encoder.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
<a href="#339" id="339">339</a>
<a href="#340" id="340">340</a>
<a href="#341" id="341">341</a>
<a href="#342" id="342">342</a>
<a href="#343" id="343">343</a>
<a href="#344" id="344">344</a>
<a href="#345" id="345">345</a>
<a href="#346" id="346">346</a>
<a href="#347" id="347">347</a>
<a href="#348" id="348">348</a>
<a href="#349" id="349">349</a>
<a href="#350" id="350">350</a>
<a href="#351" id="351">351</a>
<a href="#352" id="352">352</a>
<a href="#353" id="353">353</a>
<a href="#354" id="354">354</a>
<a href="#355" id="355">355</a>
<a href="#356" id="356">356</a>
<a href="#357" id="357">357</a>
<a href="#358" id="358">358</a>
<a href="#359" id="359">359</a>
<a href="#360" id="360">360</a>
<a href="#361" id="361">361</a>
<a href="#362" id="362">362</a>
<a href="#363" id="363">363</a>
<a href="#364" id="364">364</a>
<a href="#365" id="365">365</a>
<a href="#366" id="366">366</a>
<a href="#367" id="367">367</a>
<a href="#368" id="368">368</a>
<a href="#369" id="369">369</a>
<a href="#370" id="370">370</a>
<a href="#371" id="371">371</a>
<a href="#372" id="372">372</a>
<a href="#373" id="373">373</a>
<a href="#374" id="374">374</a>
<a href="#375" id="375">375</a>
<a href="#376" id="376">376</a>
<a href="#377" id="377">377</a>
<a href="#378" id="378">378</a>
<a href="#379" id="379">379</a>
<a href="#380" id="380">380</a>
<a href="#381" id="381">381</a>
<a href="#382" id="382">382</a>
<a href="#383" id="383">383</a>
<a href="#384" id="384">384</a>
<a href="#385" id="385">385</a>
<a href="#386" id="386">386</a>
<a href="#387" id="387">387</a>
<a href="#388" id="388">388</a>
<a href="#389" id="389">389</a>
<a href="#390" id="390">390</a>
<a href="#391" id="391">391</a>
<a href="#392" id="392">392</a>
<a href="#393" id="393">393</a>
<a href="#394" id="394">394</a>
<a href="#395" id="395">395</a>
<a href="#396" id="396">396</a>
<a href="#397" id="397">397</a>
<a href="#398" id="398">398</a>
<a href="#399" id="399">399</a>
<a href="#400" id="400">400</a>
<a href="#401" id="401">401</a>
<a href="#402" id="402">402</a>
<a href="#403" id="403">403</a>
<a href="#404" id="404">404</a>
<a href="#405" id="405">405</a>
<a href="#406" id="406">406</a>
<a href="#407" id="407">407</a>
<a href="#408" id="408">408</a>
<a href="#409" id="409">409</a>
<a href="#410" id="410">410</a>
<a href="#411" id="411">411</a>
<a href="#412" id="412">412</a>
<a href="#413" id="413">413</a>
<a href="#414" id="414">414</a>
<a href="#415" id="415">415</a>
<a href="#416" id="416">416</a>
<a href="#417" id="417">417</a>
<a href="#418" id="418">418</a>
<a href="#419" id="419">419</a>
<a href="#420" id="420">420</a>
<a href="#421" id="421">421</a>
<a href="#422" id="422">422</a>
<a href="#423" id="423">423</a>
<a href="#424" id="424">424</a>
<a href="#425" id="425">425</a>
<a href="#426" id="426">426</a>
<a href="#427" id="427">427</a>
<a href="#428" id="428">428</a>
<a href="#429" id="429">429</a>
<a href="#430" id="430">430</a>
<a href="#431" id="431">431</a>
<a href="#432" id="432">432</a>
<a href="#433" id="433">433</a>
<a href="#434" id="434">434</a>
<a href="#435" id="435">435</a>
<a href="#436" id="436">436</a>
<a href="#437" id="437">437</a>
<a href="#438" id="438">438</a>
<a href="#439" id="439">439</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Stream encoders.
</span><span class="kw">use </span>std::{
error::Error <span class="kw">as </span>StdError,
future::Future,
io::{<span class="self">self</span>, Write <span class="kw">as _</span>},
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>actix_rt::task::{spawn_blocking, JoinHandle};
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use </span>derive_more::Display;
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span><span class="kw">use </span>flate2::write::{GzEncoder, ZlibEncoder};
<span class="kw">use </span>futures_core::ready;
<span class="kw">use </span>pin_project_lite::pin_project;
<span class="kw">use </span>tracing::trace;
<span class="attr">#[cfg(feature = <span class="string">"compress-zstd"</span>)]
</span><span class="kw">use </span>zstd::stream::write::Encoder <span class="kw">as </span>ZstdEncoder;
<span class="kw">use </span><span class="kw">super</span>::Writer;
<span class="kw">use crate</span>::{
body::{<span class="self">self</span>, BodySize, MessageBody},
header::{<span class="self">self</span>, ContentEncoding, HeaderValue, CONTENT_ENCODING},
ResponseHead, StatusCode,
};
<span class="kw">const </span>MAX_CHUNK_SIZE_ENCODE_IN_PLACE: usize = <span class="number">1024</span>;
<span class="macro">pin_project!</span> {
<span class="kw">pub struct </span>Encoder&lt;B&gt; {
<span class="attr">#[pin]
</span>body: EncoderBody&lt;B&gt;,
encoder: <span class="prelude-ty">Option</span>&lt;ContentEncoder&gt;,
fut: <span class="prelude-ty">Option</span>&lt;JoinHandle&lt;<span class="prelude-ty">Result</span>&lt;ContentEncoder, io::Error&gt;&gt;&gt;,
eof: bool,
}
}
<span class="kw">impl</span>&lt;B: MessageBody&gt; Encoder&lt;B&gt; {
<span class="kw">fn </span>none() -&gt; <span class="self">Self </span>{
Encoder {
body: EncoderBody::None {
body: body::None::new(),
},
encoder: <span class="prelude-val">None</span>,
fut: <span class="prelude-val">None</span>,
eof: <span class="bool-val">true</span>,
}
}
<span class="kw">fn </span>empty() -&gt; <span class="self">Self </span>{
Encoder {
body: EncoderBody::Full { body: Bytes::new() },
encoder: <span class="prelude-val">None</span>,
fut: <span class="prelude-val">None</span>,
eof: <span class="bool-val">true</span>,
}
}
<span class="kw">pub fn </span>response(encoding: ContentEncoding, head: <span class="kw-2">&amp;mut </span>ResponseHead, body: B) -&gt; <span class="self">Self </span>{
<span class="comment">// no need to compress empty bodies
</span><span class="kw">match </span>body.size() {
BodySize::None =&gt; <span class="kw">return </span><span class="self">Self</span>::none(),
BodySize::Sized(<span class="number">0</span>) =&gt; <span class="kw">return </span><span class="self">Self</span>::empty(),
<span class="kw">_ </span>=&gt; {}
}
<span class="kw">let </span>should_encode = !(head.headers().contains_key(<span class="kw-2">&amp;</span>CONTENT_ENCODING)
|| head.status == StatusCode::SWITCHING_PROTOCOLS
|| head.status == StatusCode::NO_CONTENT
|| encoding == ContentEncoding::Identity);
<span class="kw">let </span>body = <span class="kw">match </span>body.try_into_bytes() {
<span class="prelude-val">Ok</span>(body) =&gt; EncoderBody::Full { body },
<span class="prelude-val">Err</span>(body) =&gt; EncoderBody::Stream { body },
};
<span class="kw">if </span>should_encode {
<span class="comment">// wrap body only if encoder is feature-enabled
</span><span class="kw">if let </span><span class="prelude-val">Some</span>(enc) = ContentEncoder::select(encoding) {
update_head(encoding, head);
<span class="kw">return </span>Encoder {
body,
encoder: <span class="prelude-val">Some</span>(enc),
fut: <span class="prelude-val">None</span>,
eof: <span class="bool-val">false</span>,
};
}
}
Encoder {
body,
encoder: <span class="prelude-val">None</span>,
fut: <span class="prelude-val">None</span>,
eof: <span class="bool-val">false</span>,
}
}
}
<span class="macro">pin_project!</span> {
<span class="attr">#[project = EncoderBodyProj]
</span><span class="kw">enum </span>EncoderBody&lt;B&gt; {
<span class="prelude-val">None </span>{ body: body::None },
Full { body: Bytes },
Stream { <span class="attr">#[pin] </span>body: B },
}
}
<span class="kw">impl</span>&lt;B&gt; MessageBody <span class="kw">for </span>EncoderBody&lt;B&gt;
<span class="kw">where
</span>B: MessageBody,
{
<span class="kw">type </span>Error = EncoderError;
<span class="attr">#[inline]
</span><span class="kw">fn </span>size(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; BodySize {
<span class="kw">match </span><span class="self">self </span>{
EncoderBody::None { body } =&gt; body.size(),
EncoderBody::Full { body } =&gt; body.size(),
EncoderBody::Stream { body } =&gt; body.size(),
}
}
<span class="kw">fn </span>poll_next(
<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;,
cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="self">Self</span>::Error&gt;&gt;&gt; {
<span class="kw">match </span><span class="self">self</span>.project() {
EncoderBodyProj::None { body } =&gt; {
Pin::new(body).poll_next(cx).map_err(|err| <span class="kw">match </span>err {})
}
EncoderBodyProj::Full { body } =&gt; {
Pin::new(body).poll_next(cx).map_err(|err| <span class="kw">match </span>err {})
}
EncoderBodyProj::Stream { body } =&gt; body
.poll_next(cx)
.map_err(|err| EncoderError::Body(err.into())),
}
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_into_bytes(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Bytes, <span class="self">Self</span>&gt;
<span class="kw">where
</span><span class="self">Self</span>: Sized,
{
<span class="kw">match </span><span class="self">self </span>{
EncoderBody::None { body } =&gt; <span class="prelude-val">Ok</span>(body.try_into_bytes().unwrap()),
EncoderBody::Full { body } =&gt; <span class="prelude-val">Ok</span>(body.try_into_bytes().unwrap()),
<span class="kw">_ </span>=&gt; <span class="prelude-val">Err</span>(<span class="self">self</span>),
}
}
}
<span class="kw">impl</span>&lt;B&gt; MessageBody <span class="kw">for </span>Encoder&lt;B&gt;
<span class="kw">where
</span>B: MessageBody,
{
<span class="kw">type </span>Error = EncoderError;
<span class="attr">#[inline]
</span><span class="kw">fn </span>size(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; BodySize {
<span class="kw">if </span><span class="self">self</span>.encoder.is_some() {
BodySize::Stream
} <span class="kw">else </span>{
<span class="self">self</span>.body.size()
}
}
<span class="kw">fn </span>poll_next(
<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;,
cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="prelude-ty">Result</span>&lt;Bytes, <span class="self">Self</span>::Error&gt;&gt;&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>this = <span class="self">self</span>.project();
<span class="kw">loop </span>{
<span class="kw">if </span><span class="kw-2">*</span>this.eof {
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">None</span>);
}
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref mut </span>fut) = this.fut {
<span class="kw">let </span><span class="kw-2">mut </span>encoder = <span class="macro">ready!</span>(Pin::new(fut).poll(cx))
.map_err(|<span class="kw">_</span>| {
EncoderError::Io(io::Error::new(
io::ErrorKind::Other,
<span class="string">"Blocking task was cancelled unexpectedly"</span>,
))
})<span class="question-mark">?
</span>.map_err(EncoderError::Io)<span class="question-mark">?</span>;
<span class="kw">let </span>chunk = encoder.take();
<span class="kw-2">*</span>this.encoder = <span class="prelude-val">Some</span>(encoder);
this.fut.take();
<span class="kw">if </span>!chunk.is_empty() {
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(chunk)));
}
}
<span class="kw">let </span>result = <span class="macro">ready!</span>(this.body.as_mut().poll_next(cx));
<span class="kw">match </span>result {
<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err)) =&gt; <span class="kw">return </span>Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err))),
<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(chunk)) =&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">mut </span>encoder) = this.encoder.take() {
<span class="kw">if </span>chunk.len() &lt; MAX_CHUNK_SIZE_ENCODE_IN_PLACE {
encoder.write(<span class="kw-2">&amp;</span>chunk).map_err(EncoderError::Io)<span class="question-mark">?</span>;
<span class="kw">let </span>chunk = encoder.take();
<span class="kw-2">*</span>this.encoder = <span class="prelude-val">Some</span>(encoder);
<span class="kw">if </span>!chunk.is_empty() {
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(chunk)));
}
} <span class="kw">else </span>{
<span class="kw-2">*</span>this.fut = <span class="prelude-val">Some</span>(spawn_blocking(<span class="kw">move </span>|| {
encoder.write(<span class="kw-2">&amp;</span>chunk)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(encoder)
}));
}
} <span class="kw">else </span>{
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(chunk)));
}
}
<span class="prelude-val">None </span>=&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(encoder) = this.encoder.take() {
<span class="kw">let </span>chunk = encoder.finish().map_err(EncoderError::Io)<span class="question-mark">?</span>;
<span class="kw">if </span>chunk.is_empty() {
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">None</span>);
} <span class="kw">else </span>{
<span class="kw-2">*</span>this.eof = <span class="bool-val">true</span>;
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(chunk)));
}
} <span class="kw">else </span>{
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">None</span>);
}
}
}
}
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_into_bytes(<span class="kw-2">mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Bytes, <span class="self">Self</span>&gt;
<span class="kw">where
</span><span class="self">Self</span>: Sized,
{
<span class="kw">if </span><span class="self">self</span>.encoder.is_some() {
<span class="prelude-val">Err</span>(<span class="self">self</span>)
} <span class="kw">else </span>{
<span class="kw">match </span><span class="self">self</span>.body.try_into_bytes() {
<span class="prelude-val">Ok</span>(body) =&gt; <span class="prelude-val">Ok</span>(body),
<span class="prelude-val">Err</span>(body) =&gt; {
<span class="self">self</span>.body = body;
<span class="prelude-val">Err</span>(<span class="self">self</span>)
}
}
}
}
}
<span class="kw">fn </span>update_head(encoding: ContentEncoding, head: <span class="kw-2">&amp;mut </span>ResponseHead) {
head.headers_mut()
.insert(header::CONTENT_ENCODING, encoding.to_header_value());
head.headers_mut()
.append(header::VARY, HeaderValue::from_static(<span class="string">"accept-encoding"</span>));
head.no_chunking(<span class="bool-val">false</span>);
}
<span class="kw">enum </span>ContentEncoder {
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>Deflate(ZlibEncoder&lt;Writer&gt;),
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>Gzip(GzEncoder&lt;Writer&gt;),
<span class="attr">#[cfg(feature = <span class="string">"compress-brotli"</span>)]
</span>Brotli(Box&lt;brotli::CompressorWriter&lt;Writer&gt;&gt;),
<span class="comment">// Wwe need explicit 'static lifetime here because ZstdEncoder needs a lifetime argument and we
// use `spawn_blocking` in `Encoder::poll_next` that requires `FnOnce() -&gt; R + Send + 'static`.
</span><span class="attr">#[cfg(feature = <span class="string">"compress-zstd"</span>)]
</span>Zstd(ZstdEncoder&lt;<span class="lifetime">'static</span>, Writer&gt;),
}
<span class="kw">impl </span>ContentEncoder {
<span class="kw">fn </span>select(encoding: ContentEncoding) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>&gt; {
<span class="kw">match </span>encoding {
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentEncoding::Deflate =&gt; <span class="prelude-val">Some</span>(ContentEncoder::Deflate(ZlibEncoder::new(
Writer::new(),
flate2::Compression::fast(),
))),
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentEncoding::Gzip =&gt; <span class="prelude-val">Some</span>(ContentEncoder::Gzip(GzEncoder::new(
Writer::new(),
flate2::Compression::fast(),
))),
<span class="attr">#[cfg(feature = <span class="string">"compress-brotli"</span>)]
</span>ContentEncoding::Brotli =&gt; <span class="prelude-val">Some</span>(ContentEncoder::Brotli(new_brotli_compressor())),
<span class="attr">#[cfg(feature = <span class="string">"compress-zstd"</span>)]
</span>ContentEncoding::Zstd =&gt; {
<span class="kw">let </span>encoder = ZstdEncoder::new(Writer::new(), <span class="number">3</span>).ok()<span class="question-mark">?</span>;
<span class="prelude-val">Some</span>(ContentEncoder::Zstd(encoder))
}
<span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
}
}
<span class="attr">#[inline]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>take(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; Bytes {
<span class="kw">match </span><span class="kw-2">*</span><span class="self">self </span>{
<span class="attr">#[cfg(feature = <span class="string">"compress-brotli"</span>)]
</span>ContentEncoder::Brotli(<span class="kw-2">ref mut </span>encoder) =&gt; encoder.get_mut().take(),
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentEncoder::Deflate(<span class="kw-2">ref mut </span>encoder) =&gt; encoder.get_mut().take(),
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentEncoder::Gzip(<span class="kw-2">ref mut </span>encoder) =&gt; encoder.get_mut().take(),
<span class="attr">#[cfg(feature = <span class="string">"compress-zstd"</span>)]
</span>ContentEncoder::Zstd(<span class="kw-2">ref mut </span>encoder) =&gt; encoder.get_mut().take(),
}
}
<span class="kw">fn </span>finish(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Bytes, io::Error&gt; {
<span class="kw">match </span><span class="self">self </span>{
<span class="attr">#[cfg(feature = <span class="string">"compress-brotli"</span>)]
</span>ContentEncoder::Brotli(<span class="kw-2">mut </span>encoder) =&gt; <span class="kw">match </span>encoder.flush() {
<span class="prelude-val">Ok</span>(()) =&gt; <span class="prelude-val">Ok</span>(encoder.into_inner().buf.freeze()),
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
},
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentEncoder::Gzip(encoder) =&gt; <span class="kw">match </span>encoder.finish() {
<span class="prelude-val">Ok</span>(writer) =&gt; <span class="prelude-val">Ok</span>(writer.buf.freeze()),
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
},
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentEncoder::Deflate(encoder) =&gt; <span class="kw">match </span>encoder.finish() {
<span class="prelude-val">Ok</span>(writer) =&gt; <span class="prelude-val">Ok</span>(writer.buf.freeze()),
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
},
<span class="attr">#[cfg(feature = <span class="string">"compress-zstd"</span>)]
</span>ContentEncoder::Zstd(encoder) =&gt; <span class="kw">match </span>encoder.finish() {
<span class="prelude-val">Ok</span>(writer) =&gt; <span class="prelude-val">Ok</span>(writer.buf.freeze()),
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
},
}
}
<span class="kw">fn </span>write(<span class="kw-2">&amp;mut </span><span class="self">self</span>, data: <span class="kw-2">&amp;</span>[u8]) -&gt; <span class="prelude-ty">Result</span>&lt;(), io::Error&gt; {
<span class="kw">match </span><span class="kw-2">*</span><span class="self">self </span>{
<span class="attr">#[cfg(feature = <span class="string">"compress-brotli"</span>)]
</span>ContentEncoder::Brotli(<span class="kw-2">ref mut </span>encoder) =&gt; <span class="kw">match </span>encoder.write_all(data) {
<span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Ok</span>(()),
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="macro">trace!</span>(<span class="string">"Error decoding br encoding: {}"</span>, err);
<span class="prelude-val">Err</span>(err)
}
},
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentEncoder::Gzip(<span class="kw-2">ref mut </span>encoder) =&gt; <span class="kw">match </span>encoder.write_all(data) {
<span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Ok</span>(()),
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="macro">trace!</span>(<span class="string">"Error decoding gzip encoding: {}"</span>, err);
<span class="prelude-val">Err</span>(err)
}
},
<span class="attr">#[cfg(feature = <span class="string">"compress-gzip"</span>)]
</span>ContentEncoder::Deflate(<span class="kw-2">ref mut </span>encoder) =&gt; <span class="kw">match </span>encoder.write_all(data) {
<span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Ok</span>(()),
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="macro">trace!</span>(<span class="string">"Error decoding deflate encoding: {}"</span>, err);
<span class="prelude-val">Err</span>(err)
}
},
<span class="attr">#[cfg(feature = <span class="string">"compress-zstd"</span>)]
</span>ContentEncoder::Zstd(<span class="kw-2">ref mut </span>encoder) =&gt; <span class="kw">match </span>encoder.write_all(data) {
<span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Ok</span>(()),
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="macro">trace!</span>(<span class="string">"Error decoding ztsd encoding: {}"</span>, err);
<span class="prelude-val">Err</span>(err)
}
},
}
}
}
<span class="attr">#[cfg(feature = <span class="string">"compress-brotli"</span>)]
</span><span class="kw">fn </span>new_brotli_compressor() -&gt; Box&lt;brotli::CompressorWriter&lt;Writer&gt;&gt; {
Box::new(brotli::CompressorWriter::new(
Writer::new(),
<span class="number">32 </span>* <span class="number">1024</span>, <span class="comment">// 32 KiB buffer
</span><span class="number">3</span>, <span class="comment">// BROTLI_PARAM_QUALITY
</span><span class="number">22</span>, <span class="comment">// BROTLI_PARAM_LGWIN
</span>))
}
<span class="attr">#[derive(Debug, Display)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>EncoderError {
<span class="doccomment">/// Wrapped body stream error.
</span><span class="attr">#[display(fmt = <span class="string">"body"</span>)]
</span>Body(Box&lt;<span class="kw">dyn </span>StdError&gt;),
<span class="doccomment">/// Generic I/O error.
</span><span class="attr">#[display(fmt = <span class="string">"io"</span>)]
</span>Io(io::Error),
}
<span class="kw">impl </span>StdError <span class="kw">for </span>EncoderError {
<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">'static</span>)&gt; {
<span class="kw">match </span><span class="self">self </span>{
EncoderError::Body(err) =&gt; <span class="prelude-val">Some</span>(<span class="kw-2">&amp;**</span>err),
EncoderError::Io(err) =&gt; <span class="prelude-val">Some</span>(err),
}
}
}
<span class="kw">impl </span>From&lt;EncoderError&gt; <span class="kw">for </span><span class="kw">crate</span>::Error {
<span class="kw">fn </span>from(err: EncoderError) -&gt; <span class="self">Self </span>{
<span class="kw">crate</span>::Error::new_encoder().with_cause(err)
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,81 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/encoding/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Content-Encoding support.
</span><span class="kw">use </span>std::io;
<span class="kw">use </span>bytes::{Bytes, BytesMut};
<span class="kw">mod </span>decoder;
<span class="kw">mod </span>encoder;
<span class="kw">pub use </span><span class="self">self</span>::{decoder::Decoder, encoder::Encoder};
<span class="doccomment">/// Special-purpose writer for streaming (de-)compression.
///
/// Pre-allocates 8KiB of capacity.
</span><span class="kw">struct </span>Writer {
buf: BytesMut,
}
<span class="kw">impl </span>Writer {
<span class="kw">fn </span>new() -&gt; Writer {
Writer {
buf: BytesMut::with_capacity(<span class="number">8192</span>),
}
}
<span class="kw">fn </span>take(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; Bytes {
<span class="self">self</span>.buf.split().freeze()
}
}
<span class="kw">impl </span>io::Write <span class="kw">for </span>Writer {
<span class="kw">fn </span>write(<span class="kw-2">&amp;mut </span><span class="self">self</span>, buf: <span class="kw-2">&amp;</span>[u8]) -&gt; io::Result&lt;usize&gt; {
<span class="self">self</span>.buf.extend_from_slice(buf);
<span class="prelude-val">Ok</span>(buf.len())
}
<span class="kw">fn </span>flush(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; io::Result&lt;()&gt; {
<span class="prelude-val">Ok</span>(())
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,977 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/error.rs`."><title>error.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
<a href="#339" id="339">339</a>
<a href="#340" id="340">340</a>
<a href="#341" id="341">341</a>
<a href="#342" id="342">342</a>
<a href="#343" id="343">343</a>
<a href="#344" id="344">344</a>
<a href="#345" id="345">345</a>
<a href="#346" id="346">346</a>
<a href="#347" id="347">347</a>
<a href="#348" id="348">348</a>
<a href="#349" id="349">349</a>
<a href="#350" id="350">350</a>
<a href="#351" id="351">351</a>
<a href="#352" id="352">352</a>
<a href="#353" id="353">353</a>
<a href="#354" id="354">354</a>
<a href="#355" id="355">355</a>
<a href="#356" id="356">356</a>
<a href="#357" id="357">357</a>
<a href="#358" id="358">358</a>
<a href="#359" id="359">359</a>
<a href="#360" id="360">360</a>
<a href="#361" id="361">361</a>
<a href="#362" id="362">362</a>
<a href="#363" id="363">363</a>
<a href="#364" id="364">364</a>
<a href="#365" id="365">365</a>
<a href="#366" id="366">366</a>
<a href="#367" id="367">367</a>
<a href="#368" id="368">368</a>
<a href="#369" id="369">369</a>
<a href="#370" id="370">370</a>
<a href="#371" id="371">371</a>
<a href="#372" id="372">372</a>
<a href="#373" id="373">373</a>
<a href="#374" id="374">374</a>
<a href="#375" id="375">375</a>
<a href="#376" id="376">376</a>
<a href="#377" id="377">377</a>
<a href="#378" id="378">378</a>
<a href="#379" id="379">379</a>
<a href="#380" id="380">380</a>
<a href="#381" id="381">381</a>
<a href="#382" id="382">382</a>
<a href="#383" id="383">383</a>
<a href="#384" id="384">384</a>
<a href="#385" id="385">385</a>
<a href="#386" id="386">386</a>
<a href="#387" id="387">387</a>
<a href="#388" id="388">388</a>
<a href="#389" id="389">389</a>
<a href="#390" id="390">390</a>
<a href="#391" id="391">391</a>
<a href="#392" id="392">392</a>
<a href="#393" id="393">393</a>
<a href="#394" id="394">394</a>
<a href="#395" id="395">395</a>
<a href="#396" id="396">396</a>
<a href="#397" id="397">397</a>
<a href="#398" id="398">398</a>
<a href="#399" id="399">399</a>
<a href="#400" id="400">400</a>
<a href="#401" id="401">401</a>
<a href="#402" id="402">402</a>
<a href="#403" id="403">403</a>
<a href="#404" id="404">404</a>
<a href="#405" id="405">405</a>
<a href="#406" id="406">406</a>
<a href="#407" id="407">407</a>
<a href="#408" id="408">408</a>
<a href="#409" id="409">409</a>
<a href="#410" id="410">410</a>
<a href="#411" id="411">411</a>
<a href="#412" id="412">412</a>
<a href="#413" id="413">413</a>
<a href="#414" id="414">414</a>
<a href="#415" id="415">415</a>
<a href="#416" id="416">416</a>
<a href="#417" id="417">417</a>
<a href="#418" id="418">418</a>
<a href="#419" id="419">419</a>
<a href="#420" id="420">420</a>
<a href="#421" id="421">421</a>
<a href="#422" id="422">422</a>
<a href="#423" id="423">423</a>
<a href="#424" id="424">424</a>
<a href="#425" id="425">425</a>
<a href="#426" id="426">426</a>
<a href="#427" id="427">427</a>
<a href="#428" id="428">428</a>
<a href="#429" id="429">429</a>
<a href="#430" id="430">430</a>
<a href="#431" id="431">431</a>
<a href="#432" id="432">432</a>
<a href="#433" id="433">433</a>
<a href="#434" id="434">434</a>
<a href="#435" id="435">435</a>
<a href="#436" id="436">436</a>
<a href="#437" id="437">437</a>
<a href="#438" id="438">438</a>
<a href="#439" id="439">439</a>
<a href="#440" id="440">440</a>
<a href="#441" id="441">441</a>
<a href="#442" id="442">442</a>
<a href="#443" id="443">443</a>
<a href="#444" id="444">444</a>
<a href="#445" id="445">445</a>
<a href="#446" id="446">446</a>
<a href="#447" id="447">447</a>
<a href="#448" id="448">448</a>
<a href="#449" id="449">449</a>
<a href="#450" id="450">450</a>
<a href="#451" id="451">451</a>
<a href="#452" id="452">452</a>
<a href="#453" id="453">453</a>
<a href="#454" id="454">454</a>
<a href="#455" id="455">455</a>
<a href="#456" id="456">456</a>
<a href="#457" id="457">457</a>
<a href="#458" id="458">458</a>
<a href="#459" id="459">459</a>
<a href="#460" id="460">460</a>
<a href="#461" id="461">461</a>
<a href="#462" id="462">462</a>
<a href="#463" id="463">463</a>
<a href="#464" id="464">464</a>
<a href="#465" id="465">465</a>
<a href="#466" id="466">466</a>
<a href="#467" id="467">467</a>
<a href="#468" id="468">468</a>
<a href="#469" id="469">469</a>
<a href="#470" id="470">470</a>
<a href="#471" id="471">471</a>
<a href="#472" id="472">472</a>
<a href="#473" id="473">473</a>
<a href="#474" id="474">474</a>
<a href="#475" id="475">475</a>
<a href="#476" id="476">476</a>
<a href="#477" id="477">477</a>
<a href="#478" id="478">478</a>
<a href="#479" id="479">479</a>
<a href="#480" id="480">480</a>
<a href="#481" id="481">481</a>
<a href="#482" id="482">482</a>
<a href="#483" id="483">483</a>
<a href="#484" id="484">484</a>
<a href="#485" id="485">485</a>
<a href="#486" id="486">486</a>
<a href="#487" id="487">487</a>
<a href="#488" id="488">488</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Error and Result module
</span><span class="kw">use </span>std::{error::Error <span class="kw">as </span>StdError, fmt, io, str::Utf8Error, string::FromUtf8Error};
<span class="kw">use </span>derive_more::{Display, Error, From};
<span class="kw">pub use </span>http::Error <span class="kw">as </span>HttpError;
<span class="kw">use </span>http::{uri::InvalidUri, StatusCode};
<span class="kw">use crate</span>::{body::BoxBody, Response};
<span class="kw">pub struct </span>Error {
inner: Box&lt;ErrorInner&gt;,
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>ErrorInner {
<span class="attr">#[allow(dead_code)]
</span>kind: Kind,
cause: <span class="prelude-ty">Option</span>&lt;Box&lt;<span class="kw">dyn </span>StdError&gt;&gt;,
}
<span class="kw">impl </span>Error {
<span class="kw">fn </span>new(kind: Kind) -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{
inner: Box::new(ErrorInner { kind, cause: <span class="prelude-val">None </span>}),
}
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>with_cause(<span class="kw-2">mut </span><span class="self">self</span>, cause: <span class="kw">impl </span>Into&lt;Box&lt;<span class="kw">dyn </span>StdError&gt;&gt;) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.inner.cause = <span class="prelude-val">Some</span>(cause.into());
<span class="self">self
</span>}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new_http() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(Kind::Http)
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new_parse() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(Kind::Parse)
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new_payload() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(Kind::Payload)
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new_body() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(Kind::Body)
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new_send_response() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(Kind::SendResponse)
}
<span class="attr">#[allow(unused)] </span><span class="comment">// available for future use
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new_io() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(Kind::Io)
}
<span class="attr">#[allow(unused)] </span><span class="comment">// used in encoder behind feature flag so ignore unused warning
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new_encoder() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(Kind::Encoder)
}
<span class="attr">#[allow(unused)] </span><span class="comment">// used with `ws` feature flag
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new_ws() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(Kind::Ws)
}
}
<span class="kw">impl </span>From&lt;Error&gt; <span class="kw">for </span>Response&lt;BoxBody&gt; {
<span class="kw">fn </span>from(err: Error) -&gt; <span class="self">Self </span>{
<span class="comment">// TODO: more appropriate error status codes, usage assessment needed
</span><span class="kw">let </span>status_code = <span class="kw">match </span>err.inner.kind {
Kind::Parse =&gt; StatusCode::BAD_REQUEST,
<span class="kw">_ </span>=&gt; StatusCode::INTERNAL_SERVER_ERROR,
};
Response::new(status_code).set_body(BoxBody::new(err.to_string()))
}
}
<span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">enum </span>Kind {
<span class="attr">#[display(fmt = <span class="string">"error processing HTTP"</span>)]
</span>Http,
<span class="attr">#[display(fmt = <span class="string">"error parsing HTTP message"</span>)]
</span>Parse,
<span class="attr">#[display(fmt = <span class="string">"request payload read error"</span>)]
</span>Payload,
<span class="attr">#[display(fmt = <span class="string">"response body write error"</span>)]
</span>Body,
<span class="attr">#[display(fmt = <span class="string">"send response error"</span>)]
</span>SendResponse,
<span class="attr">#[display(fmt = <span class="string">"error in WebSocket process"</span>)]
</span>Ws,
<span class="attr">#[display(fmt = <span class="string">"connection error"</span>)]
</span>Io,
<span class="attr">#[display(fmt = <span class="string">"encoder error"</span>)]
</span>Encoder,
}
<span class="kw">impl </span>fmt::Debug <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">'_</span>&gt;) -&gt; fmt::Result {
f.debug_struct(<span class="string">"actix_http::Error"</span>)
.field(<span class="string">"kind"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.inner.kind)
.field(<span class="string">"cause"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.inner.cause)
.finish()
}
}
<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">'_</span>&gt;) -&gt; fmt::Result {
<span class="kw">match </span><span class="self">self</span>.inner.cause.as_ref() {
<span class="prelude-val">Some</span>(err) =&gt; <span class="macro">write!</span>(f, <span class="string">"{}: {}"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.inner.kind, err),
<span class="prelude-val">None </span>=&gt; <span class="macro">write!</span>(f, <span class="string">"{}"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.inner.kind),
}
}
}
<span class="kw">impl </span>StdError <span class="kw">for </span>Error {
<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">'static</span>)&gt; {
<span class="self">self</span>.inner.cause.as_ref().map(Box::as_ref)
}
}
<span class="kw">impl </span>From&lt;std::convert::Infallible&gt; <span class="kw">for </span>Error {
<span class="kw">fn </span>from(err: std::convert::Infallible) -&gt; <span class="self">Self </span>{
<span class="kw">match </span>err {}
}
}
<span class="kw">impl </span>From&lt;HttpError&gt; <span class="kw">for </span>Error {
<span class="kw">fn </span>from(err: HttpError) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new_http().with_cause(err)
}
}
<span class="attr">#[cfg(feature = <span class="string">"ws"</span>)]
</span><span class="kw">impl </span>From&lt;<span class="kw">crate</span>::ws::HandshakeError&gt; <span class="kw">for </span>Error {
<span class="kw">fn </span>from(err: <span class="kw">crate</span>::ws::HandshakeError) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new_ws().with_cause(err)
}
}
<span class="attr">#[cfg(feature = <span class="string">"ws"</span>)]
</span><span class="kw">impl </span>From&lt;<span class="kw">crate</span>::ws::ProtocolError&gt; <span class="kw">for </span>Error {
<span class="kw">fn </span>from(err: <span class="kw">crate</span>::ws::ProtocolError) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new_ws().with_cause(err)
}
}
<span class="doccomment">/// A set of errors that can occur during parsing HTTP streams.
</span><span class="attr">#[derive(Debug, Display, Error)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>ParseError {
<span class="doccomment">/// An invalid `Method`, such as `GE.T`.
</span><span class="attr">#[display(fmt = <span class="string">"invalid method specified"</span>)]
</span>Method,
<span class="doccomment">/// An invalid `Uri`, such as `exam ple.domain`.
</span><span class="attr">#[display(fmt = <span class="string">"URI error: {}"</span>, _0)]
</span>Uri(InvalidUri),
<span class="doccomment">/// An invalid `HttpVersion`, such as `HTP/1.1`
</span><span class="attr">#[display(fmt = <span class="string">"invalid HTTP version specified"</span>)]
</span>Version,
<span class="doccomment">/// An invalid `Header`.
</span><span class="attr">#[display(fmt = <span class="string">"invalid Header provided"</span>)]
</span>Header,
<span class="doccomment">/// A message head is too large to be reasonable.
</span><span class="attr">#[display(fmt = <span class="string">"message head is too large"</span>)]
</span>TooLarge,
<span class="doccomment">/// A message reached EOF, but is not complete.
</span><span class="attr">#[display(fmt = <span class="string">"message is incomplete"</span>)]
</span>Incomplete,
<span class="doccomment">/// An invalid `Status`, such as `1337 ELITE`.
</span><span class="attr">#[display(fmt = <span class="string">"invalid status provided"</span>)]
</span>Status,
<span class="doccomment">/// A timeout occurred waiting for an IO event.
</span><span class="attr">#[allow(dead_code)]
#[display(fmt = <span class="string">"timeout"</span>)]
</span>Timeout,
<span class="doccomment">/// An I/O error that occurred while trying to read or write to a network stream.
</span><span class="attr">#[display(fmt = <span class="string">"I/O error: {}"</span>, _0)]
</span>Io(io::Error),
<span class="doccomment">/// Parsing a field as string failed.
</span><span class="attr">#[display(fmt = <span class="string">"UTF-8 error: {}"</span>, _0)]
</span>Utf8(Utf8Error),
}
<span class="kw">impl </span>From&lt;io::Error&gt; <span class="kw">for </span>ParseError {
<span class="kw">fn </span>from(err: io::Error) -&gt; ParseError {
ParseError::Io(err)
}
}
<span class="kw">impl </span>From&lt;InvalidUri&gt; <span class="kw">for </span>ParseError {
<span class="kw">fn </span>from(err: InvalidUri) -&gt; ParseError {
ParseError::Uri(err)
}
}
<span class="kw">impl </span>From&lt;Utf8Error&gt; <span class="kw">for </span>ParseError {
<span class="kw">fn </span>from(err: Utf8Error) -&gt; ParseError {
ParseError::Utf8(err)
}
}
<span class="kw">impl </span>From&lt;FromUtf8Error&gt; <span class="kw">for </span>ParseError {
<span class="kw">fn </span>from(err: FromUtf8Error) -&gt; ParseError {
ParseError::Utf8(err.utf8_error())
}
}
<span class="kw">impl </span>From&lt;httparse::Error&gt; <span class="kw">for </span>ParseError {
<span class="kw">fn </span>from(err: httparse::Error) -&gt; ParseError {
<span class="kw">match </span>err {
httparse::Error::HeaderName
| httparse::Error::HeaderValue
| httparse::Error::NewLine
| httparse::Error::Token =&gt; ParseError::Header,
httparse::Error::Status =&gt; ParseError::Status,
httparse::Error::TooManyHeaders =&gt; ParseError::TooLarge,
httparse::Error::Version =&gt; ParseError::Version,
}
}
}
<span class="kw">impl </span>From&lt;ParseError&gt; <span class="kw">for </span>Error {
<span class="kw">fn </span>from(err: ParseError) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new_parse().with_cause(err)
}
}
<span class="kw">impl </span>From&lt;ParseError&gt; <span class="kw">for </span>Response&lt;BoxBody&gt; {
<span class="kw">fn </span>from(err: ParseError) -&gt; <span class="self">Self </span>{
Error::from(err).into()
}
}
<span class="doccomment">/// A set of errors that can occur during payload parsing.
</span><span class="attr">#[derive(Debug, Display)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>PayloadError {
<span class="doccomment">/// A payload reached EOF, but is not complete.
</span><span class="attr">#[display(fmt = <span class="string">"payload reached EOF before completing: {:?}"</span>, _0)]
</span>Incomplete(<span class="prelude-ty">Option</span>&lt;io::Error&gt;),
<span class="doccomment">/// Content encoding stream corruption.
</span><span class="attr">#[display(fmt = <span class="string">"can not decode content-encoding"</span>)]
</span>EncodingCorrupted,
<span class="doccomment">/// Payload reached size limit.
</span><span class="attr">#[display(fmt = <span class="string">"payload reached size limit"</span>)]
</span>Overflow,
<span class="doccomment">/// Payload length is unknown.
</span><span class="attr">#[display(fmt = <span class="string">"payload length is unknown"</span>)]
</span>UnknownLength,
<span class="doccomment">/// HTTP/2 payload error.
</span><span class="attr">#[cfg(feature = <span class="string">"http2"</span>)]
#[display(fmt = <span class="string">"{}"</span>, _0)]
</span>Http2Payload(::h2::Error),
<span class="doccomment">/// Generic I/O error.
</span><span class="attr">#[display(fmt = <span class="string">"{}"</span>, _0)]
</span>Io(io::Error),
}
<span class="kw">impl </span>std::error::Error <span class="kw">for </span>PayloadError {
<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">'static</span>)&gt; {
<span class="kw">match </span><span class="self">self </span>{
PayloadError::Incomplete(<span class="prelude-val">None</span>) =&gt; <span class="prelude-val">None</span>,
PayloadError::Incomplete(<span class="prelude-val">Some</span>(err)) =&gt; <span class="prelude-val">Some</span>(err),
PayloadError::EncodingCorrupted =&gt; <span class="prelude-val">None</span>,
PayloadError::Overflow =&gt; <span class="prelude-val">None</span>,
PayloadError::UnknownLength =&gt; <span class="prelude-val">None</span>,
<span class="attr">#[cfg(feature = <span class="string">"http2"</span>)]
</span>PayloadError::Http2Payload(err) =&gt; <span class="prelude-val">Some</span>(err),
PayloadError::Io(err) =&gt; <span class="prelude-val">Some</span>(err),
}
}
}
<span class="attr">#[cfg(feature = <span class="string">"http2"</span>)]
</span><span class="kw">impl </span>From&lt;::h2::Error&gt; <span class="kw">for </span>PayloadError {
<span class="kw">fn </span>from(err: ::h2::Error) -&gt; <span class="self">Self </span>{
PayloadError::Http2Payload(err)
}
}
<span class="kw">impl </span>From&lt;<span class="prelude-ty">Option</span>&lt;io::Error&gt;&gt; <span class="kw">for </span>PayloadError {
<span class="kw">fn </span>from(err: <span class="prelude-ty">Option</span>&lt;io::Error&gt;) -&gt; <span class="self">Self </span>{
PayloadError::Incomplete(err)
}
}
<span class="kw">impl </span>From&lt;io::Error&gt; <span class="kw">for </span>PayloadError {
<span class="kw">fn </span>from(err: io::Error) -&gt; <span class="self">Self </span>{
PayloadError::Incomplete(<span class="prelude-val">Some</span>(err))
}
}
<span class="kw">impl </span>From&lt;PayloadError&gt; <span class="kw">for </span>Error {
<span class="kw">fn </span>from(err: PayloadError) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new_payload().with_cause(err)
}
}
<span class="doccomment">/// A set of errors that can occur during dispatching HTTP requests.
</span><span class="attr">#[derive(Debug, Display, From)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>DispatchError {
<span class="doccomment">/// Service error.
</span><span class="attr">#[display(fmt = <span class="string">"service error"</span>)]
</span>Service(Response&lt;BoxBody&gt;),
<span class="doccomment">/// Body streaming error.
</span><span class="attr">#[display(fmt = <span class="string">"body error: {}"</span>, _0)]
</span>Body(Box&lt;<span class="kw">dyn </span>StdError&gt;),
<span class="doccomment">/// Upgrade service error.
</span><span class="attr">#[display(fmt = <span class="string">"upgrade error"</span>)]
</span>Upgrade,
<span class="doccomment">/// An `io::Error` that occurred while trying to read or write to a network stream.
</span><span class="attr">#[display(fmt = <span class="string">"I/O error: {}"</span>, _0)]
</span>Io(io::Error),
<span class="doccomment">/// Request parse error.
</span><span class="attr">#[display(fmt = <span class="string">"request parse error: {}"</span>, _0)]
</span>Parse(ParseError),
<span class="doccomment">/// HTTP/2 error.
</span><span class="attr">#[display(fmt = <span class="string">"{}"</span>, _0)]
#[cfg(feature = <span class="string">"http2"</span>)]
</span>H2(h2::Error),
<span class="doccomment">/// The first request did not complete within the specified timeout.
</span><span class="attr">#[display(fmt = <span class="string">"request did not complete within the specified timeout"</span>)]
</span>SlowRequestTimeout,
<span class="doccomment">/// Disconnect timeout. Makes sense for TLS streams.
</span><span class="attr">#[display(fmt = <span class="string">"connection shutdown timeout"</span>)]
</span>DisconnectTimeout,
<span class="doccomment">/// Handler dropped payload before reading EOF.
</span><span class="attr">#[display(fmt = <span class="string">"handler dropped payload before reading EOF"</span>)]
</span>HandlerDroppedPayload,
<span class="doccomment">/// Internal error.
</span><span class="attr">#[display(fmt = <span class="string">"internal error"</span>)]
</span>InternalError,
}
<span class="kw">impl </span>StdError <span class="kw">for </span>DispatchError {
<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">'static</span>)&gt; {
<span class="kw">match </span><span class="self">self </span>{
DispatchError::Service(_res) =&gt; <span class="prelude-val">None</span>,
DispatchError::Body(err) =&gt; <span class="prelude-val">Some</span>(<span class="kw-2">&amp;**</span>err),
DispatchError::Io(err) =&gt; <span class="prelude-val">Some</span>(err),
DispatchError::Parse(err) =&gt; <span class="prelude-val">Some</span>(err),
<span class="attr">#[cfg(feature = <span class="string">"http2"</span>)]
</span>DispatchError::H2(err) =&gt; <span class="prelude-val">Some</span>(err),
<span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
}
}
}
<span class="doccomment">/// A set of error that can occur during parsing content type.
</span><span class="attr">#[derive(Debug, Display, Error)]
#[cfg_attr(test, derive(PartialEq, Eq))]
#[non_exhaustive]
</span><span class="kw">pub enum </span>ContentTypeError {
<span class="doccomment">/// Can not parse content type.
</span><span class="attr">#[display(fmt = <span class="string">"could not parse content type"</span>)]
</span>ParseError,
<span class="doccomment">/// Unknown content encoding.
</span><span class="attr">#[display(fmt = <span class="string">"unknown content encoding"</span>)]
</span>UnknownEncoding,
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>http::Error <span class="kw">as </span>HttpError;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>test_into_response() {
<span class="kw">let </span>resp: Response&lt;BoxBody&gt; = ParseError::Incomplete.into();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::BAD_REQUEST);
<span class="kw">let </span>err: HttpError = StatusCode::from_u16(<span class="number">10000</span>).err().unwrap().into();
<span class="kw">let </span>resp: Response&lt;BoxBody&gt; = Error::new_http().with_cause(err).into();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_as_response() {
<span class="kw">let </span>orig = io::Error::new(io::ErrorKind::Other, <span class="string">"other"</span>);
<span class="kw">let </span>err: Error = ParseError::Io(orig).into();
<span class="macro">assert_eq!</span>(
<span class="macro">format!</span>(<span class="string">"{}"</span>, err),
<span class="string">"error parsing HTTP message: I/O error: other"
</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_error_display() {
<span class="kw">let </span>orig = io::Error::new(io::ErrorKind::Other, <span class="string">"other"</span>);
<span class="kw">let </span>err = Error::new_io().with_cause(orig);
<span class="macro">assert_eq!</span>(<span class="string">"connection error: other"</span>, err.to_string());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_error_http_response() {
<span class="kw">let </span>orig = io::Error::new(io::ErrorKind::Other, <span class="string">"other"</span>);
<span class="kw">let </span>err = Error::new_io().with_cause(orig);
<span class="kw">let </span>resp: Response&lt;BoxBody&gt; = err.into();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_payload_error() {
<span class="kw">let </span>err: PayloadError = io::Error::new(io::ErrorKind::Other, <span class="string">"ParseError"</span>).into();
<span class="macro">assert!</span>(err.to_string().contains(<span class="string">"ParseError"</span>));
<span class="kw">let </span>err = PayloadError::Incomplete(<span class="prelude-val">None</span>);
<span class="macro">assert_eq!</span>(
err.to_string(),
<span class="string">"payload reached EOF before completing: None"
</span>);
}
<span class="macro">macro_rules!</span> from {
(<span class="macro-nonterminal">$from</span>:expr =&gt; <span class="macro-nonterminal">$error</span>:pat) =&gt; {
<span class="kw">match </span>ParseError::from(<span class="macro-nonterminal">$from</span>) {
err @ <span class="macro-nonterminal">$error </span>=&gt; {
<span class="macro">assert!</span>(err.to_string().len() &gt;= <span class="number">5</span>);
}
err =&gt; <span class="macro">unreachable!</span>(<span class="string">"{:?}"</span>, err),
}
};
}
<span class="macro">macro_rules!</span> from_and_cause {
(<span class="macro-nonterminal">$from</span>:expr =&gt; <span class="macro-nonterminal">$error</span>:pat) =&gt; {
<span class="kw">match </span>ParseError::from(<span class="macro-nonterminal">$from</span>) {
e @ <span class="macro-nonterminal">$error </span>=&gt; {
<span class="kw">let </span>desc = <span class="macro">format!</span>(<span class="string">"{}"</span>, e);
<span class="macro">assert_eq!</span>(desc, <span class="macro">format!</span>(<span class="string">"I/O error: {}"</span>, <span class="macro-nonterminal">$from</span>));
}
<span class="kw">_ </span>=&gt; <span class="macro">unreachable!</span>(<span class="string">"{:?}"</span>, <span class="macro-nonterminal">$from</span>),
}
};
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_from() {
<span class="macro">from_and_cause!</span>(io::Error::new(io::ErrorKind::Other, <span class="string">"other"</span>) =&gt; ParseError::Io(..));
<span class="macro">from!</span>(httparse::Error::HeaderName =&gt; ParseError::Header);
<span class="macro">from!</span>(httparse::Error::HeaderName =&gt; ParseError::Header);
<span class="macro">from!</span>(httparse::Error::HeaderValue =&gt; ParseError::Header);
<span class="macro">from!</span>(httparse::Error::NewLine =&gt; ParseError::Header);
<span class="macro">from!</span>(httparse::Error::Status =&gt; ParseError::Status);
<span class="macro">from!</span>(httparse::Error::Token =&gt; ParseError::Header);
<span class="macro">from!</span>(httparse::Error::TooManyHeaders =&gt; ParseError::TooLarge);
<span class="macro">from!</span>(httparse::Error::Version =&gt; ParseError::Version);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,603 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/extensions.rs`."><title>extensions.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
any::{Any, TypeId},
collections::HashMap,
fmt,
hash::{BuildHasherDefault, Hasher},
};
<span class="doccomment">/// A hasher for `TypeId`s that takes advantage of its known characteristics.
///
/// Author of `anymap` crate has done research on the topic:
/// https://github.com/chris-morgan/anymap/blob/2e9a5704/src/lib.rs#L599
</span><span class="attr">#[derive(Debug, Default)]
</span><span class="kw">struct </span>NoOpHasher(u64);
<span class="kw">impl </span>Hasher <span class="kw">for </span>NoOpHasher {
<span class="kw">fn </span>write(<span class="kw-2">&amp;mut </span><span class="self">self</span>, _bytes: <span class="kw-2">&amp;</span>[u8]) {
<span class="macro">unimplemented!</span>(<span class="string">"This NoOpHasher can only handle u64s"</span>)
}
<span class="kw">fn </span>write_u64(<span class="kw-2">&amp;mut </span><span class="self">self</span>, i: u64) {
<span class="self">self</span>.<span class="number">0 </span>= i;
}
<span class="kw">fn </span>finish(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; u64 {
<span class="self">self</span>.<span class="number">0
</span>}
}
<span class="doccomment">/// A type map for request extensions.
///
/// All entries into this map must be owned types (or static references).
</span><span class="attr">#[derive(Default)]
</span><span class="kw">pub struct </span>Extensions {
<span class="doccomment">/// Use AHasher with a std HashMap with for faster lookups on the small `TypeId` keys.
</span>map: HashMap&lt;TypeId, Box&lt;<span class="kw">dyn </span>Any&gt;, BuildHasherDefault&lt;NoOpHasher&gt;&gt;,
}
<span class="kw">impl </span>Extensions {
<span class="doccomment">/// Creates an empty `Extensions`.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>new() -&gt; Extensions {
Extensions {
map: HashMap::default(),
}
}
<span class="doccomment">/// Insert an item into the map.
///
/// If an item of this type was already stored, it will be replaced and returned.
///
/// ```
/// # use actix_http::Extensions;
/// let mut map = Extensions::new();
/// assert_eq!(map.insert(""), None);
/// assert_eq!(map.insert(1u32), None);
/// assert_eq!(map.insert(2u32), Some(1u32));
/// assert_eq!(*map.get::&lt;u32&gt;().unwrap(), 2u32);
/// ```
</span><span class="kw">pub fn </span>insert&lt;T: <span class="lifetime">'static</span>&gt;(<span class="kw-2">&amp;mut </span><span class="self">self</span>, val: T) -&gt; <span class="prelude-ty">Option</span>&lt;T&gt; {
<span class="self">self</span>.map
.insert(TypeId::of::&lt;T&gt;(), Box::new(val))
.and_then(downcast_owned)
}
<span class="doccomment">/// Check if map contains an item of a given type.
///
/// ```
/// # use actix_http::Extensions;
/// let mut map = Extensions::new();
/// assert!(!map.contains::&lt;u32&gt;());
///
/// assert_eq!(map.insert(1u32), None);
/// assert!(map.contains::&lt;u32&gt;());
/// ```
</span><span class="kw">pub fn </span>contains&lt;T: <span class="lifetime">'static</span>&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.map.contains_key(<span class="kw-2">&amp;</span>TypeId::of::&lt;T&gt;())
}
<span class="doccomment">/// Get a reference to an item of a given type.
///
/// ```
/// # use actix_http::Extensions;
/// let mut map = Extensions::new();
/// map.insert(1u32);
/// assert_eq!(map.get::&lt;u32&gt;(), Some(&amp;1u32));
/// ```
</span><span class="kw">pub fn </span>get&lt;T: <span class="lifetime">'static</span>&gt;(<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="self">self</span>.map
.get(<span class="kw-2">&amp;</span>TypeId::of::&lt;T&gt;())
.and_then(|boxed| boxed.downcast_ref())
}
<span class="doccomment">/// Get a mutable reference to an item of a given type.
///
/// ```
/// # use actix_http::Extensions;
/// let mut map = Extensions::new();
/// map.insert(1u32);
/// assert_eq!(map.get_mut::&lt;u32&gt;(), Some(&amp;mut 1u32));
/// ```
</span><span class="kw">pub fn </span>get_mut&lt;T: <span class="lifetime">'static</span>&gt;(<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="self">self</span>.map
.get_mut(<span class="kw-2">&amp;</span>TypeId::of::&lt;T&gt;())
.and_then(|boxed| boxed.downcast_mut())
}
<span class="doccomment">/// Remove an item from the map of a given type.
///
/// If an item of this type was already stored, it will be returned.
///
/// ```
/// # use actix_http::Extensions;
/// let mut map = Extensions::new();
///
/// map.insert(1u32);
/// assert_eq!(map.get::&lt;u32&gt;(), Some(&amp;1u32));
///
/// assert_eq!(map.remove::&lt;u32&gt;(), Some(1u32));
/// assert!(!map.contains::&lt;u32&gt;());
/// ```
</span><span class="kw">pub fn </span>remove&lt;T: <span class="lifetime">'static</span>&gt;(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;T&gt; {
<span class="self">self</span>.map.remove(<span class="kw-2">&amp;</span>TypeId::of::&lt;T&gt;()).and_then(downcast_owned)
}
<span class="doccomment">/// Clear the `Extensions` of all inserted extensions.
///
/// ```
/// # use actix_http::Extensions;
/// let mut map = Extensions::new();
///
/// map.insert(1u32);
/// assert!(map.contains::&lt;u32&gt;());
///
/// map.clear();
/// assert!(!map.contains::&lt;u32&gt;());
/// ```
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>clear(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="self">self</span>.map.clear();
}
<span class="doccomment">/// Extends self with the items from another `Extensions`.
</span><span class="kw">pub fn </span>extend(<span class="kw-2">&amp;mut </span><span class="self">self</span>, other: Extensions) {
<span class="self">self</span>.map.extend(other.map);
}
}
<span class="kw">impl </span>fmt::Debug <span class="kw">for </span>Extensions {
<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">'_</span>&gt;) -&gt; fmt::Result {
f.debug_struct(<span class="string">"Extensions"</span>).finish()
}
}
<span class="kw">fn </span>downcast_owned&lt;T: <span class="lifetime">'static</span>&gt;(boxed: Box&lt;<span class="kw">dyn </span>Any&gt;) -&gt; <span class="prelude-ty">Option</span>&lt;T&gt; {
boxed.downcast().ok().map(|boxed| <span class="kw-2">*</span>boxed)
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>test_remove() {
<span class="kw">let </span><span class="kw-2">mut </span>map = Extensions::new();
map.insert::&lt;i8&gt;(<span class="number">123</span>);
<span class="macro">assert!</span>(map.get::&lt;i8&gt;().is_some());
map.remove::&lt;i8&gt;();
<span class="macro">assert!</span>(map.get::&lt;i8&gt;().is_none());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_clear() {
<span class="kw">let </span><span class="kw-2">mut </span>map = Extensions::new();
map.insert::&lt;i8&gt;(<span class="number">8</span>);
map.insert::&lt;i16&gt;(<span class="number">16</span>);
map.insert::&lt;i32&gt;(<span class="number">32</span>);
<span class="macro">assert!</span>(map.contains::&lt;i8&gt;());
<span class="macro">assert!</span>(map.contains::&lt;i16&gt;());
<span class="macro">assert!</span>(map.contains::&lt;i32&gt;());
map.clear();
<span class="macro">assert!</span>(!map.contains::&lt;i8&gt;());
<span class="macro">assert!</span>(!map.contains::&lt;i16&gt;());
<span class="macro">assert!</span>(!map.contains::&lt;i32&gt;());
map.insert::&lt;i8&gt;(<span class="number">10</span>);
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>map.get::&lt;i8&gt;().unwrap(), <span class="number">10</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_integers() {
<span class="kw">static </span>A: u32 = <span class="number">8</span>;
<span class="kw">let </span><span class="kw-2">mut </span>map = Extensions::new();
map.insert::&lt;i8&gt;(<span class="number">8</span>);
map.insert::&lt;i16&gt;(<span class="number">16</span>);
map.insert::&lt;i32&gt;(<span class="number">32</span>);
map.insert::&lt;i64&gt;(<span class="number">64</span>);
map.insert::&lt;i128&gt;(<span class="number">128</span>);
map.insert::&lt;u8&gt;(<span class="number">8</span>);
map.insert::&lt;u16&gt;(<span class="number">16</span>);
map.insert::&lt;u32&gt;(<span class="number">32</span>);
map.insert::&lt;u64&gt;(<span class="number">64</span>);
map.insert::&lt;u128&gt;(<span class="number">128</span>);
map.insert::&lt;<span class="kw-2">&amp;</span><span class="lifetime">'static </span>u32&gt;(<span class="kw-2">&amp;</span>A);
<span class="macro">assert!</span>(map.get::&lt;i8&gt;().is_some());
<span class="macro">assert!</span>(map.get::&lt;i16&gt;().is_some());
<span class="macro">assert!</span>(map.get::&lt;i32&gt;().is_some());
<span class="macro">assert!</span>(map.get::&lt;i64&gt;().is_some());
<span class="macro">assert!</span>(map.get::&lt;i128&gt;().is_some());
<span class="macro">assert!</span>(map.get::&lt;u8&gt;().is_some());
<span class="macro">assert!</span>(map.get::&lt;u16&gt;().is_some());
<span class="macro">assert!</span>(map.get::&lt;u32&gt;().is_some());
<span class="macro">assert!</span>(map.get::&lt;u64&gt;().is_some());
<span class="macro">assert!</span>(map.get::&lt;u128&gt;().is_some());
<span class="macro">assert!</span>(map.get::&lt;<span class="kw-2">&amp;</span><span class="lifetime">'static </span>u32&gt;().is_some());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_composition() {
<span class="kw">struct </span>Magi&lt;T&gt;(<span class="kw">pub </span>T);
<span class="kw">struct </span>Madoka {
<span class="kw">pub </span>god: bool,
}
<span class="kw">struct </span>Homura {
<span class="kw">pub </span>attempts: usize,
}
<span class="kw">struct </span>Mami {
<span class="kw">pub </span>guns: usize,
}
<span class="kw">let </span><span class="kw-2">mut </span>map = Extensions::new();
map.insert(Magi(Madoka { god: <span class="bool-val">false </span>}));
map.insert(Magi(Homura { attempts: <span class="number">0 </span>}));
map.insert(Magi(Mami { guns: <span class="number">999 </span>}));
<span class="macro">assert!</span>(!map.get::&lt;Magi&lt;Madoka&gt;&gt;().unwrap().<span class="number">0</span>.god);
<span class="macro">assert_eq!</span>(<span class="number">0</span>, map.get::&lt;Magi&lt;Homura&gt;&gt;().unwrap().<span class="number">0</span>.attempts);
<span class="macro">assert_eq!</span>(<span class="number">999</span>, map.get::&lt;Magi&lt;Mami&gt;&gt;().unwrap().<span class="number">0</span>.guns);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_extensions() {
<span class="attr">#[derive(Debug, PartialEq)]
</span><span class="kw">struct </span>MyType(i32);
<span class="kw">let </span><span class="kw-2">mut </span>extensions = Extensions::new();
extensions.insert(<span class="number">5i32</span>);
extensions.insert(MyType(<span class="number">10</span>));
<span class="macro">assert_eq!</span>(extensions.get(), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="number">5i32</span>));
<span class="macro">assert_eq!</span>(extensions.get_mut(), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;mut </span><span class="number">5i32</span>));
<span class="macro">assert_eq!</span>(extensions.remove::&lt;i32&gt;(), <span class="prelude-val">Some</span>(<span class="number">5i32</span>));
<span class="macro">assert!</span>(extensions.get::&lt;i32&gt;().is_none());
<span class="macro">assert_eq!</span>(extensions.get::&lt;bool&gt;(), <span class="prelude-val">None</span>);
<span class="macro">assert_eq!</span>(extensions.get(), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>MyType(<span class="number">10</span>)));
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_extend() {
<span class="attr">#[derive(Debug, PartialEq)]
</span><span class="kw">struct </span>MyType(i32);
<span class="kw">let </span><span class="kw-2">mut </span>extensions = Extensions::new();
extensions.insert(<span class="number">5i32</span>);
extensions.insert(MyType(<span class="number">10</span>));
<span class="kw">let </span><span class="kw-2">mut </span>other = Extensions::new();
other.insert(<span class="number">15i32</span>);
other.insert(<span class="number">20u8</span>);
extensions.extend(other);
<span class="macro">assert_eq!</span>(extensions.get(), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="number">15i32</span>));
<span class="macro">assert_eq!</span>(extensions.get_mut(), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;mut </span><span class="number">15i32</span>));
<span class="macro">assert_eq!</span>(extensions.remove::&lt;i32&gt;(), <span class="prelude-val">Some</span>(<span class="number">15i32</span>));
<span class="macro">assert!</span>(extensions.get::&lt;i32&gt;().is_none());
<span class="macro">assert_eq!</span>(extensions.get::&lt;bool&gt;(), <span class="prelude-val">None</span>);
<span class="macro">assert_eq!</span>(extensions.get(), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>MyType(<span class="number">10</span>)));
<span class="macro">assert_eq!</span>(extensions.get(), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="number">20u8</span>));
<span class="macro">assert_eq!</span>(extensions.get_mut(), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;mut </span><span class="number">20u8</span>));
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,855 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/h1/chunked.rs`."><title>chunked.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
<a href="#339" id="339">339</a>
<a href="#340" id="340">340</a>
<a href="#341" id="341">341</a>
<a href="#342" id="342">342</a>
<a href="#343" id="343">343</a>
<a href="#344" id="344">344</a>
<a href="#345" id="345">345</a>
<a href="#346" id="346">346</a>
<a href="#347" id="347">347</a>
<a href="#348" id="348">348</a>
<a href="#349" id="349">349</a>
<a href="#350" id="350">350</a>
<a href="#351" id="351">351</a>
<a href="#352" id="352">352</a>
<a href="#353" id="353">353</a>
<a href="#354" id="354">354</a>
<a href="#355" id="355">355</a>
<a href="#356" id="356">356</a>
<a href="#357" id="357">357</a>
<a href="#358" id="358">358</a>
<a href="#359" id="359">359</a>
<a href="#360" id="360">360</a>
<a href="#361" id="361">361</a>
<a href="#362" id="362">362</a>
<a href="#363" id="363">363</a>
<a href="#364" id="364">364</a>
<a href="#365" id="365">365</a>
<a href="#366" id="366">366</a>
<a href="#367" id="367">367</a>
<a href="#368" id="368">368</a>
<a href="#369" id="369">369</a>
<a href="#370" id="370">370</a>
<a href="#371" id="371">371</a>
<a href="#372" id="372">372</a>
<a href="#373" id="373">373</a>
<a href="#374" id="374">374</a>
<a href="#375" id="375">375</a>
<a href="#376" id="376">376</a>
<a href="#377" id="377">377</a>
<a href="#378" id="378">378</a>
<a href="#379" id="379">379</a>
<a href="#380" id="380">380</a>
<a href="#381" id="381">381</a>
<a href="#382" id="382">382</a>
<a href="#383" id="383">383</a>
<a href="#384" id="384">384</a>
<a href="#385" id="385">385</a>
<a href="#386" id="386">386</a>
<a href="#387" id="387">387</a>
<a href="#388" id="388">388</a>
<a href="#389" id="389">389</a>
<a href="#390" id="390">390</a>
<a href="#391" id="391">391</a>
<a href="#392" id="392">392</a>
<a href="#393" id="393">393</a>
<a href="#394" id="394">394</a>
<a href="#395" id="395">395</a>
<a href="#396" id="396">396</a>
<a href="#397" id="397">397</a>
<a href="#398" id="398">398</a>
<a href="#399" id="399">399</a>
<a href="#400" id="400">400</a>
<a href="#401" id="401">401</a>
<a href="#402" id="402">402</a>
<a href="#403" id="403">403</a>
<a href="#404" id="404">404</a>
<a href="#405" id="405">405</a>
<a href="#406" id="406">406</a>
<a href="#407" id="407">407</a>
<a href="#408" id="408">408</a>
<a href="#409" id="409">409</a>
<a href="#410" id="410">410</a>
<a href="#411" id="411">411</a>
<a href="#412" id="412">412</a>
<a href="#413" id="413">413</a>
<a href="#414" id="414">414</a>
<a href="#415" id="415">415</a>
<a href="#416" id="416">416</a>
<a href="#417" id="417">417</a>
<a href="#418" id="418">418</a>
<a href="#419" id="419">419</a>
<a href="#420" id="420">420</a>
<a href="#421" id="421">421</a>
<a href="#422" id="422">422</a>
<a href="#423" id="423">423</a>
<a href="#424" id="424">424</a>
<a href="#425" id="425">425</a>
<a href="#426" id="426">426</a>
<a href="#427" id="427">427</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{io, task::Poll};
<span class="kw">use </span>bytes::{Buf <span class="kw">as _</span>, Bytes, BytesMut};
<span class="kw">use </span>tracing::{debug, trace};
<span class="macro">macro_rules!</span> byte (
(<span class="macro-nonterminal">$rdr</span>:ident) =&gt; ({
<span class="kw">if </span><span class="macro-nonterminal">$rdr</span>.len() &gt; <span class="number">0 </span>{
<span class="kw">let </span>b = <span class="macro-nonterminal">$rdr</span>[<span class="number">0</span>];
<span class="macro-nonterminal">$rdr</span>.advance(<span class="number">1</span>);
b
} <span class="kw">else </span>{
<span class="kw">return </span>Poll::Pending
}
})
);
<span class="attr">#[derive(Debug, Clone, PartialEq, Eq)]
</span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">enum </span>ChunkedState {
Size,
SizeLws,
Extension,
SizeLf,
Body,
BodyCr,
BodyLf,
EndCr,
EndLf,
End,
}
<span class="kw">impl </span>ChunkedState {
<span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>step(
<span class="kw-2">&amp;</span><span class="self">self</span>,
body: <span class="kw-2">&amp;mut </span>BytesMut,
size: <span class="kw-2">&amp;mut </span>u64,
buf: <span class="kw-2">&amp;mut </span><span class="prelude-ty">Option</span>&lt;Bytes&gt;,
) -&gt; Poll&lt;<span class="prelude-ty">Result</span>&lt;ChunkedState, io::Error&gt;&gt; {
<span class="kw">use </span><span class="self">self</span>::ChunkedState::<span class="kw-2">*</span>;
<span class="kw">match </span><span class="kw-2">*</span><span class="self">self </span>{
Size =&gt; ChunkedState::read_size(body, size),
SizeLws =&gt; ChunkedState::read_size_lws(body),
Extension =&gt; ChunkedState::read_extension(body),
SizeLf =&gt; ChunkedState::read_size_lf(body, <span class="kw-2">*</span>size),
Body =&gt; ChunkedState::read_body(body, size, buf),
BodyCr =&gt; ChunkedState::read_body_cr(body),
BodyLf =&gt; ChunkedState::read_body_lf(body),
EndCr =&gt; ChunkedState::read_end_cr(body),
EndLf =&gt; ChunkedState::read_end_lf(body),
End =&gt; Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::End)),
}
}
<span class="kw">fn </span>read_size(rdr: <span class="kw-2">&amp;mut </span>BytesMut, size: <span class="kw-2">&amp;mut </span>u64) -&gt; Poll&lt;<span class="prelude-ty">Result</span>&lt;ChunkedState, io::Error&gt;&gt; {
<span class="kw">let </span>radix = <span class="number">16</span>;
<span class="kw">let </span>rem = <span class="kw">match </span><span class="macro">byte!</span>(rdr) {
b @ <span class="string">b'0'</span>..=<span class="string">b'9' </span>=&gt; b - <span class="string">b'0'</span>,
b @ <span class="string">b'a'</span>..=<span class="string">b'f' </span>=&gt; b + <span class="number">10 </span>- <span class="string">b'a'</span>,
b @ <span class="string">b'A'</span>..=<span class="string">b'F' </span>=&gt; b + <span class="number">10 </span>- <span class="string">b'A'</span>,
<span class="string">b'\t' </span>| <span class="string">b' ' </span>=&gt; <span class="kw">return </span>Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::SizeLws)),
<span class="string">b';' </span>=&gt; <span class="kw">return </span>Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::Extension)),
<span class="string">b'\r' </span>=&gt; <span class="kw">return </span>Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::SizeLf)),
<span class="kw">_ </span>=&gt; {
<span class="kw">return </span>Poll::Ready(<span class="prelude-val">Err</span>(io::Error::new(
io::ErrorKind::InvalidInput,
<span class="string">"Invalid chunk size line: Invalid Size"</span>,
)));
}
};
<span class="kw">match </span>size.checked_mul(radix) {
<span class="prelude-val">Some</span>(n) =&gt; {
<span class="kw-2">*</span>size = n;
<span class="kw-2">*</span>size += rem <span class="kw">as </span>u64;
Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::Size))
}
<span class="prelude-val">None </span>=&gt; {
<span class="macro">debug!</span>(<span class="string">"chunk size would overflow u64"</span>);
Poll::Ready(<span class="prelude-val">Err</span>(io::Error::new(
io::ErrorKind::InvalidInput,
<span class="string">"Invalid chunk size line: Size is too big"</span>,
)))
}
}
}
<span class="kw">fn </span>read_size_lws(rdr: <span class="kw-2">&amp;mut </span>BytesMut) -&gt; Poll&lt;<span class="prelude-ty">Result</span>&lt;ChunkedState, io::Error&gt;&gt; {
<span class="kw">match </span><span class="macro">byte!</span>(rdr) {
<span class="comment">// LWS can follow the chunk size, but no more digits can come
</span><span class="string">b'\t' </span>| <span class="string">b' ' </span>=&gt; Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::SizeLws)),
<span class="string">b';' </span>=&gt; Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::Extension)),
<span class="string">b'\r' </span>=&gt; Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::SizeLf)),
<span class="kw">_ </span>=&gt; Poll::Ready(<span class="prelude-val">Err</span>(io::Error::new(
io::ErrorKind::InvalidInput,
<span class="string">"Invalid chunk size linear white space"</span>,
))),
}
}
<span class="kw">fn </span>read_extension(rdr: <span class="kw-2">&amp;mut </span>BytesMut) -&gt; Poll&lt;<span class="prelude-ty">Result</span>&lt;ChunkedState, io::Error&gt;&gt; {
<span class="kw">match </span><span class="macro">byte!</span>(rdr) {
<span class="string">b'\r' </span>=&gt; Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::SizeLf)),
<span class="comment">// strictly 0x20 (space) should be disallowed but we don't parse quoted strings here
</span><span class="number">0x00</span>..=<span class="number">0x08 </span>| <span class="number">0x0a</span>..=<span class="number">0x1f </span>| <span class="number">0x7f </span>=&gt; Poll::Ready(<span class="prelude-val">Err</span>(io::Error::new(
io::ErrorKind::InvalidInput,
<span class="string">"Invalid character in chunk extension"</span>,
))),
<span class="kw">_ </span>=&gt; Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::Extension)), <span class="comment">// no supported extensions
</span>}
}
<span class="kw">fn </span>read_size_lf(rdr: <span class="kw-2">&amp;mut </span>BytesMut, size: u64) -&gt; Poll&lt;<span class="prelude-ty">Result</span>&lt;ChunkedState, io::Error&gt;&gt; {
<span class="kw">match </span><span class="macro">byte!</span>(rdr) {
<span class="string">b'\n' </span><span class="kw">if </span>size &gt; <span class="number">0 </span>=&gt; Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::Body)),
<span class="string">b'\n' </span><span class="kw">if </span>size == <span class="number">0 </span>=&gt; Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::EndCr)),
<span class="kw">_ </span>=&gt; Poll::Ready(<span class="prelude-val">Err</span>(io::Error::new(
io::ErrorKind::InvalidInput,
<span class="string">"Invalid chunk size LF"</span>,
))),
}
}
<span class="kw">fn </span>read_body(
rdr: <span class="kw-2">&amp;mut </span>BytesMut,
rem: <span class="kw-2">&amp;mut </span>u64,
buf: <span class="kw-2">&amp;mut </span><span class="prelude-ty">Option</span>&lt;Bytes&gt;,
) -&gt; Poll&lt;<span class="prelude-ty">Result</span>&lt;ChunkedState, io::Error&gt;&gt; {
<span class="macro">trace!</span>(<span class="string">"Chunked read, remaining={:?}"</span>, rem);
<span class="kw">let </span>len = rdr.len() <span class="kw">as </span>u64;
<span class="kw">if </span>len == <span class="number">0 </span>{
Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::Body))
} <span class="kw">else </span>{
<span class="kw">let </span>slice;
<span class="kw">if </span><span class="kw-2">*</span>rem &gt; len {
slice = rdr.split().freeze();
<span class="kw-2">*</span>rem -= len;
} <span class="kw">else </span>{
slice = rdr.split_to(<span class="kw-2">*</span>rem <span class="kw">as </span>usize).freeze();
<span class="kw-2">*</span>rem = <span class="number">0</span>;
}
<span class="kw-2">*</span>buf = <span class="prelude-val">Some</span>(slice);
<span class="kw">if </span><span class="kw-2">*</span>rem &gt; <span class="number">0 </span>{
Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::Body))
} <span class="kw">else </span>{
Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::BodyCr))
}
}
}
<span class="kw">fn </span>read_body_cr(rdr: <span class="kw-2">&amp;mut </span>BytesMut) -&gt; Poll&lt;<span class="prelude-ty">Result</span>&lt;ChunkedState, io::Error&gt;&gt; {
<span class="kw">match </span><span class="macro">byte!</span>(rdr) {
<span class="string">b'\r' </span>=&gt; Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::BodyLf)),
<span class="kw">_ </span>=&gt; Poll::Ready(<span class="prelude-val">Err</span>(io::Error::new(
io::ErrorKind::InvalidInput,
<span class="string">"Invalid chunk body CR"</span>,
))),
}
}
<span class="kw">fn </span>read_body_lf(rdr: <span class="kw-2">&amp;mut </span>BytesMut) -&gt; Poll&lt;<span class="prelude-ty">Result</span>&lt;ChunkedState, io::Error&gt;&gt; {
<span class="kw">match </span><span class="macro">byte!</span>(rdr) {
<span class="string">b'\n' </span>=&gt; Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::Size)),
<span class="kw">_ </span>=&gt; Poll::Ready(<span class="prelude-val">Err</span>(io::Error::new(
io::ErrorKind::InvalidInput,
<span class="string">"Invalid chunk body LF"</span>,
))),
}
}
<span class="kw">fn </span>read_end_cr(rdr: <span class="kw-2">&amp;mut </span>BytesMut) -&gt; Poll&lt;<span class="prelude-ty">Result</span>&lt;ChunkedState, io::Error&gt;&gt; {
<span class="kw">match </span><span class="macro">byte!</span>(rdr) {
<span class="string">b'\r' </span>=&gt; Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::EndLf)),
<span class="kw">_ </span>=&gt; Poll::Ready(<span class="prelude-val">Err</span>(io::Error::new(
io::ErrorKind::InvalidInput,
<span class="string">"Invalid chunk end CR"</span>,
))),
}
}
<span class="kw">fn </span>read_end_lf(rdr: <span class="kw-2">&amp;mut </span>BytesMut) -&gt; Poll&lt;<span class="prelude-ty">Result</span>&lt;ChunkedState, io::Error&gt;&gt; {
<span class="kw">match </span><span class="macro">byte!</span>(rdr) {
<span class="string">b'\n' </span>=&gt; Poll::Ready(<span class="prelude-val">Ok</span>(ChunkedState::End)),
<span class="kw">_ </span>=&gt; Poll::Ready(<span class="prelude-val">Err</span>(io::Error::new(
io::ErrorKind::InvalidInput,
<span class="string">"Invalid chunk end LF"</span>,
))),
}
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>actix_codec::Decoder <span class="kw">as _</span>;
<span class="kw">use </span>bytes::{Bytes, BytesMut};
<span class="kw">use </span>http::Method;
<span class="kw">use crate</span>::{
error::ParseError,
h1::decoder::{MessageDecoder, PayloadItem},
HttpMessage <span class="kw">as _</span>, Request,
};
<span class="macro">macro_rules!</span> parse_ready {
(<span class="macro-nonterminal">$e</span>:expr) =&gt; {{
<span class="kw">match </span>MessageDecoder::&lt;Request&gt;::default().decode(<span class="macro-nonterminal">$e</span>) {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>((msg, <span class="kw">_</span>))) =&gt; msg,
<span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; <span class="macro">unreachable!</span>(<span class="string">"Eof during parsing http request"</span>),
<span class="prelude-val">Err</span>(err) =&gt; <span class="macro">unreachable!</span>(<span class="string">"Error during parsing http request: {:?}"</span>, err),
}
}};
}
<span class="macro">macro_rules!</span> expect_parse_err {
(<span class="macro-nonterminal">$e</span>:expr) =&gt; {{
<span class="kw">match </span>MessageDecoder::&lt;Request&gt;::default().decode(<span class="macro-nonterminal">$e</span>) {
<span class="prelude-val">Err</span>(err) =&gt; <span class="kw">match </span>err {
ParseError::Io(<span class="kw">_</span>) =&gt; <span class="macro">unreachable!</span>(<span class="string">"Parse error expected"</span>),
<span class="kw">_ </span>=&gt; {}
},
<span class="kw">_ </span>=&gt; <span class="macro">unreachable!</span>(<span class="string">"Error expected"</span>),
}
}};
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_chunked_payload_chunk_extension() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(
<span class="string">"GET /test HTTP/1.1\r\n\
transfer-encoding: chunked\r\n\
\r\n"</span>,
);
<span class="kw">let </span><span class="kw-2">mut </span>reader = MessageDecoder::&lt;Request&gt;::default();
<span class="kw">let </span>(msg, pl) = reader.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="kw">let </span><span class="kw-2">mut </span>pl = pl.unwrap();
<span class="macro">assert!</span>(msg.chunked().unwrap());
buf.extend(<span class="string">b"4;test\r\ndata\r\n4\r\nline\r\n0\r\n\r\n"</span>); <span class="comment">// test: test\r\n\r\n")
</span><span class="kw">let </span>chunk = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap().chunk();
<span class="macro">assert_eq!</span>(chunk, Bytes::from_static(<span class="string">b"data"</span>));
<span class="kw">let </span>chunk = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap().chunk();
<span class="macro">assert_eq!</span>(chunk, Bytes::from_static(<span class="string">b"line"</span>));
<span class="kw">let </span>msg = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert!</span>(msg.eof());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_request_chunked() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(
<span class="string">"GET /test HTTP/1.1\r\n\
transfer-encoding: chunked\r\n\r\n"</span>,
);
<span class="kw">let </span>req = <span class="macro">parse_ready!</span>(<span class="kw-2">&amp;mut </span>buf);
<span class="kw">if let </span><span class="prelude-val">Ok</span>(val) = req.chunked() {
<span class="macro">assert!</span>(val);
} <span class="kw">else </span>{
<span class="macro">unreachable!</span>(<span class="string">"Error"</span>);
}
<span class="comment">// intentional typo in "chunked"
</span><span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(
<span class="string">"GET /test HTTP/1.1\r\n\
transfer-encoding: chnked\r\n\r\n"</span>,
);
<span class="macro">expect_parse_err!</span>(<span class="kw-2">&amp;mut </span>buf);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_http_request_chunked_payload() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(
<span class="string">"GET /test HTTP/1.1\r\n\
transfer-encoding: chunked\r\n\r\n"</span>,
);
<span class="kw">let </span><span class="kw-2">mut </span>reader = MessageDecoder::&lt;Request&gt;::default();
<span class="kw">let </span>(req, pl) = reader.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="kw">let </span><span class="kw-2">mut </span>pl = pl.unwrap();
<span class="macro">assert!</span>(req.chunked().unwrap());
buf.extend(<span class="string">b"4\r\ndata\r\n4\r\nline\r\n0\r\n\r\n"</span>);
<span class="macro">assert_eq!</span>(
pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap().chunk().as_ref(),
<span class="string">b"data"
</span>);
<span class="macro">assert_eq!</span>(
pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap().chunk().as_ref(),
<span class="string">b"line"
</span>);
<span class="macro">assert!</span>(pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap().eof());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_http_request_chunked_payload_and_next_message() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(
<span class="string">"GET /test HTTP/1.1\r\n\
transfer-encoding: chunked\r\n\r\n"</span>,
);
<span class="kw">let </span><span class="kw-2">mut </span>reader = MessageDecoder::&lt;Request&gt;::default();
<span class="kw">let </span>(req, pl) = reader.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="kw">let </span><span class="kw-2">mut </span>pl = pl.unwrap();
<span class="macro">assert!</span>(req.chunked().unwrap());
buf.extend(
<span class="string">b"4\r\ndata\r\n4\r\nline\r\n0\r\n\r\n\
POST /test2 HTTP/1.1\r\n\
transfer-encoding: chunked\r\n\r\n"
</span>.iter(),
);
<span class="kw">let </span>msg = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert_eq!</span>(msg.chunk().as_ref(), <span class="string">b"data"</span>);
<span class="kw">let </span>msg = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert_eq!</span>(msg.chunk().as_ref(), <span class="string">b"line"</span>);
<span class="kw">let </span>msg = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert!</span>(msg.eof());
<span class="kw">let </span>(req, <span class="kw">_</span>) = reader.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert!</span>(req.chunked().unwrap());
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>req.method(), Method::POST);
<span class="macro">assert!</span>(req.chunked().unwrap());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_http_request_chunked_payload_chunks() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(
<span class="string">"GET /test HTTP/1.1\r\n\
transfer-encoding: chunked\r\n\r\n"</span>,
);
<span class="kw">let </span><span class="kw-2">mut </span>reader = MessageDecoder::&lt;Request&gt;::default();
<span class="kw">let </span>(req, pl) = reader.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="kw">let </span><span class="kw-2">mut </span>pl = pl.unwrap();
<span class="macro">assert!</span>(req.chunked().unwrap());
buf.extend(<span class="string">b"4\r\n1111\r\n"</span>);
<span class="kw">let </span>msg = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert_eq!</span>(msg.chunk().as_ref(), <span class="string">b"1111"</span>);
buf.extend(<span class="string">b"4\r\ndata\r"</span>);
<span class="kw">let </span>msg = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert_eq!</span>(msg.chunk().as_ref(), <span class="string">b"data"</span>);
buf.extend(<span class="string">b"\n4"</span>);
<span class="macro">assert!</span>(pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().is_none());
buf.extend(<span class="string">b"\r"</span>);
<span class="macro">assert!</span>(pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().is_none());
buf.extend(<span class="string">b"\n"</span>);
<span class="macro">assert!</span>(pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().is_none());
buf.extend(<span class="string">b"li"</span>);
<span class="kw">let </span>msg = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert_eq!</span>(msg.chunk().as_ref(), <span class="string">b"li"</span>);
<span class="comment">//trailers
//buf.feed_data("test: test\r\n");
//not_ready!(reader.parse(&amp;mut buf, &amp;mut readbuf));
</span>buf.extend(<span class="string">b"ne\r\n0\r\n"</span>);
<span class="kw">let </span>msg = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert_eq!</span>(msg.chunk().as_ref(), <span class="string">b"ne"</span>);
<span class="macro">assert!</span>(pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().is_none());
buf.extend(<span class="string">b"\r\n"</span>);
<span class="macro">assert!</span>(pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap().eof());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>chunk_extension_quoted() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(
<span class="string">"GET /test HTTP/1.1\r\n\
Host: localhost:8080\r\n\
Transfer-Encoding: chunked\r\n\
\r\n\
2;hello=b;one=\"1 2 3\"\r\n\
xx"</span>,
);
<span class="kw">let </span><span class="kw-2">mut </span>reader = MessageDecoder::&lt;Request&gt;::default();
<span class="kw">let </span>(_msg, pl) = reader.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="kw">let </span><span class="kw-2">mut </span>pl = pl.unwrap();
<span class="kw">let </span>chunk = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert_eq!</span>(chunk, PayloadItem::Chunk(Bytes::from_static(<span class="string">b"xx"</span>)));
}
<span class="attr">#[test]
</span><span class="kw">fn </span>hrs_chunk_extension_invalid() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(
<span class="string">"GET / HTTP/1.1\r\n\
Host: localhost:8080\r\n\
Transfer-Encoding: chunked\r\n\
\r\n\
2;x\nx\r\n\
4c\r\n\
0\r\n"</span>,
);
<span class="kw">let </span><span class="kw-2">mut </span>reader = MessageDecoder::&lt;Request&gt;::default();
<span class="kw">let </span>(_msg, pl) = reader.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="kw">let </span><span class="kw-2">mut </span>pl = pl.unwrap();
<span class="kw">let </span>err = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap_err();
<span class="macro">assert!</span>(err
.to_string()
.contains(<span class="string">"Invalid character in chunk extension"</span>));
}
<span class="attr">#[test]
</span><span class="kw">fn </span>hrs_chunk_size_overflow() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(
<span class="string">"GET / HTTP/1.1\r\n\
Host: example.com\r\n\
Transfer-Encoding: chunked\r\n\
\r\n\
f0000000000000003\r\n\
abc\r\n\
0\r\n"</span>,
);
<span class="kw">let </span><span class="kw-2">mut </span>reader = MessageDecoder::&lt;Request&gt;::default();
<span class="kw">let </span>(_msg, pl) = reader.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="kw">let </span><span class="kw-2">mut </span>pl = pl.unwrap();
<span class="kw">let </span>err = pl.decode(<span class="kw-2">&amp;mut </span>buf).unwrap_err();
<span class="macro">assert!</span>(err
.to_string()
.contains(<span class="string">"Invalid chunk size line: Size is too big"</span>));
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,481 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/h1/client.rs`."><title>client.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{fmt, io};
<span class="kw">use </span>bitflags::bitflags;
<span class="kw">use </span>bytes::{Bytes, BytesMut};
<span class="kw">use </span>http::{Method, Version};
<span class="kw">use </span>tokio_util::codec::{Decoder, Encoder};
<span class="kw">use super</span>::{
decoder::{<span class="self">self</span>, PayloadDecoder, PayloadItem, PayloadType},
encoder, reserve_readbuf, Message, MessageType,
};
<span class="kw">use crate</span>::{
body::BodySize,
error::{ParseError, PayloadError},
ConnectionType, RequestHeadType, ResponseHead, ServiceConfig,
};
<span class="macro">bitflags!</span> {
<span class="attr">#[derive(Debug, Clone, Copy)]
</span><span class="kw">struct </span>Flags: u8 {
<span class="kw">const </span>HEAD = <span class="number">0b0000_0001</span>;
<span class="kw">const </span>KEEP_ALIVE_ENABLED = <span class="number">0b0000_1000</span>;
<span class="kw">const </span>STREAM = <span class="number">0b0001_0000</span>;
}
}
<span class="doccomment">/// HTTP/1 Codec
</span><span class="kw">pub struct </span>ClientCodec {
inner: ClientCodecInner,
}
<span class="doccomment">/// HTTP/1 Payload Codec
</span><span class="kw">pub struct </span>ClientPayloadCodec {
inner: ClientCodecInner,
}
<span class="kw">struct </span>ClientCodecInner {
config: ServiceConfig,
decoder: decoder::MessageDecoder&lt;ResponseHead&gt;,
payload: <span class="prelude-ty">Option</span>&lt;PayloadDecoder&gt;,
version: Version,
conn_type: ConnectionType,
<span class="comment">// encoder part
</span>flags: Flags,
encoder: encoder::MessageEncoder&lt;RequestHeadType&gt;,
}
<span class="kw">impl </span>Default <span class="kw">for </span>ClientCodec {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
ClientCodec::new(ServiceConfig::default())
}
}
<span class="kw">impl </span>fmt::Debug <span class="kw">for </span>ClientCodec {
<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">'_</span>&gt;) -&gt; fmt::Result {
f.debug_struct(<span class="string">"h1::ClientCodec"</span>)
.field(<span class="string">"flags"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.inner.flags)
.finish_non_exhaustive()
}
}
<span class="kw">impl </span>ClientCodec {
<span class="doccomment">/// Create HTTP/1 codec.
///
/// `keepalive_enabled` how response `connection` header get generated.
</span><span class="kw">pub fn </span>new(config: ServiceConfig) -&gt; <span class="self">Self </span>{
<span class="kw">let </span>flags = <span class="kw">if </span>config.keep_alive().enabled() {
Flags::KEEP_ALIVE_ENABLED
} <span class="kw">else </span>{
Flags::empty()
};
ClientCodec {
inner: ClientCodecInner {
config,
decoder: decoder::MessageDecoder::default(),
payload: <span class="prelude-val">None</span>,
version: Version::HTTP_11,
conn_type: ConnectionType::Close,
flags,
encoder: encoder::MessageEncoder::default(),
},
}
}
<span class="doccomment">/// Check if request is upgrade
</span><span class="kw">pub fn </span>upgrade(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.inner.conn_type == ConnectionType::Upgrade
}
<span class="doccomment">/// Check if last response is keep-alive
</span><span class="kw">pub fn </span>keep_alive(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.inner.conn_type == ConnectionType::KeepAlive
}
<span class="doccomment">/// Check last request's message type
</span><span class="kw">pub fn </span>message_type(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; MessageType {
<span class="kw">if </span><span class="self">self</span>.inner.flags.contains(Flags::STREAM) {
MessageType::Stream
} <span class="kw">else if </span><span class="self">self</span>.inner.payload.is_none() {
MessageType::None
} <span class="kw">else </span>{
MessageType::Payload
}
}
<span class="doccomment">/// Convert message codec to a payload codec
</span><span class="kw">pub fn </span>into_payload_codec(<span class="self">self</span>) -&gt; ClientPayloadCodec {
ClientPayloadCodec { inner: <span class="self">self</span>.inner }
}
}
<span class="kw">impl </span>ClientPayloadCodec {
<span class="doccomment">/// Check if last response is keep-alive
</span><span class="kw">pub fn </span>keep_alive(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.inner.conn_type == ConnectionType::KeepAlive
}
<span class="doccomment">/// Transform payload codec to a message codec
</span><span class="kw">pub fn </span>into_message_codec(<span class="self">self</span>) -&gt; ClientCodec {
ClientCodec { inner: <span class="self">self</span>.inner }
}
}
<span class="kw">impl </span>Decoder <span class="kw">for </span>ClientCodec {
<span class="kw">type </span>Item = ResponseHead;
<span class="kw">type </span>Error = ParseError;
<span class="kw">fn </span>decode(<span class="kw-2">&amp;mut </span><span class="self">self</span>, src: <span class="kw-2">&amp;mut </span>BytesMut) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt;, <span class="self">Self</span>::Error&gt; {
<span class="macro">debug_assert!</span>(
<span class="self">self</span>.inner.payload.is_none(),
<span class="string">"Payload decoder should not be set"
</span>);
<span class="kw">if let </span><span class="prelude-val">Some</span>((req, payload)) = <span class="self">self</span>.inner.decoder.decode(src)<span class="question-mark">? </span>{
<span class="kw">if let </span><span class="prelude-val">Some</span>(conn_type) = req.conn_type() {
<span class="comment">// do not use peer's keep-alive
</span><span class="self">self</span>.inner.conn_type = <span class="kw">if </span>conn_type == ConnectionType::KeepAlive {
<span class="self">self</span>.inner.conn_type
} <span class="kw">else </span>{
conn_type
};
}
<span class="kw">if </span>!<span class="self">self</span>.inner.flags.contains(Flags::HEAD) {
<span class="kw">match </span>payload {
PayloadType::None =&gt; <span class="self">self</span>.inner.payload = <span class="prelude-val">None</span>,
PayloadType::Payload(pl) =&gt; <span class="self">self</span>.inner.payload = <span class="prelude-val">Some</span>(pl),
PayloadType::Stream(pl) =&gt; {
<span class="self">self</span>.inner.payload = <span class="prelude-val">Some</span>(pl);
<span class="self">self</span>.inner.flags.insert(Flags::STREAM);
}
}
} <span class="kw">else </span>{
<span class="self">self</span>.inner.payload = <span class="prelude-val">None</span>;
}
reserve_readbuf(src);
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(req))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
}
}
<span class="kw">impl </span>Decoder <span class="kw">for </span>ClientPayloadCodec {
<span class="kw">type </span>Item = <span class="prelude-ty">Option</span>&lt;Bytes&gt;;
<span class="kw">type </span>Error = PayloadError;
<span class="kw">fn </span>decode(<span class="kw-2">&amp;mut </span><span class="self">self</span>, src: <span class="kw-2">&amp;mut </span>BytesMut) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt;, <span class="self">Self</span>::Error&gt; {
<span class="macro">debug_assert!</span>(
<span class="self">self</span>.inner.payload.is_some(),
<span class="string">"Payload decoder is not specified"
</span>);
<span class="prelude-val">Ok</span>(<span class="kw">match </span><span class="self">self</span>.inner.payload.as_mut().unwrap().decode(src)<span class="question-mark">? </span>{
<span class="prelude-val">Some</span>(PayloadItem::Chunk(chunk)) =&gt; {
reserve_readbuf(src);
<span class="prelude-val">Some</span>(<span class="prelude-val">Some</span>(chunk))
}
<span class="prelude-val">Some</span>(PayloadItem::Eof) =&gt; {
<span class="self">self</span>.inner.payload.take();
<span class="prelude-val">Some</span>(<span class="prelude-val">None</span>)
}
<span class="prelude-val">None </span>=&gt; <span class="prelude-val">None</span>,
})
}
}
<span class="kw">impl </span>Encoder&lt;Message&lt;(RequestHeadType, BodySize)&gt;&gt; <span class="kw">for </span>ClientCodec {
<span class="kw">type </span>Error = io::Error;
<span class="kw">fn </span>encode(
<span class="kw-2">&amp;mut </span><span class="self">self</span>,
item: Message&lt;(RequestHeadType, BodySize)&gt;,
dst: <span class="kw-2">&amp;mut </span>BytesMut,
) -&gt; <span class="prelude-ty">Result</span>&lt;(), <span class="self">Self</span>::Error&gt; {
<span class="kw">match </span>item {
Message::Item((<span class="kw-2">mut </span>head, length)) =&gt; {
<span class="kw">let </span>inner = <span class="kw-2">&amp;mut </span><span class="self">self</span>.inner;
inner.version = head.as_ref().version;
inner
.flags
.set(Flags::HEAD, head.as_ref().method == Method::HEAD);
<span class="comment">// connection status
</span>inner.conn_type = <span class="kw">match </span>head.as_ref().connection_type() {
ConnectionType::KeepAlive =&gt; {
<span class="kw">if </span>inner.flags.contains(Flags::KEEP_ALIVE_ENABLED) {
ConnectionType::KeepAlive
} <span class="kw">else </span>{
ConnectionType::Close
}
}
ConnectionType::Upgrade =&gt; ConnectionType::Upgrade,
ConnectionType::Close =&gt; ConnectionType::Close,
};
inner.encoder.encode(
dst,
<span class="kw-2">&amp;mut </span>head,
<span class="bool-val">false</span>,
<span class="bool-val">false</span>,
inner.version,
length,
inner.conn_type,
<span class="kw-2">&amp;</span>inner.config,
)<span class="question-mark">?</span>;
}
Message::Chunk(<span class="prelude-val">Some</span>(bytes)) =&gt; {
<span class="self">self</span>.inner.encoder.encode_chunk(bytes.as_ref(), dst)<span class="question-mark">?</span>;
}
Message::Chunk(<span class="prelude-val">None</span>) =&gt; {
<span class="self">self</span>.inner.encoder.encode_eof(dst)<span class="question-mark">?</span>;
}
}
<span class="prelude-val">Ok</span>(())
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,481 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/h1/codec.rs`."><title>codec.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{fmt, io};
<span class="kw">use </span>bitflags::bitflags;
<span class="kw">use </span>bytes::BytesMut;
<span class="kw">use </span>http::{Method, Version};
<span class="kw">use </span>tokio_util::codec::{Decoder, Encoder};
<span class="kw">use super</span>::{
decoder::{<span class="self">self</span>, PayloadDecoder, PayloadItem, PayloadType},
encoder, Message, MessageType,
};
<span class="kw">use crate</span>::{body::BodySize, error::ParseError, ConnectionType, Request, Response, ServiceConfig};
<span class="macro">bitflags!</span> {
<span class="attr">#[derive(Debug, Clone, Copy)]
</span><span class="kw">struct </span>Flags: u8 {
<span class="kw">const </span>HEAD = <span class="number">0b0000_0001</span>;
<span class="kw">const </span>KEEP_ALIVE_ENABLED = <span class="number">0b0000_0010</span>;
<span class="kw">const </span>STREAM = <span class="number">0b0000_0100</span>;
}
}
<span class="doccomment">/// HTTP/1 Codec
</span><span class="kw">pub struct </span>Codec {
config: ServiceConfig,
decoder: decoder::MessageDecoder&lt;Request&gt;,
payload: <span class="prelude-ty">Option</span>&lt;PayloadDecoder&gt;,
version: Version,
conn_type: ConnectionType,
<span class="comment">// encoder part
</span>flags: Flags,
encoder: encoder::MessageEncoder&lt;Response&lt;()&gt;&gt;,
}
<span class="kw">impl </span>Default <span class="kw">for </span>Codec {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
Codec::new(ServiceConfig::default())
}
}
<span class="kw">impl </span>fmt::Debug <span class="kw">for </span>Codec {
<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">'_</span>&gt;) -&gt; fmt::Result {
f.debug_struct(<span class="string">"h1::Codec"</span>)
.field(<span class="string">"flags"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.flags)
.finish_non_exhaustive()
}
}
<span class="kw">impl </span>Codec {
<span class="doccomment">/// Create HTTP/1 codec.
///
/// `keepalive_enabled` how response `connection` header get generated.
</span><span class="kw">pub fn </span>new(config: ServiceConfig) -&gt; <span class="self">Self </span>{
<span class="kw">let </span>flags = <span class="kw">if </span>config.keep_alive().enabled() {
Flags::KEEP_ALIVE_ENABLED
} <span class="kw">else </span>{
Flags::empty()
};
Codec {
config,
flags,
decoder: decoder::MessageDecoder::default(),
payload: <span class="prelude-val">None</span>,
version: Version::HTTP_11,
conn_type: ConnectionType::Close,
encoder: encoder::MessageEncoder::default(),
}
}
<span class="doccomment">/// Check if request is upgrade.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>upgrade(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.conn_type == ConnectionType::Upgrade
}
<span class="doccomment">/// Check if last response is keep-alive.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>keep_alive(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.conn_type == ConnectionType::KeepAlive
}
<span class="doccomment">/// Check if keep-alive enabled on server level.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>keep_alive_enabled(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.flags.contains(Flags::KEEP_ALIVE_ENABLED)
}
<span class="doccomment">/// Check last request's message type.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>message_type(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; MessageType {
<span class="kw">if </span><span class="self">self</span>.flags.contains(Flags::STREAM) {
MessageType::Stream
} <span class="kw">else if </span><span class="self">self</span>.payload.is_none() {
MessageType::None
} <span class="kw">else </span>{
MessageType::Payload
}
}
<span class="attr">#[inline]
</span><span class="kw">pub fn </span>config(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ServiceConfig {
<span class="kw-2">&amp;</span><span class="self">self</span>.config
}
}
<span class="kw">impl </span>Decoder <span class="kw">for </span>Codec {
<span class="kw">type </span>Item = Message&lt;Request&gt;;
<span class="kw">type </span>Error = ParseError;
<span class="kw">fn </span>decode(<span class="kw-2">&amp;mut </span><span class="self">self</span>, src: <span class="kw-2">&amp;mut </span>BytesMut) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt;, <span class="self">Self</span>::Error&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref mut </span>payload) = <span class="self">self</span>.payload {
<span class="prelude-val">Ok</span>(<span class="kw">match </span>payload.decode(src)<span class="question-mark">? </span>{
<span class="prelude-val">Some</span>(PayloadItem::Chunk(chunk)) =&gt; <span class="prelude-val">Some</span>(Message::Chunk(<span class="prelude-val">Some</span>(chunk))),
<span class="prelude-val">Some</span>(PayloadItem::Eof) =&gt; {
<span class="self">self</span>.payload.take();
<span class="prelude-val">Some</span>(Message::Chunk(<span class="prelude-val">None</span>))
}
<span class="prelude-val">None </span>=&gt; <span class="prelude-val">None</span>,
})
} <span class="kw">else if let </span><span class="prelude-val">Some</span>((req, payload)) = <span class="self">self</span>.decoder.decode(src)<span class="question-mark">? </span>{
<span class="kw">let </span>head = req.head();
<span class="self">self</span>.flags.set(Flags::HEAD, head.method == Method::HEAD);
<span class="self">self</span>.version = head.version;
<span class="self">self</span>.conn_type = head.connection_type();
<span class="kw">if </span><span class="self">self</span>.conn_type == ConnectionType::KeepAlive
&amp;&amp; !<span class="self">self</span>.flags.contains(Flags::KEEP_ALIVE_ENABLED)
{
<span class="self">self</span>.conn_type = ConnectionType::Close
}
<span class="kw">match </span>payload {
PayloadType::None =&gt; <span class="self">self</span>.payload = <span class="prelude-val">None</span>,
PayloadType::Payload(pl) =&gt; <span class="self">self</span>.payload = <span class="prelude-val">Some</span>(pl),
PayloadType::Stream(pl) =&gt; {
<span class="self">self</span>.payload = <span class="prelude-val">Some</span>(pl);
<span class="self">self</span>.flags.insert(Flags::STREAM);
}
}
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Message::Item(req)))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
}
}
<span class="kw">impl </span>Encoder&lt;Message&lt;(Response&lt;()&gt;, BodySize)&gt;&gt; <span class="kw">for </span>Codec {
<span class="kw">type </span>Error = io::Error;
<span class="kw">fn </span>encode(
<span class="kw-2">&amp;mut </span><span class="self">self</span>,
item: Message&lt;(Response&lt;()&gt;, BodySize)&gt;,
dst: <span class="kw-2">&amp;mut </span>BytesMut,
) -&gt; <span class="prelude-ty">Result</span>&lt;(), <span class="self">Self</span>::Error&gt; {
<span class="kw">match </span>item {
Message::Item((<span class="kw-2">mut </span>res, length)) =&gt; {
<span class="comment">// set response version
</span>res.head_mut().version = <span class="self">self</span>.version;
<span class="comment">// connection status
</span><span class="self">self</span>.conn_type = <span class="kw">if let </span><span class="prelude-val">Some</span>(ct) = res.head().conn_type() {
<span class="kw">if </span>ct == ConnectionType::KeepAlive {
<span class="self">self</span>.conn_type
} <span class="kw">else </span>{
ct
}
} <span class="kw">else </span>{
<span class="self">self</span>.conn_type
};
<span class="comment">// encode message
</span><span class="self">self</span>.encoder.encode(
dst,
<span class="kw-2">&amp;mut </span>res,
<span class="self">self</span>.flags.contains(Flags::HEAD),
<span class="self">self</span>.flags.contains(Flags::STREAM),
<span class="self">self</span>.version,
length,
<span class="self">self</span>.conn_type,
<span class="kw-2">&amp;</span><span class="self">self</span>.config,
)<span class="question-mark">?</span>;
}
Message::Chunk(<span class="prelude-val">Some</span>(bytes)) =&gt; {
<span class="self">self</span>.encoder.encode_chunk(bytes.as_ref(), dst)<span class="question-mark">?</span>;
}
Message::Chunk(<span class="prelude-val">None</span>) =&gt; {
<span class="self">self</span>.encoder.encode_eof(dst)<span class="question-mark">?</span>;
}
}
<span class="prelude-val">Ok</span>(())
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use </span><span class="kw">crate</span>::HttpMessage <span class="kw">as _</span>;
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>test_http_request_chunked_payload_and_next_message() {
<span class="kw">let </span><span class="kw-2">mut </span>codec = Codec::default();
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(
<span class="string">"GET /test HTTP/1.1\r\n\
transfer-encoding: chunked\r\n\r\n"</span>,
);
<span class="kw">let </span>item = codec.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="kw">let </span>req = item.message();
<span class="macro">assert_eq!</span>(req.method(), Method::GET);
<span class="macro">assert!</span>(req.chunked().unwrap());
buf.extend(
<span class="string">b"4\r\ndata\r\n4\r\nline\r\n0\r\n\r\n\
POST /test2 HTTP/1.1\r\n\
transfer-encoding: chunked\r\n\r\n"
</span>.iter(),
);
<span class="kw">let </span>msg = codec.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert_eq!</span>(msg.chunk().as_ref(), <span class="string">b"data"</span>);
<span class="kw">let </span>msg = codec.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert_eq!</span>(msg.chunk().as_ref(), <span class="string">b"line"</span>);
<span class="kw">let </span>msg = codec.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="macro">assert!</span>(msg.eof());
<span class="comment">// decode next message
</span><span class="kw">let </span>item = codec.decode(<span class="kw-2">&amp;mut </span>buf).unwrap().unwrap();
<span class="kw">let </span>req = item.message();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>req.method(), Method::POST);
<span class="macro">assert!</span>(req.chunked().unwrap());
}
}
</code></pre></div></section></main></body></html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/h1/expect.rs`."><title>expect.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>actix_service::{Service, ServiceFactory};
<span class="kw">use </span>actix_utils::future::{ready, Ready};
<span class="kw">use crate</span>::{Error, Request};
<span class="kw">pub struct </span>ExpectHandler;
<span class="kw">impl </span>ServiceFactory&lt;Request&gt; <span class="kw">for </span>ExpectHandler {
<span class="kw">type </span>Response = Request;
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Config = ();
<span class="kw">type </span>Service = ExpectHandler;
<span class="kw">type </span>InitError = Error;
<span class="kw">type </span>Future = Ready&lt;<span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Service, <span class="self">Self</span>::InitError&gt;&gt;;
<span class="kw">fn </span>new_service(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: <span class="self">Self</span>::Config) -&gt; <span class="self">Self</span>::Future {
ready(<span class="prelude-val">Ok</span>(ExpectHandler))
}
}
<span class="kw">impl </span>Service&lt;Request&gt; <span class="kw">for </span>ExpectHandler {
<span class="kw">type </span>Response = Request;
<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>::Response, <span class="self">Self</span>::Error&gt;&gt;;
<span class="macro">actix_service::always_ready!</span>();
<span class="kw">fn </span>call(<span class="kw-2">&amp;</span><span class="self">self</span>, req: Request) -&gt; <span class="self">Self</span>::Future {
ready(<span class="prelude-val">Ok</span>(req))
<span class="comment">// TODO: add some way to trigger error
// Err(error::ErrorExpectationFailed("test"))
</span>}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,187 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/h1/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! HTTP/1 protocol implementation.
</span><span class="kw">use </span>bytes::{Bytes, BytesMut};
<span class="kw">mod </span>chunked;
<span class="kw">mod </span>client;
<span class="kw">mod </span>codec;
<span class="kw">mod </span>decoder;
<span class="kw">mod </span>dispatcher;
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>dispatcher_tests;
<span class="kw">mod </span>encoder;
<span class="kw">mod </span>expect;
<span class="kw">mod </span>payload;
<span class="kw">mod </span>service;
<span class="kw">mod </span>timer;
<span class="kw">mod </span>upgrade;
<span class="kw">mod </span>utils;
<span class="kw">pub use </span><span class="self">self</span>::{
client::{ClientCodec, ClientPayloadCodec},
codec::Codec,
dispatcher::Dispatcher,
expect::ExpectHandler,
payload::Payload,
service::{H1Service, H1ServiceHandler},
upgrade::UpgradeHandler,
utils::SendResponse,
};
<span class="attr">#[derive(Debug)]
</span><span class="doccomment">/// Codec message
</span><span class="kw">pub enum </span>Message&lt;T&gt; {
<span class="doccomment">/// HTTP message.
</span>Item(T),
<span class="doccomment">/// Payload chunk.
</span>Chunk(<span class="prelude-ty">Option</span>&lt;Bytes&gt;),
}
<span class="kw">impl</span>&lt;T&gt; From&lt;T&gt; <span class="kw">for </span>Message&lt;T&gt; {
<span class="kw">fn </span>from(item: T) -&gt; <span class="self">Self </span>{
Message::Item(item)
}
}
<span class="doccomment">/// Incoming request type
</span><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq)]
</span><span class="kw">pub enum </span>MessageType {
<span class="prelude-val">None</span>,
Payload,
Stream,
}
<span class="kw">const </span>LW: usize = <span class="number">2 </span>* <span class="number">1024</span>;
<span class="kw">const </span>HW: usize = <span class="number">32 </span>* <span class="number">1024</span>;
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>reserve_readbuf(src: <span class="kw-2">&amp;mut </span>BytesMut) {
<span class="kw">let </span>cap = src.capacity();
<span class="kw">if </span>cap &lt; LW {
src.reserve(HW - cap);
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use </span><span class="kw">crate</span>::Request;
<span class="kw">impl </span>Message&lt;Request&gt; {
<span class="kw">pub fn </span>message(<span class="self">self</span>) -&gt; Request {
<span class="kw">match </span><span class="self">self </span>{
Message::Item(req) =&gt; req,
<span class="kw">_ </span>=&gt; <span class="macro">panic!</span>(<span class="string">"error"</span>),
}
}
<span class="kw">pub fn </span>chunk(<span class="self">self</span>) -&gt; Bytes {
<span class="kw">match </span><span class="self">self </span>{
Message::Chunk(<span class="prelude-val">Some</span>(data)) =&gt; data,
<span class="kw">_ </span>=&gt; <span class="macro">panic!</span>(<span class="string">"error"</span>),
}
}
<span class="kw">pub fn </span>eof(<span class="self">self</span>) -&gt; bool {
<span class="kw">match </span><span class="self">self </span>{
Message::Chunk(<span class="prelude-val">None</span>) =&gt; <span class="bool-val">true</span>,
Message::Chunk(<span class="prelude-val">Some</span>(<span class="kw">_</span>)) =&gt; <span class="bool-val">false</span>,
<span class="kw">_ </span>=&gt; <span class="macro">panic!</span>(<span class="string">"error"</span>),
}
}
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,565 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/h1/payload.rs`."><title>payload.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Payload stream
</span><span class="kw">use </span>std::{
cell::RefCell,
collections::VecDeque,
pin::Pin,
rc::{Rc, Weak},
task::{Context, Poll, Waker},
};
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use </span>futures_core::Stream;
<span class="kw">use </span><span class="kw">crate</span>::error::PayloadError;
<span class="doccomment">/// max buffer size 32k
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>MAX_BUFFER_SIZE: usize = <span class="number">32_768</span>;
<span class="attr">#[derive(Debug, PartialEq, Eq)]
</span><span class="kw">pub enum </span>PayloadStatus {
Read,
Pause,
Dropped,
}
<span class="doccomment">/// Buffered stream of bytes chunks
///
/// Payload stores chunks in a vector. First chunk can be received with `poll_next`. Payload does
/// not notify current task when new data is available.
///
/// Payload can be used as `Response` body stream.
</span><span class="attr">#[derive(Debug)]
</span><span class="kw">pub struct </span>Payload {
inner: Rc&lt;RefCell&lt;Inner&gt;&gt;,
}
<span class="kw">impl </span>Payload {
<span class="doccomment">/// Creates a payload stream.
///
/// This method construct two objects responsible for bytes stream generation:
/// - `PayloadSender` - *Sender* side of the stream
/// - `Payload` - *Receiver* side of the stream
</span><span class="kw">pub fn </span>create(eof: bool) -&gt; (PayloadSender, Payload) {
<span class="kw">let </span>shared = Rc::new(RefCell::new(Inner::new(eof)));
(
PayloadSender::new(Rc::downgrade(<span class="kw-2">&amp;</span>shared)),
Payload { inner: shared },
)
}
<span class="doccomment">/// Creates an empty payload.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>empty() -&gt; Payload {
Payload {
inner: Rc::new(RefCell::new(Inner::new(<span class="bool-val">true</span>))),
}
}
<span class="doccomment">/// Length of the data in this payload
</span><span class="attr">#[cfg(test)]
</span><span class="kw">pub fn </span>len(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<span class="self">self</span>.inner.borrow().len()
}
<span class="doccomment">/// Is payload empty
</span><span class="attr">#[cfg(test)]
</span><span class="kw">pub fn </span>is_empty(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.inner.borrow().len() == <span class="number">0
</span>}
<span class="doccomment">/// Put unused data back to payload
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>unread_data(<span class="kw-2">&amp;mut </span><span class="self">self</span>, data: Bytes) {
<span class="self">self</span>.inner.borrow_mut().unread_data(data);
}
}
<span class="kw">impl </span>Stream <span class="kw">for </span>Payload {
<span class="kw">type </span>Item = <span class="prelude-ty">Result</span>&lt;Bytes, PayloadError&gt;;
<span class="kw">fn </span>poll_next(
<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;,
cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="prelude-ty">Result</span>&lt;Bytes, PayloadError&gt;&gt;&gt; {
Pin::new(<span class="kw-2">&amp;mut *</span><span class="self">self</span>.inner.borrow_mut()).poll_next(cx)
}
}
<span class="doccomment">/// Sender part of the payload stream
</span><span class="kw">pub struct </span>PayloadSender {
inner: Weak&lt;RefCell&lt;Inner&gt;&gt;,
}
<span class="kw">impl </span>PayloadSender {
<span class="kw">fn </span>new(inner: Weak&lt;RefCell&lt;Inner&gt;&gt;) -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{ inner }
}
<span class="attr">#[inline]
</span><span class="kw">pub fn </span>set_error(<span class="kw-2">&amp;mut </span><span class="self">self</span>, err: PayloadError) {
<span class="kw">if let </span><span class="prelude-val">Some</span>(shared) = <span class="self">self</span>.inner.upgrade() {
shared.borrow_mut().set_error(err)
}
}
<span class="attr">#[inline]
</span><span class="kw">pub fn </span>feed_eof(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="kw">if let </span><span class="prelude-val">Some</span>(shared) = <span class="self">self</span>.inner.upgrade() {
shared.borrow_mut().feed_eof()
}
}
<span class="attr">#[inline]
</span><span class="kw">pub fn </span>feed_data(<span class="kw-2">&amp;mut </span><span class="self">self</span>, data: Bytes) {
<span class="kw">if let </span><span class="prelude-val">Some</span>(shared) = <span class="self">self</span>.inner.upgrade() {
shared.borrow_mut().feed_data(data)
}
}
<span class="attr">#[allow(clippy::needless_pass_by_ref_mut)]
#[inline]
</span><span class="kw">pub fn </span>need_read(<span class="kw-2">&amp;</span><span class="self">self</span>, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; PayloadStatus {
<span class="comment">// we check need_read only if Payload (other side) is alive,
// otherwise always return true (consume payload)
</span><span class="kw">if let </span><span class="prelude-val">Some</span>(shared) = <span class="self">self</span>.inner.upgrade() {
<span class="kw">if </span>shared.borrow().need_read {
PayloadStatus::Read
} <span class="kw">else </span>{
shared.borrow_mut().register_io(cx);
PayloadStatus::Pause
}
} <span class="kw">else </span>{
PayloadStatus::Dropped
}
}
}
<span class="attr">#[derive(Debug)]
</span><span class="kw">struct </span>Inner {
len: usize,
eof: bool,
err: <span class="prelude-ty">Option</span>&lt;PayloadError&gt;,
need_read: bool,
items: VecDeque&lt;Bytes&gt;,
task: <span class="prelude-ty">Option</span>&lt;Waker&gt;,
io_task: <span class="prelude-ty">Option</span>&lt;Waker&gt;,
}
<span class="kw">impl </span>Inner {
<span class="kw">fn </span>new(eof: bool) -&gt; <span class="self">Self </span>{
Inner {
eof,
len: <span class="number">0</span>,
err: <span class="prelude-val">None</span>,
items: VecDeque::new(),
need_read: <span class="bool-val">true</span>,
task: <span class="prelude-val">None</span>,
io_task: <span class="prelude-val">None</span>,
}
}
<span class="doccomment">/// Wake up future waiting for payload data to be available.
</span><span class="kw">fn </span>wake(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="kw">if let </span><span class="prelude-val">Some</span>(waker) = <span class="self">self</span>.task.take() {
waker.wake();
}
}
<span class="doccomment">/// Wake up future feeding data to Payload.
</span><span class="kw">fn </span>wake_io(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="kw">if let </span><span class="prelude-val">Some</span>(waker) = <span class="self">self</span>.io_task.take() {
waker.wake();
}
}
<span class="doccomment">/// Register future waiting data from payload.
/// Waker would be used in `Inner::wake`
</span><span class="kw">fn </span>register(<span class="kw-2">&amp;mut </span><span class="self">self</span>, cx: <span class="kw-2">&amp;</span>Context&lt;<span class="lifetime">'_</span>&gt;) {
<span class="kw">if </span><span class="self">self
</span>.task
.as_ref()
.map_or(<span class="bool-val">true</span>, |w| !cx.waker().will_wake(w))
{
<span class="self">self</span>.task = <span class="prelude-val">Some</span>(cx.waker().clone());
}
}
<span class="comment">// Register future feeding data to payload.
</span><span class="doccomment">/// Waker would be used in `Inner::wake_io`
</span><span class="kw">fn </span>register_io(<span class="kw-2">&amp;mut </span><span class="self">self</span>, cx: <span class="kw-2">&amp;</span>Context&lt;<span class="lifetime">'_</span>&gt;) {
<span class="kw">if </span><span class="self">self
</span>.io_task
.as_ref()
.map_or(<span class="bool-val">true</span>, |w| !cx.waker().will_wake(w))
{
<span class="self">self</span>.io_task = <span class="prelude-val">Some</span>(cx.waker().clone());
}
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>set_error(<span class="kw-2">&amp;mut </span><span class="self">self</span>, err: PayloadError) {
<span class="self">self</span>.err = <span class="prelude-val">Some</span>(err);
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>feed_eof(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="self">self</span>.eof = <span class="bool-val">true</span>;
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>feed_data(<span class="kw-2">&amp;mut </span><span class="self">self</span>, data: Bytes) {
<span class="self">self</span>.len += data.len();
<span class="self">self</span>.items.push_back(data);
<span class="self">self</span>.need_read = <span class="self">self</span>.len &lt; MAX_BUFFER_SIZE;
<span class="self">self</span>.wake();
}
<span class="attr">#[cfg(test)]
</span><span class="kw">fn </span>len(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<span class="self">self</span>.len
}
<span class="kw">fn </span>poll_next(
<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;,
cx: <span class="kw-2">&amp;</span>Context&lt;<span class="lifetime">'_</span>&gt;,
) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="prelude-ty">Result</span>&lt;Bytes, PayloadError&gt;&gt;&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(data) = <span class="self">self</span>.items.pop_front() {
<span class="self">self</span>.len -= data.len();
<span class="self">self</span>.need_read = <span class="self">self</span>.len &lt; MAX_BUFFER_SIZE;
<span class="kw">if </span><span class="self">self</span>.need_read &amp;&amp; !<span class="self">self</span>.eof {
<span class="self">self</span>.register(cx);
}
<span class="self">self</span>.wake_io();
Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(data)))
} <span class="kw">else if let </span><span class="prelude-val">Some</span>(err) = <span class="self">self</span>.err.take() {
Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err)))
} <span class="kw">else if </span><span class="self">self</span>.eof {
Poll::Ready(<span class="prelude-val">None</span>)
} <span class="kw">else </span>{
<span class="self">self</span>.need_read = <span class="bool-val">true</span>;
<span class="self">self</span>.register(cx);
<span class="self">self</span>.wake_io();
Poll::Pending
}
}
<span class="kw">fn </span>unread_data(<span class="kw-2">&amp;mut </span><span class="self">self</span>, data: Bytes) {
<span class="self">self</span>.len += data.len();
<span class="self">self</span>.items.push_front(data);
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>actix_utils::future::poll_fn;
<span class="kw">use </span>static_assertions::{assert_impl_all, assert_not_impl_any};
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="macro">assert_impl_all!</span>(Payload: Unpin);
<span class="macro">assert_not_impl_any!</span>(Payload: Send, Sync);
<span class="macro">assert_impl_all!</span>(Inner: Unpin, Send, Sync);
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>test_unread_data() {
<span class="kw">let </span>(<span class="kw">_</span>, <span class="kw-2">mut </span>payload) = Payload::create(<span class="bool-val">false</span>);
payload.unread_data(Bytes::from(<span class="string">"data"</span>));
<span class="macro">assert!</span>(!payload.is_empty());
<span class="macro">assert_eq!</span>(payload.len(), <span class="number">4</span>);
<span class="macro">assert_eq!</span>(
Bytes::from(<span class="string">"data"</span>),
poll_fn(|cx| Pin::new(<span class="kw-2">&amp;mut </span>payload).poll_next(cx))
.<span class="kw">await
</span>.unwrap()
.unwrap()
);
}
}
</code></pre></div></section></main></body></html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,163 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/h1/timer.rs`."><title>timer.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{fmt, future::Future, pin::Pin, task::Context};
<span class="kw">use </span>actix_rt::time::{Instant, Sleep};
<span class="kw">use </span>tracing::trace;
<span class="attr">#[derive(Debug)]
</span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">enum </span>TimerState {
Disabled,
Inactive,
Active { timer: Pin&lt;Box&lt;Sleep&gt;&gt; },
}
<span class="kw">impl </span>TimerState {
<span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(enabled: bool) -&gt; <span class="self">Self </span>{
<span class="kw">if </span>enabled {
<span class="self">Self</span>::Inactive
} <span class="kw">else </span>{
<span class="self">Self</span>::Disabled
}
}
<span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>is_enabled(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="macro">matches!</span>(<span class="self">self</span>, <span class="self">Self</span>::Active { .. } | <span class="self">Self</span>::Inactive)
}
<span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>set(<span class="kw-2">&amp;mut </span><span class="self">self</span>, timer: Sleep, line: u32) {
<span class="kw">if </span><span class="macro">matches!</span>(<span class="self">self</span>, <span class="self">Self</span>::Disabled) {
<span class="macro">trace!</span>(<span class="string">"setting disabled timer from line {}"</span>, line);
}
<span class="kw-2">*</span><span class="self">self </span>= <span class="self">Self</span>::Active {
timer: Box::pin(timer),
};
}
<span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>set_and_init(<span class="kw-2">&amp;mut </span><span class="self">self</span>, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;, timer: Sleep, line: u32) {
<span class="self">self</span>.set(timer, line);
<span class="self">self</span>.init(cx);
}
<span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>clear(<span class="kw-2">&amp;mut </span><span class="self">self</span>, line: u32) {
<span class="kw">if </span><span class="macro">matches!</span>(<span class="self">self</span>, <span class="self">Self</span>::Disabled) {
<span class="macro">trace!</span>(<span class="string">"trying to clear a disabled timer from line {}"</span>, line);
}
<span class="kw">if </span><span class="macro">matches!</span>(<span class="self">self</span>, <span class="self">Self</span>::Inactive) {
<span class="macro">trace!</span>(<span class="string">"trying to clear an inactive timer from line {}"</span>, line);
}
<span class="kw-2">*</span><span class="self">self </span>= <span class="self">Self</span>::Inactive;
}
<span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>init(<span class="kw-2">&amp;mut </span><span class="self">self</span>, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) {
<span class="kw">if let </span>TimerState::Active { timer } = <span class="self">self </span>{
<span class="kw">let _ </span>= timer.as_mut().poll(cx);
}
}
}
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>TimerState {
<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">'_</span>&gt;) -&gt; fmt::Result {
<span class="kw">match </span><span class="self">self </span>{
TimerState::Disabled =&gt; f.write_str(<span class="string">"timer is disabled"</span>),
TimerState::Inactive =&gt; f.write_str(<span class="string">"timer is inactive"</span>),
TimerState::Active { timer } =&gt; {
<span class="kw">let </span>deadline = timer.deadline();
<span class="kw">let </span>now = Instant::now();
<span class="kw">if </span>deadline &lt; now {
f.write_str(<span class="string">"timer is active and has reached deadline"</span>)
} <span class="kw">else </span>{
<span class="macro">write!</span>(
f,
<span class="string">"timer is active and due to expire in {} milliseconds"</span>,
((deadline - now).as_secs_f32() * <span class="number">1000.0</span>)
)
}
}
}
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,65 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/h1/upgrade.rs`."><title>upgrade.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>actix_codec::Framed;
<span class="kw">use </span>actix_service::{Service, ServiceFactory};
<span class="kw">use </span>futures_core::future::LocalBoxFuture;
<span class="kw">use crate</span>::{h1::Codec, Error, Request};
<span class="kw">pub struct </span>UpgradeHandler;
<span class="kw">impl</span>&lt;T&gt; ServiceFactory&lt;(Request, Framed&lt;T, Codec&gt;)&gt; <span class="kw">for </span>UpgradeHandler {
<span class="kw">type </span>Response = ();
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Config = ();
<span class="kw">type </span>Service = UpgradeHandler;
<span class="kw">type </span>InitError = Error;
<span class="kw">type </span>Future = LocalBoxFuture&lt;<span class="lifetime">'static</span>, <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>::Service, <span class="self">Self</span>::InitError&gt;&gt;;
<span class="kw">fn </span>new_service(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: ()) -&gt; <span class="self">Self</span>::Future {
<span class="macro">unimplemented!</span>()
}
}
<span class="kw">impl</span>&lt;T&gt; Service&lt;(Request, Framed&lt;T, Codec&gt;)&gt; <span class="kw">for </span>UpgradeHandler {
<span class="kw">type </span>Response = ();
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Future = LocalBoxFuture&lt;<span class="lifetime">'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::always_ready!</span>();
<span class="kw">fn </span>call(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: (Request, Framed&lt;T, Codec&gt;)) -&gt; <span class="self">Self</span>::Future {
<span class="macro">unimplemented!</span>()
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,277 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/h1/utils.rs`."><title>utils.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>actix_codec::{AsyncRead, AsyncWrite, Framed};
<span class="kw">use </span>pin_project_lite::pin_project;
<span class="kw">use crate</span>::{
body::{BodySize, MessageBody},
h1::{Codec, Message},
Error, Response,
};
<span class="macro">pin_project!</span> {
<span class="doccomment">/// Send HTTP/1 response
</span><span class="kw">pub struct </span>SendResponse&lt;T, B&gt; {
res: <span class="prelude-ty">Option</span>&lt;Message&lt;(Response&lt;()&gt;, BodySize)&gt;&gt;,
<span class="attr">#[pin]
</span>body: <span class="prelude-ty">Option</span>&lt;B&gt;,
<span class="attr">#[pin]
</span>framed: <span class="prelude-ty">Option</span>&lt;Framed&lt;T, Codec&gt;&gt;,
}
}
<span class="kw">impl</span>&lt;T, B&gt; SendResponse&lt;T, B&gt;
<span class="kw">where
</span>B: MessageBody,
B::Error: Into&lt;Error&gt;,
{
<span class="kw">pub fn </span>new(framed: Framed&lt;T, Codec&gt;, response: Response&lt;B&gt;) -&gt; <span class="self">Self </span>{
<span class="kw">let </span>(res, body) = response.into_parts();
SendResponse {
res: <span class="prelude-val">Some</span>((res, body.size()).into()),
body: <span class="prelude-val">Some</span>(body),
framed: <span class="prelude-val">Some</span>(framed),
}
}
}
<span class="kw">impl</span>&lt;T, B&gt; Future <span class="kw">for </span>SendResponse&lt;T, B&gt;
<span class="kw">where
</span>T: AsyncRead + AsyncWrite + Unpin,
B: MessageBody,
B::Error: Into&lt;Error&gt;,
{
<span class="kw">type </span>Output = <span class="prelude-ty">Result</span>&lt;Framed&lt;T, Codec&gt;, Error&gt;;
<span class="comment">// TODO: rethink if we need loops in polls
</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;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;<span class="self">Self</span>::Output&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>this = <span class="self">self</span>.as_mut().project();
<span class="kw">let </span><span class="kw-2">mut </span>body_done = this.body.is_none();
<span class="kw">loop </span>{
<span class="kw">let </span><span class="kw-2">mut </span>body_ready = !body_done;
<span class="comment">// send body
</span><span class="kw">if </span>this.res.is_none() &amp;&amp; body_ready {
<span class="kw">while </span>body_ready
&amp;&amp; !body_done
&amp;&amp; !this
.framed
.as_ref()
.as_pin_ref()
.unwrap()
.is_write_buf_full()
{
<span class="kw">let </span>next = <span class="kw">match </span>this.body.as_mut().as_pin_mut().unwrap().poll_next(cx) {
Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(item))) =&gt; Poll::Ready(<span class="prelude-val">Some</span>(item)),
Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err))) =&gt; <span class="kw">return </span>Poll::Ready(<span class="prelude-val">Err</span>(err.into())),
Poll::Ready(<span class="prelude-val">None</span>) =&gt; Poll::Ready(<span class="prelude-val">None</span>),
Poll::Pending =&gt; Poll::Pending,
};
<span class="kw">match </span>next {
Poll::Ready(item) =&gt; {
<span class="comment">// body is done when item is None
</span>body_done = item.is_none();
<span class="kw">if </span>body_done {
this.body.set(<span class="prelude-val">None</span>);
}
<span class="kw">let </span>framed = this.framed.as_mut().as_pin_mut().unwrap();
framed
.write(Message::Chunk(item))
.map_err(|err| Error::new_send_response().with_cause(err))<span class="question-mark">?</span>;
}
Poll::Pending =&gt; body_ready = <span class="bool-val">false</span>,
}
}
}
<span class="kw">let </span>framed = this.framed.as_mut().as_pin_mut().unwrap();
<span class="comment">// flush write buffer
</span><span class="kw">if </span>!framed.is_write_buf_empty() {
<span class="kw">match </span>framed
.flush(cx)
.map_err(|err| Error::new_send_response().with_cause(err))<span class="question-mark">?
</span>{
Poll::Ready(<span class="kw">_</span>) =&gt; {
<span class="kw">if </span>body_ready {
<span class="kw">continue</span>;
} <span class="kw">else </span>{
<span class="kw">return </span>Poll::Pending;
}
}
Poll::Pending =&gt; <span class="kw">return </span>Poll::Pending,
}
}
<span class="comment">// send response
</span><span class="kw">if let </span><span class="prelude-val">Some</span>(res) = this.res.take() {
framed
.write(res)
.map_err(|err| Error::new_send_response().with_cause(err))<span class="question-mark">?</span>;
<span class="kw">continue</span>;
}
<span class="kw">if </span>!body_done {
<span class="kw">if </span>body_ready {
<span class="kw">continue</span>;
} <span class="kw">else </span>{
<span class="kw">return </span>Poll::Pending;
}
} <span class="kw">else </span>{
<span class="kw">break</span>;
}
}
<span class="kw">let </span>framed = this.framed.take().unwrap();
Poll::Ready(<span class="prelude-val">Ok</span>(framed))
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,711 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/h2/dispatcher.rs`."><title>dispatcher.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
<a href="#339" id="339">339</a>
<a href="#340" id="340">340</a>
<a href="#341" id="341">341</a>
<a href="#342" id="342">342</a>
<a href="#343" id="343">343</a>
<a href="#344" id="344">344</a>
<a href="#345" id="345">345</a>
<a href="#346" id="346">346</a>
<a href="#347" id="347">347</a>
<a href="#348" id="348">348</a>
<a href="#349" id="349">349</a>
<a href="#350" id="350">350</a>
<a href="#351" id="351">351</a>
<a href="#352" id="352">352</a>
<a href="#353" id="353">353</a>
<a href="#354" id="354">354</a>
<a href="#355" id="355">355</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
cmp,
error::Error <span class="kw">as </span>StdError,
future::Future,
marker::PhantomData,
net,
pin::{pin, Pin},
rc::Rc,
task::{Context, Poll},
};
<span class="kw">use </span>actix_codec::{AsyncRead, AsyncWrite};
<span class="kw">use </span>actix_rt::time::{sleep, Sleep};
<span class="kw">use </span>actix_service::Service;
<span class="kw">use </span>actix_utils::future::poll_fn;
<span class="kw">use </span>bytes::{Bytes, BytesMut};
<span class="kw">use </span>futures_core::ready;
<span class="kw">use </span>h2::{
server::{Connection, SendResponse},
Ping, PingPong,
};
<span class="kw">use </span>pin_project_lite::pin_project;
<span class="kw">use crate</span>::{
body::{BodySize, BoxBody, MessageBody},
config::ServiceConfig,
header::{
HeaderName, HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING, UPGRADE,
},
service::HttpFlow,
Extensions, Method, OnConnectData, Payload, Request, Response, ResponseHead,
};
<span class="kw">const </span>CHUNK_SIZE: usize = <span class="number">16_384</span>;
<span class="macro">pin_project!</span> {
<span class="doccomment">/// Dispatcher for HTTP/2 protocol.
</span><span class="kw">pub struct </span>Dispatcher&lt;T, S, B, X, U&gt; {
flow: Rc&lt;HttpFlow&lt;S, X, U&gt;&gt;,
connection: Connection&lt;T, Bytes&gt;,
conn_data: <span class="prelude-ty">Option</span>&lt;Rc&lt;Extensions&gt;&gt;,
config: ServiceConfig,
peer_addr: <span class="prelude-ty">Option</span>&lt;net::SocketAddr&gt;,
ping_pong: <span class="prelude-ty">Option</span>&lt;H2PingPong&gt;,
_phantom: PhantomData&lt;B&gt;
}
}
<span class="kw">impl</span>&lt;T, S, B, X, U&gt; Dispatcher&lt;T, S, B, X, U&gt;
<span class="kw">where
</span>T: AsyncRead + AsyncWrite + Unpin,
{
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new(
<span class="kw-2">mut </span>conn: Connection&lt;T, Bytes&gt;,
flow: Rc&lt;HttpFlow&lt;S, X, U&gt;&gt;,
config: ServiceConfig,
peer_addr: <span class="prelude-ty">Option</span>&lt;net::SocketAddr&gt;,
conn_data: OnConnectData,
timer: <span class="prelude-ty">Option</span>&lt;Pin&lt;Box&lt;Sleep&gt;&gt;&gt;,
) -&gt; <span class="self">Self </span>{
<span class="kw">let </span>ping_pong = config.keep_alive().duration().map(|dur| H2PingPong {
timer: timer
.map(|<span class="kw-2">mut </span>timer| {
<span class="comment">// reuse timer slot if it was initialized for handshake
</span>timer.as_mut().reset((config.now() + dur).into());
timer
})
.unwrap_or_else(|| Box::pin(sleep(dur))),
in_flight: <span class="bool-val">false</span>,
ping_pong: conn.ping_pong().unwrap(),
});
<span class="self">Self </span>{
flow,
config,
peer_addr,
connection: conn,
conn_data: conn_data.<span class="number">0</span>.map(Rc::new),
ping_pong,
_phantom: PhantomData,
}
}
}
<span class="kw">struct </span>H2PingPong {
<span class="doccomment">/// Handle to send ping frames from the peer.
</span>ping_pong: PingPong,
<span class="doccomment">/// True when a ping has been sent and is waiting for a reply.
</span>in_flight: bool,
<span class="doccomment">/// Timeout for pong response.
</span>timer: Pin&lt;Box&lt;Sleep&gt;&gt;,
}
<span class="kw">impl</span>&lt;T, S, B, X, U&gt; Future <span class="kw">for </span>Dispatcher&lt;T, S, B, X, U&gt;
<span class="kw">where
</span>T: AsyncRead + AsyncWrite + Unpin,
S: Service&lt;Request&gt;,
S::Error: Into&lt;Response&lt;BoxBody&gt;&gt;,
S::Future: <span class="lifetime">'static</span>,
S::Response: Into&lt;Response&lt;B&gt;&gt;,
B: MessageBody,
{
<span class="kw">type </span>Output = <span class="prelude-ty">Result</span>&lt;(), <span class="kw">crate</span>::error::DispatchError&gt;;
<span class="attr">#[inline]
</span><span class="kw">fn </span>poll(<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;<span class="self">Self</span>::Output&gt; {
<span class="kw">let </span>this = <span class="self">self</span>.get_mut();
<span class="kw">loop </span>{
<span class="kw">match </span>Pin::new(<span class="kw-2">&amp;mut </span>this.connection).poll_accept(cx)<span class="question-mark">? </span>{
Poll::Ready(<span class="prelude-val">Some</span>((req, tx))) =&gt; {
<span class="kw">let </span>(parts, body) = req.into_parts();
<span class="kw">let </span>payload = <span class="kw">crate</span>::h2::Payload::new(body);
<span class="kw">let </span>pl = Payload::H2 { payload };
<span class="kw">let </span><span class="kw-2">mut </span>req = Request::with_payload(pl);
<span class="kw">let </span>head_req = parts.method == Method::HEAD;
<span class="kw">let </span>head = req.head_mut();
head.uri = parts.uri;
head.method = parts.method;
head.version = parts.version;
head.headers = parts.headers.into();
head.peer_addr = this.peer_addr;
req.conn_data.clone_from(<span class="kw-2">&amp;</span>this.conn_data);
<span class="kw">let </span>fut = this.flow.service.call(req);
<span class="kw">let </span>config = this.config.clone();
<span class="comment">// multiplex request handling with spawn task
</span>actix_rt::spawn(<span class="kw">async move </span>{
<span class="comment">// resolve service call and send response.
</span><span class="kw">let </span>res = <span class="kw">match </span>fut.<span class="kw">await </span>{
<span class="prelude-val">Ok</span>(res) =&gt; handle_response(res.into(), tx, config, head_req).<span class="kw">await</span>,
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="kw">let </span>res: Response&lt;BoxBody&gt; = err.into();
handle_response(res, tx, config, head_req).<span class="kw">await
</span>}
};
<span class="comment">// log error.
</span><span class="kw">if let </span><span class="prelude-val">Err</span>(err) = res {
<span class="kw">match </span>err {
DispatchError::SendResponse(err) =&gt; {
<span class="macro">tracing::trace!</span>(<span class="string">"Error sending response: {err:?}"</span>);
}
DispatchError::SendData(err) =&gt; {
<span class="macro">tracing::warn!</span>(<span class="string">"Send data error: {err:?}"</span>);
}
DispatchError::ResponseBody(err) =&gt; {
<span class="macro">tracing::error!</span>(<span class="string">"Response payload stream error: {err:?}"</span>);
}
}
}
});
}
Poll::Ready(<span class="prelude-val">None</span>) =&gt; <span class="kw">return </span>Poll::Ready(<span class="prelude-val">Ok</span>(())),
Poll::Pending =&gt; <span class="kw">match </span>this.ping_pong.as_mut() {
<span class="prelude-val">Some</span>(ping_pong) =&gt; <span class="kw">loop </span>{
<span class="kw">if </span>ping_pong.in_flight {
<span class="comment">// When there is an in-flight ping-pong, poll pong and and keep-alive
// timer. On successful pong received, update keep-alive timer to
// determine the next timing of ping pong.
</span><span class="kw">match </span>ping_pong.ping_pong.poll_pong(cx)<span class="question-mark">? </span>{
Poll::Ready(<span class="kw">_</span>) =&gt; {
ping_pong.in_flight = <span class="bool-val">false</span>;
<span class="kw">let </span>dead_line = this.config.keep_alive_deadline().unwrap();
ping_pong.timer.as_mut().reset(dead_line.into());
}
Poll::Pending =&gt; {
<span class="kw">return </span>ping_pong.timer.as_mut().poll(cx).map(|<span class="kw">_</span>| <span class="prelude-val">Ok</span>(()));
}
}
} <span class="kw">else </span>{
<span class="comment">// When there is no in-flight ping-pong, keep-alive timer is used to
// wait for next timing of ping-pong. Therefore, at this point it serves
// as an interval instead.
</span><span class="macro">ready!</span>(ping_pong.timer.as_mut().poll(cx));
ping_pong.ping_pong.send_ping(Ping::opaque())<span class="question-mark">?</span>;
<span class="kw">let </span>dead_line = this.config.keep_alive_deadline().unwrap();
ping_pong.timer.as_mut().reset(dead_line.into());
ping_pong.in_flight = <span class="bool-val">true</span>;
}
},
<span class="prelude-val">None </span>=&gt; <span class="kw">return </span>Poll::Pending,
},
}
}
}
}
<span class="kw">enum </span>DispatchError {
SendResponse(h2::Error),
SendData(h2::Error),
ResponseBody(Box&lt;<span class="kw">dyn </span>StdError&gt;),
}
<span class="kw">async fn </span>handle_response&lt;B&gt;(
res: Response&lt;B&gt;,
<span class="kw-2">mut </span>tx: SendResponse&lt;Bytes&gt;,
config: ServiceConfig,
head_req: bool,
) -&gt; <span class="prelude-ty">Result</span>&lt;(), DispatchError&gt;
<span class="kw">where
</span>B: MessageBody,
{
<span class="kw">let </span>(res, body) = res.replace_body(());
<span class="comment">// prepare response.
</span><span class="kw">let </span><span class="kw-2">mut </span>size = body.size();
<span class="kw">let </span>res = prepare_response(config, res.head(), <span class="kw-2">&amp;mut </span>size);
<span class="kw">let </span>eof_or_head = size.is_eof() || head_req;
<span class="comment">// send response head and return on eof.
</span><span class="kw">let </span><span class="kw-2">mut </span>stream = tx
.send_response(res, eof_or_head)
.map_err(DispatchError::SendResponse)<span class="question-mark">?</span>;
<span class="kw">if </span>eof_or_head {
<span class="kw">return </span><span class="prelude-val">Ok</span>(());
}
<span class="kw">let </span><span class="kw-2">mut </span>body = <span class="macro">pin!</span>(body);
<span class="comment">// poll response body and send chunks to client
</span><span class="kw">while let </span><span class="prelude-val">Some</span>(res) = poll_fn(|cx| body.as_mut().poll_next(cx)).<span class="kw">await </span>{
<span class="kw">let </span><span class="kw-2">mut </span>chunk = res.map_err(|err| DispatchError::ResponseBody(err.into()))<span class="question-mark">?</span>;
<span class="lifetime">'send</span>: <span class="kw">loop </span>{
<span class="kw">let </span>chunk_size = cmp::min(chunk.len(), CHUNK_SIZE);
<span class="comment">// reserve enough space and wait for stream ready.
</span>stream.reserve_capacity(chunk_size);
<span class="kw">match </span>poll_fn(|cx| stream.poll_capacity(cx)).<span class="kw">await </span>{
<span class="comment">// No capacity left. drop body and return.
</span><span class="prelude-val">None </span>=&gt; <span class="kw">return </span><span class="prelude-val">Ok</span>(()),
<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err)) =&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(DispatchError::SendData(err)),
<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(cap)) =&gt; {
<span class="comment">// split chunk to writeable size and send to client
</span><span class="kw">let </span>len = chunk.len();
<span class="kw">let </span>bytes = chunk.split_to(cmp::min(len, cap));
stream
.send_data(bytes, <span class="bool-val">false</span>)
.map_err(DispatchError::SendData)<span class="question-mark">?</span>;
<span class="comment">// Current chuck completely sent. break send loop and poll next one.
</span><span class="kw">if </span>chunk.is_empty() {
<span class="kw">break </span><span class="lifetime">'send</span>;
}
}
}
}
}
<span class="comment">// response body streaming finished. send end of stream and return.
</span>stream
.send_data(Bytes::new(), <span class="bool-val">true</span>)
.map_err(DispatchError::SendData)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(())
}
<span class="kw">fn </span>prepare_response(
config: ServiceConfig,
head: <span class="kw-2">&amp;</span>ResponseHead,
size: <span class="kw-2">&amp;mut </span>BodySize,
) -&gt; http::Response&lt;()&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>has_date = <span class="bool-val">false</span>;
<span class="kw">let </span><span class="kw-2">mut </span>skip_len = size != <span class="kw-2">&amp;</span>BodySize::Stream;
<span class="kw">let </span><span class="kw-2">mut </span>res = http::Response::new(());
<span class="kw-2">*</span>res.status_mut() = head.status;
<span class="kw-2">*</span>res.version_mut() = http::Version::HTTP_2;
<span class="comment">// Content length
</span><span class="kw">match </span>head.status {
http::StatusCode::NO_CONTENT
| http::StatusCode::CONTINUE
| http::StatusCode::PROCESSING =&gt; <span class="kw-2">*</span>size = BodySize::None,
http::StatusCode::SWITCHING_PROTOCOLS =&gt; {
skip_len = <span class="bool-val">true</span>;
<span class="kw-2">*</span>size = BodySize::Stream;
}
<span class="kw">_ </span>=&gt; {}
}
<span class="kw">match </span>size {
BodySize::None | BodySize::Stream =&gt; {}
BodySize::Sized(<span class="number">0</span>) =&gt; {
<span class="attr">#[allow(clippy::declare_interior_mutable_const)]
</span><span class="kw">const </span>HV_ZERO: HeaderValue = HeaderValue::from_static(<span class="string">"0"</span>);
res.headers_mut().insert(CONTENT_LENGTH, HV_ZERO);
}
BodySize::Sized(len) =&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>buf = itoa::Buffer::new();
res.headers_mut().insert(
CONTENT_LENGTH,
HeaderValue::from_str(buf.format(<span class="kw-2">*</span>len)).unwrap(),
);
}
};
<span class="comment">// copy headers
</span><span class="kw">for </span>(key, value) <span class="kw">in </span>head.headers.iter() {
<span class="kw">match </span>key {
<span class="comment">// omit HTTP/1.x only headers according to:
// https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.2
</span><span class="kw-2">&amp;</span>CONNECTION | <span class="kw-2">&amp;</span>TRANSFER_ENCODING | <span class="kw-2">&amp;</span>UPGRADE =&gt; <span class="kw">continue</span>,
<span class="kw-2">&amp;</span>CONTENT_LENGTH <span class="kw">if </span>skip_len =&gt; <span class="kw">continue</span>,
<span class="kw-2">&amp;</span>DATE =&gt; has_date = <span class="bool-val">true</span>,
<span class="comment">// omit HTTP/1.x only headers according to:
// https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.2
</span>hdr <span class="kw">if </span>hdr == HeaderName::from_static(<span class="string">"keep-alive"</span>)
|| hdr == HeaderName::from_static(<span class="string">"proxy-connection"</span>) =&gt;
{
<span class="kw">continue
</span>}
<span class="kw">_ </span>=&gt; {}
}
res.headers_mut().append(key, value.clone());
}
<span class="comment">// set date header
</span><span class="kw">if </span>!has_date {
<span class="kw">let </span><span class="kw-2">mut </span>bytes = BytesMut::with_capacity(<span class="number">29</span>);
config.write_date_header_value(<span class="kw-2">&amp;mut </span>bytes);
res.headers_mut().insert(
DATE,
<span class="comment">// SAFETY: serialized date-times are known ASCII strings
</span><span class="kw">unsafe </span>{ HeaderValue::from_maybe_shared_unchecked(bytes.freeze()) },
);
}
res
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,215 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/h2/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! HTTP/2 protocol.
</span><span class="kw">use </span>std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>actix_codec::{AsyncRead, AsyncWrite};
<span class="kw">use </span>actix_rt::time::{sleep_until, Sleep};
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use </span>futures_core::{ready, Stream};
<span class="kw">use </span>h2::{
server::{handshake, Connection, Handshake},
RecvStream,
};
<span class="kw">use crate</span>::{
config::ServiceConfig,
error::{DispatchError, PayloadError},
};
<span class="kw">mod </span>dispatcher;
<span class="kw">mod </span>service;
<span class="kw">pub use </span><span class="self">self</span>::{dispatcher::Dispatcher, service::H2Service};
<span class="doccomment">/// HTTP/2 peer stream.
</span><span class="kw">pub struct </span>Payload {
stream: RecvStream,
}
<span class="kw">impl </span>Payload {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new(stream: RecvStream) -&gt; <span class="self">Self </span>{
<span class="self">Self </span>{ stream }
}
}
<span class="kw">impl </span>Stream <span class="kw">for </span>Payload {
<span class="kw">type </span>Item = <span class="prelude-ty">Result</span>&lt;Bytes, PayloadError&gt;;
<span class="kw">fn </span>poll_next(<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt;&gt; {
<span class="kw">let </span>this = <span class="self">self</span>.get_mut();
<span class="kw">match </span><span class="macro">ready!</span>(Pin::new(<span class="kw-2">&amp;mut </span>this.stream).poll_data(cx)) {
<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(chunk)) =&gt; {
<span class="kw">let </span>len = chunk.len();
<span class="kw">match </span>this.stream.flow_control().release_capacity(len) {
<span class="prelude-val">Ok</span>(()) =&gt; Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(chunk))),
<span class="prelude-val">Err</span>(err) =&gt; Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err.into()))),
}
}
<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err)) =&gt; Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err.into()))),
<span class="prelude-val">None </span>=&gt; Poll::Ready(<span class="prelude-val">None</span>),
}
}
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>handshake_with_timeout&lt;T&gt;(io: T, config: <span class="kw-2">&amp;</span>ServiceConfig) -&gt; HandshakeWithTimeout&lt;T&gt;
<span class="kw">where
</span>T: AsyncRead + AsyncWrite + Unpin,
{
HandshakeWithTimeout {
handshake: handshake(io),
timer: config
.client_request_deadline()
.map(|deadline| Box::pin(sleep_until(deadline.into()))),
}
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>HandshakeWithTimeout&lt;T: AsyncRead + AsyncWrite + Unpin&gt; {
handshake: Handshake&lt;T&gt;,
timer: <span class="prelude-ty">Option</span>&lt;Pin&lt;Box&lt;Sleep&gt;&gt;&gt;,
}
<span class="kw">impl</span>&lt;T&gt; Future <span class="kw">for </span>HandshakeWithTimeout&lt;T&gt;
<span class="kw">where
</span>T: AsyncRead + AsyncWrite + Unpin,
{
<span class="kw">type </span>Output = <span class="prelude-ty">Result</span>&lt;(Connection&lt;T, Bytes&gt;, <span class="prelude-ty">Option</span>&lt;Pin&lt;Box&lt;Sleep&gt;&gt;&gt;), DispatchError&gt;;
<span class="kw">fn </span>poll(<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;<span class="self">Self</span>::Output&gt; {
<span class="kw">let </span>this = <span class="self">self</span>.get_mut();
<span class="kw">match </span>Pin::new(<span class="kw-2">&amp;mut </span>this.handshake).poll(cx)<span class="question-mark">? </span>{
<span class="comment">// return the timer on success handshake; its slot can be re-used for h2 ping-pong
</span>Poll::Ready(conn) =&gt; Poll::Ready(<span class="prelude-val">Ok</span>((conn, this.timer.take()))),
Poll::Pending =&gt; <span class="kw">match </span>this.timer.as_mut() {
<span class="prelude-val">Some</span>(timer) =&gt; {
<span class="macro">ready!</span>(timer.as_mut().poll(cx));
Poll::Ready(<span class="prelude-val">Err</span>(DispatchError::SlowRequestTimeout))
}
<span class="prelude-val">None </span>=&gt; Poll::Pending,
},
}
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>static_assertions::assert_impl_all;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="macro">assert_impl_all!</span>(Payload: Unpin, Send, Sync);
}
</code></pre></div></section></main></body></html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,113 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/as_name.rs`."><title>as_name.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Sealed [`AsHeaderName`] trait and implementations.
</span><span class="kw">use </span>std::{borrow::Cow, str::FromStr <span class="kw">as _</span>};
<span class="kw">use </span>http::header::{HeaderName, InvalidHeaderName};
<span class="doccomment">/// Sealed trait implemented for types that can be effectively borrowed as a [`HeaderValue`].
///
/// [`HeaderValue`]: super::HeaderValue
</span><span class="kw">pub trait </span>AsHeaderName: Sealed {}
<span class="kw">pub struct </span>Seal;
<span class="kw">pub trait </span>Sealed {
<span class="kw">fn </span>try_as_name(<span class="kw-2">&amp;</span><span class="self">self</span>, seal: Seal) -&gt; <span class="prelude-ty">Result</span>&lt;Cow&lt;<span class="lifetime">'_</span>, HeaderName&gt;, InvalidHeaderName&gt;;
}
<span class="kw">impl </span>Sealed <span class="kw">for </span>HeaderName {
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_as_name(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Seal) -&gt; <span class="prelude-ty">Result</span>&lt;Cow&lt;<span class="lifetime">'_</span>, HeaderName&gt;, InvalidHeaderName&gt; {
<span class="prelude-val">Ok</span>(Cow::Borrowed(<span class="self">self</span>))
}
}
<span class="kw">impl </span>AsHeaderName <span class="kw">for </span>HeaderName {}
<span class="kw">impl </span>Sealed <span class="kw">for </span><span class="kw-2">&amp;</span>HeaderName {
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_as_name(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Seal) -&gt; <span class="prelude-ty">Result</span>&lt;Cow&lt;<span class="lifetime">'_</span>, HeaderName&gt;, InvalidHeaderName&gt; {
<span class="prelude-val">Ok</span>(Cow::Borrowed(<span class="kw-2">*</span><span class="self">self</span>))
}
}
<span class="kw">impl </span>AsHeaderName <span class="kw">for </span><span class="kw-2">&amp;</span>HeaderName {}
<span class="kw">impl </span>Sealed <span class="kw">for </span><span class="kw-2">&amp;</span>str {
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_as_name(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Seal) -&gt; <span class="prelude-ty">Result</span>&lt;Cow&lt;<span class="lifetime">'_</span>, HeaderName&gt;, InvalidHeaderName&gt; {
HeaderName::from_str(<span class="self">self</span>).map(Cow::Owned)
}
}
<span class="kw">impl </span>AsHeaderName <span class="kw">for </span><span class="kw-2">&amp;</span>str {}
<span class="kw">impl </span>Sealed <span class="kw">for </span>String {
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_as_name(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Seal) -&gt; <span class="prelude-ty">Result</span>&lt;Cow&lt;<span class="lifetime">'_</span>, HeaderName&gt;, InvalidHeaderName&gt; {
HeaderName::from_str(<span class="self">self</span>).map(Cow::Owned)
}
}
<span class="kw">impl </span>AsHeaderName <span class="kw">for </span>String {}
<span class="kw">impl </span>Sealed <span class="kw">for </span><span class="kw-2">&amp;</span>String {
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_as_name(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Seal) -&gt; <span class="prelude-ty">Result</span>&lt;Cow&lt;<span class="lifetime">'_</span>, HeaderName&gt;, InvalidHeaderName&gt; {
HeaderName::from_str(<span class="self">self</span>).map(Cow::Owned)
}
}
<span class="kw">impl </span>AsHeaderName <span class="kw">for </span><span class="kw-2">&amp;</span>String {}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,107 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/common.rs`."><title>common.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Common header names not defined in [`http`].
//!
//! Any headers added to this file will need to be re-exported from the list at `crate::headers`.
</span><span class="kw">use </span>http::header::HeaderName;
<span class="doccomment">/// Response header field that indicates how caches have handled that response and its corresponding
/// request.
///
/// See [RFC 9211](https://www.rfc-editor.org/rfc/rfc9211) for full semantics.
</span><span class="comment">// TODO(breaking): replace with http's version
</span><span class="kw">pub const </span>CACHE_STATUS: HeaderName = HeaderName::from_static(<span class="string">"cache-status"</span>);
<span class="doccomment">/// Response header field that allows origin servers to control the behavior of CDN caches
/// interposed between them and clients separately from other caches that might handle the response.
///
/// See [RFC 9213](https://www.rfc-editor.org/rfc/rfc9213) for full semantics.
</span><span class="comment">// TODO(breaking): replace with http's version
</span><span class="kw">pub const </span>CDN_CACHE_CONTROL: HeaderName = HeaderName::from_static(<span class="string">"cdn-cache-control"</span>);
<span class="doccomment">/// Response header that prevents a document from loading any cross-origin resources that don't
/// explicitly grant the document permission (using [CORP] or [CORS]).
///
/// [CORP]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy_(CORP)
/// [CORS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
</span><span class="kw">pub const </span>CROSS_ORIGIN_EMBEDDER_POLICY: HeaderName =
HeaderName::from_static(<span class="string">"cross-origin-embedder-policy"</span>);
<span class="doccomment">/// Response header that allows you to ensure a top-level document does not share a browsing context
/// group with cross-origin documents.
</span><span class="kw">pub const </span>CROSS_ORIGIN_OPENER_POLICY: HeaderName =
HeaderName::from_static(<span class="string">"cross-origin-opener-policy"</span>);
<span class="doccomment">/// Response header that conveys a desire that the browser blocks no-cors cross-origin/cross-site
/// requests to the given resource.
</span><span class="kw">pub const </span>CROSS_ORIGIN_RESOURCE_POLICY: HeaderName =
HeaderName::from_static(<span class="string">"cross-origin-resource-policy"</span>);
<span class="doccomment">/// Response header that provides a mechanism to allow and deny the use of browser features in a
/// document or within any `&lt;iframe&gt;` elements in the document.
</span><span class="kw">pub const </span>PERMISSIONS_POLICY: HeaderName = HeaderName::from_static(<span class="string">"permissions-policy"</span>);
<span class="doccomment">/// Request header (de-facto standard) for identifying the originating IP address of a client
/// connecting to a web server through a proxy server.
</span><span class="kw">pub const </span>X_FORWARDED_FOR: HeaderName = HeaderName::from_static(<span class="string">"x-forwarded-for"</span>);
<span class="doccomment">/// Request header (de-facto standard) for identifying the original host requested by the client in
/// the `Host` HTTP request header.
</span><span class="kw">pub const </span>X_FORWARDED_HOST: HeaderName = HeaderName::from_static(<span class="string">"x-forwarded-host"</span>);
<span class="doccomment">/// Request header (de-facto standard) for identifying the protocol that a client used to connect to
/// your proxy or load balancer.
</span><span class="kw">pub const </span>X_FORWARDED_PROTO: HeaderName = HeaderName::from_static(<span class="string">"x-forwarded-proto"</span>);
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,241 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/into_pair.rs`."><title>into_pair.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! [`TryIntoHeaderPair`] trait and implementations.
</span><span class="kw">use super</span>::{
Header, HeaderName, HeaderValue, InvalidHeaderName, InvalidHeaderValue, TryIntoHeaderValue,
};
<span class="kw">use </span><span class="kw">crate</span>::error::HttpError;
<span class="doccomment">/// An interface for types that can be converted into a [`HeaderName`] + [`HeaderValue`] pair for
/// insertion into a [`HeaderMap`].
///
/// [`HeaderMap`]: super::HeaderMap
</span><span class="kw">pub trait </span>TryIntoHeaderPair: Sized {
<span class="kw">type </span>Error: Into&lt;HttpError&gt;;
<span class="kw">fn </span>try_into_pair(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(HeaderName, HeaderValue), <span class="self">Self</span>::Error&gt;;
}
<span class="attr">#[derive(Debug)]
</span><span class="kw">pub enum </span>InvalidHeaderPart {
Name(InvalidHeaderName),
Value(InvalidHeaderValue),
}
<span class="kw">impl </span>From&lt;InvalidHeaderPart&gt; <span class="kw">for </span>HttpError {
<span class="kw">fn </span>from(part_err: InvalidHeaderPart) -&gt; <span class="self">Self </span>{
<span class="kw">match </span>part_err {
InvalidHeaderPart::Name(err) =&gt; err.into(),
InvalidHeaderPart::Value(err) =&gt; err.into(),
}
}
}
<span class="kw">impl</span>&lt;V&gt; TryIntoHeaderPair <span class="kw">for </span>(HeaderName, V)
<span class="kw">where
</span>V: TryIntoHeaderValue,
V::Error: Into&lt;InvalidHeaderValue&gt;,
{
<span class="kw">type </span>Error = InvalidHeaderPart;
<span class="kw">fn </span>try_into_pair(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(HeaderName, HeaderValue), <span class="self">Self</span>::Error&gt; {
<span class="kw">let </span>(name, value) = <span class="self">self</span>;
<span class="kw">let </span>value = value
.try_into_value()
.map_err(|err| InvalidHeaderPart::Value(err.into()))<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>((name, value))
}
}
<span class="kw">impl</span>&lt;V&gt; TryIntoHeaderPair <span class="kw">for </span>(<span class="kw-2">&amp;</span>HeaderName, V)
<span class="kw">where
</span>V: TryIntoHeaderValue,
V::Error: Into&lt;InvalidHeaderValue&gt;,
{
<span class="kw">type </span>Error = InvalidHeaderPart;
<span class="kw">fn </span>try_into_pair(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(HeaderName, HeaderValue), <span class="self">Self</span>::Error&gt; {
<span class="kw">let </span>(name, value) = <span class="self">self</span>;
<span class="kw">let </span>value = value
.try_into_value()
.map_err(|err| InvalidHeaderPart::Value(err.into()))<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>((name.clone(), value))
}
}
<span class="kw">impl</span>&lt;V&gt; TryIntoHeaderPair <span class="kw">for </span>(<span class="kw-2">&amp;</span>[u8], V)
<span class="kw">where
</span>V: TryIntoHeaderValue,
V::Error: Into&lt;InvalidHeaderValue&gt;,
{
<span class="kw">type </span>Error = InvalidHeaderPart;
<span class="kw">fn </span>try_into_pair(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(HeaderName, HeaderValue), <span class="self">Self</span>::Error&gt; {
<span class="kw">let </span>(name, value) = <span class="self">self</span>;
<span class="kw">let </span>name = HeaderName::try_from(name).map_err(InvalidHeaderPart::Name)<span class="question-mark">?</span>;
<span class="kw">let </span>value = value
.try_into_value()
.map_err(|err| InvalidHeaderPart::Value(err.into()))<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>((name, value))
}
}
<span class="kw">impl</span>&lt;V&gt; TryIntoHeaderPair <span class="kw">for </span>(<span class="kw-2">&amp;</span>str, V)
<span class="kw">where
</span>V: TryIntoHeaderValue,
V::Error: Into&lt;InvalidHeaderValue&gt;,
{
<span class="kw">type </span>Error = InvalidHeaderPart;
<span class="kw">fn </span>try_into_pair(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(HeaderName, HeaderValue), <span class="self">Self</span>::Error&gt; {
<span class="kw">let </span>(name, value) = <span class="self">self</span>;
<span class="kw">let </span>name = HeaderName::try_from(name).map_err(InvalidHeaderPart::Name)<span class="question-mark">?</span>;
<span class="kw">let </span>value = value
.try_into_value()
.map_err(|err| InvalidHeaderPart::Value(err.into()))<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>((name, value))
}
}
<span class="kw">impl</span>&lt;V&gt; TryIntoHeaderPair <span class="kw">for </span>(String, V)
<span class="kw">where
</span>V: TryIntoHeaderValue,
V::Error: Into&lt;InvalidHeaderValue&gt;,
{
<span class="kw">type </span>Error = InvalidHeaderPart;
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_into_pair(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(HeaderName, HeaderValue), <span class="self">Self</span>::Error&gt; {
<span class="kw">let </span>(name, value) = <span class="self">self</span>;
(name.as_str(), value).try_into_pair()
}
}
<span class="kw">impl</span>&lt;T: Header&gt; TryIntoHeaderPair <span class="kw">for </span>T {
<span class="kw">type </span>Error = &lt;T <span class="kw">as </span>TryIntoHeaderValue&gt;::Error;
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_into_pair(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(HeaderName, HeaderValue), <span class="self">Self</span>::Error&gt; {
<span class="prelude-val">Ok</span>((T::name(), <span class="self">self</span>.try_into_value()<span class="question-mark">?</span>))
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,263 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/into_value.rs`."><title>into_value.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! [`TryIntoHeaderValue`] trait and implementations.
</span><span class="kw">use </span>bytes::Bytes;
<span class="kw">use </span>http::{header::InvalidHeaderValue, Error <span class="kw">as </span>HttpError, HeaderValue};
<span class="kw">use </span>mime::Mime;
<span class="doccomment">/// An interface for types that can be converted into a [`HeaderValue`].
</span><span class="kw">pub trait </span>TryIntoHeaderValue: Sized {
<span class="doccomment">/// The type returned in the event of a conversion error.
</span><span class="kw">type </span>Error: Into&lt;HttpError&gt;;
<span class="doccomment">/// Try to convert value to a HeaderValue.
</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">impl </span>TryIntoHeaderValue <span class="kw">for </span>HeaderValue {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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="prelude-val">Ok</span>(<span class="self">self</span>)
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span><span class="kw-2">&amp;</span>HeaderValue {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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="prelude-val">Ok</span>(<span class="self">self</span>.clone())
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span><span class="kw-2">&amp;</span>str {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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>.parse()
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span><span class="kw-2">&amp;</span>[u8] {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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_bytes(<span class="self">self</span>)
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>Bytes {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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>)
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>Vec&lt;u8&gt; {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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::try_from(<span class="self">self</span>)
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>String {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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::try_from(<span class="self">self</span>)
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>usize {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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::try_from(<span class="self">self</span>.to_string())
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>i64 {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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::try_from(<span class="self">self</span>.to_string())
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>u64 {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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::try_from(<span class="self">self</span>.to_string())
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>i32 {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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::try_from(<span class="self">self</span>.to_string())
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>u32 {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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::try_from(<span class="self">self</span>.to_string())
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>Mime {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="attr">#[inline]
</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_str(<span class="self">self</span>.as_ref())
}
}
</code></pre></div></section></main></body></html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,181 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Pre-defined `HeaderName`s, traits for parsing and conversion, and other header utility methods.
</span><span class="comment">// declaring new header consts will yield this error
</span><span class="attr">#![allow(clippy::declare_interior_mutable_const)]
</span><span class="comment">// re-export from http except header map related items
</span><span class="kw">pub use </span>::http::header::{
HeaderName, HeaderValue, InvalidHeaderName, InvalidHeaderValue, ToStrError,
};
<span class="comment">// re-export const header names, list is explicit so that any updates to `common` module do not
// conflict with this set
</span><span class="kw">pub use </span>::http::header::{
ACCEPT, ACCEPT_CHARSET, ACCEPT_ENCODING, ACCEPT_LANGUAGE, ACCEPT_RANGES,
ACCESS_CONTROL_ALLOW_CREDENTIALS, ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_METHODS,
ACCESS_CONTROL_ALLOW_ORIGIN, ACCESS_CONTROL_EXPOSE_HEADERS, ACCESS_CONTROL_MAX_AGE,
ACCESS_CONTROL_REQUEST_HEADERS, ACCESS_CONTROL_REQUEST_METHOD, AGE, ALLOW, ALT_SVC,
AUTHORIZATION, CACHE_CONTROL, CONNECTION, CONTENT_DISPOSITION, CONTENT_ENCODING,
CONTENT_LANGUAGE, CONTENT_LENGTH, CONTENT_LOCATION, CONTENT_RANGE, CONTENT_SECURITY_POLICY,
CONTENT_SECURITY_POLICY_REPORT_ONLY, CONTENT_TYPE, COOKIE, DATE, DNT, ETAG, EXPECT, EXPIRES,
FORWARDED, FROM, HOST, IF_MATCH, IF_MODIFIED_SINCE, IF_NONE_MATCH, IF_RANGE,
IF_UNMODIFIED_SINCE, LAST_MODIFIED, LINK, LOCATION, MAX_FORWARDS, ORIGIN, PRAGMA,
PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, PUBLIC_KEY_PINS, PUBLIC_KEY_PINS_REPORT_ONLY, RANGE,
REFERER, REFERRER_POLICY, REFRESH, RETRY_AFTER, SEC_WEBSOCKET_ACCEPT, SEC_WEBSOCKET_EXTENSIONS,
SEC_WEBSOCKET_KEY, SEC_WEBSOCKET_PROTOCOL, SEC_WEBSOCKET_VERSION, SERVER, SET_COOKIE,
STRICT_TRANSPORT_SECURITY, TE, TRAILER, TRANSFER_ENCODING, UPGRADE, UPGRADE_INSECURE_REQUESTS,
USER_AGENT, VARY, VIA, WARNING, WWW_AUTHENTICATE, X_CONTENT_TYPE_OPTIONS,
X_DNS_PREFETCH_CONTROL, X_FRAME_OPTIONS, X_XSS_PROTECTION,
};
<span class="kw">use </span>percent_encoding::{AsciiSet, CONTROLS};
<span class="kw">use crate</span>::{error::ParseError, HttpMessage};
<span class="kw">mod </span>as_name;
<span class="kw">mod </span>common;
<span class="kw">mod </span>into_pair;
<span class="kw">mod </span>into_value;
<span class="kw">pub mod </span>map;
<span class="kw">mod </span>shared;
<span class="kw">mod </span>utils;
<span class="kw">pub use </span><span class="self">self</span>::{
as_name::AsHeaderName,
<span class="comment">// re-export list is explicit so that any updates to `http` do not conflict with this set
</span>common::{
CACHE_STATUS, CDN_CACHE_CONTROL, CROSS_ORIGIN_EMBEDDER_POLICY, CROSS_ORIGIN_OPENER_POLICY,
CROSS_ORIGIN_RESOURCE_POLICY, PERMISSIONS_POLICY, X_FORWARDED_FOR, X_FORWARDED_HOST,
X_FORWARDED_PROTO,
},
into_pair::TryIntoHeaderPair,
into_value::TryIntoHeaderValue,
map::HeaderMap,
shared::{
parse_extended_value, q, Charset, ContentEncoding, ExtendedValue, HttpDate, LanguageTag,
Quality, QualityItem,
},
utils::{fmt_comma_delimited, from_comma_delimited, from_one_raw_str, http_percent_encode},
};
<span class="doccomment">/// An interface for types that already represent a valid header.
</span><span class="kw">pub trait </span>Header: TryIntoHeaderValue {
<span class="doccomment">/// Returns the name of the header field.
</span><span class="kw">fn </span>name() -&gt; HeaderName;
<span class="doccomment">/// Parse the header from a HTTP message.
</span><span class="kw">fn </span>parse&lt;M: HttpMessage&gt;(msg: <span class="kw-2">&amp;</span>M) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, ParseError&gt;;
}
<span class="doccomment">/// This encode set is used for HTTP header values and is defined at
/// &lt;https://datatracker.ietf.org/doc/html/rfc5987#section-3.2&gt;.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>HTTP_VALUE: <span class="kw-2">&amp;</span>AsciiSet = <span class="kw-2">&amp;</span>CONTROLS
.add(<span class="string">b' '</span>)
.add(<span class="string">b'"'</span>)
.add(<span class="string">b'%'</span>)
.add(<span class="string">b'\''</span>)
.add(<span class="string">b'('</span>)
.add(<span class="string">b')'</span>)
.add(<span class="string">b'*'</span>)
.add(<span class="string">b','</span>)
.add(<span class="string">b'/'</span>)
.add(<span class="string">b':'</span>)
.add(<span class="string">b';'</span>)
.add(<span class="string">b'&lt;'</span>)
.add(<span class="string">b'-'</span>)
.add(<span class="string">b'&gt;'</span>)
.add(<span class="string">b'?'</span>)
.add(<span class="string">b'['</span>)
.add(<span class="string">b'\\'</span>)
.add(<span class="string">b']'</span>)
.add(<span class="string">b'{'</span>)
.add(<span class="string">b'}'</span>);
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,311 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/shared/charset.rs`."><title>charset.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{fmt, str};
<span class="kw">use </span><span class="self">self</span>::Charset::<span class="kw-2">*</span>;
<span class="doccomment">/// A MIME character set.
///
/// The string representation is normalized to upper case.
///
/// See &lt;http://www.iana.org/assignments/character-sets/character-sets.xhtml&gt;.
</span><span class="attr">#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(non_camel_case_types)]
</span><span class="kw">pub enum </span>Charset {
<span class="doccomment">/// US ASCII
</span>Us_Ascii,
<span class="doccomment">/// ISO-8859-1
</span>Iso_8859_1,
<span class="doccomment">/// ISO-8859-2
</span>Iso_8859_2,
<span class="doccomment">/// ISO-8859-3
</span>Iso_8859_3,
<span class="doccomment">/// ISO-8859-4
</span>Iso_8859_4,
<span class="doccomment">/// ISO-8859-5
</span>Iso_8859_5,
<span class="doccomment">/// ISO-8859-6
</span>Iso_8859_6,
<span class="doccomment">/// ISO-8859-7
</span>Iso_8859_7,
<span class="doccomment">/// ISO-8859-8
</span>Iso_8859_8,
<span class="doccomment">/// ISO-8859-9
</span>Iso_8859_9,
<span class="doccomment">/// ISO-8859-10
</span>Iso_8859_10,
<span class="doccomment">/// Shift_JIS
</span>Shift_Jis,
<span class="doccomment">/// EUC-JP
</span>Euc_Jp,
<span class="doccomment">/// ISO-2022-KR
</span>Iso_2022_Kr,
<span class="doccomment">/// EUC-KR
</span>Euc_Kr,
<span class="doccomment">/// ISO-2022-JP
</span>Iso_2022_Jp,
<span class="doccomment">/// ISO-2022-JP-2
</span>Iso_2022_Jp_2,
<span class="doccomment">/// ISO-8859-6-E
</span>Iso_8859_6_E,
<span class="doccomment">/// ISO-8859-6-I
</span>Iso_8859_6_I,
<span class="doccomment">/// ISO-8859-8-E
</span>Iso_8859_8_E,
<span class="doccomment">/// ISO-8859-8-I
</span>Iso_8859_8_I,
<span class="doccomment">/// GB2312
</span>Gb2312,
<span class="doccomment">/// Big5
</span>Big5,
<span class="doccomment">/// KOI8-R
</span>Koi8_R,
<span class="doccomment">/// An arbitrary charset specified as a string
</span>Ext(String),
}
<span class="kw">impl </span>Charset {
<span class="kw">fn </span>label(<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="kw-2">*</span><span class="self">self </span>{
Us_Ascii =&gt; <span class="string">"US-ASCII"</span>,
Iso_8859_1 =&gt; <span class="string">"ISO-8859-1"</span>,
Iso_8859_2 =&gt; <span class="string">"ISO-8859-2"</span>,
Iso_8859_3 =&gt; <span class="string">"ISO-8859-3"</span>,
Iso_8859_4 =&gt; <span class="string">"ISO-8859-4"</span>,
Iso_8859_5 =&gt; <span class="string">"ISO-8859-5"</span>,
Iso_8859_6 =&gt; <span class="string">"ISO-8859-6"</span>,
Iso_8859_7 =&gt; <span class="string">"ISO-8859-7"</span>,
Iso_8859_8 =&gt; <span class="string">"ISO-8859-8"</span>,
Iso_8859_9 =&gt; <span class="string">"ISO-8859-9"</span>,
Iso_8859_10 =&gt; <span class="string">"ISO-8859-10"</span>,
Shift_Jis =&gt; <span class="string">"Shift-JIS"</span>,
Euc_Jp =&gt; <span class="string">"EUC-JP"</span>,
Iso_2022_Kr =&gt; <span class="string">"ISO-2022-KR"</span>,
Euc_Kr =&gt; <span class="string">"EUC-KR"</span>,
Iso_2022_Jp =&gt; <span class="string">"ISO-2022-JP"</span>,
Iso_2022_Jp_2 =&gt; <span class="string">"ISO-2022-JP-2"</span>,
Iso_8859_6_E =&gt; <span class="string">"ISO-8859-6-E"</span>,
Iso_8859_6_I =&gt; <span class="string">"ISO-8859-6-I"</span>,
Iso_8859_8_E =&gt; <span class="string">"ISO-8859-8-E"</span>,
Iso_8859_8_I =&gt; <span class="string">"ISO-8859-8-I"</span>,
Gb2312 =&gt; <span class="string">"GB2312"</span>,
Big5 =&gt; <span class="string">"Big5"</span>,
Koi8_R =&gt; <span class="string">"KOI8-R"</span>,
Ext(<span class="kw-2">ref </span>s) =&gt; s,
}
}
}
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>Charset {
<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">'_</span>&gt;) -&gt; fmt::Result {
f.write_str(<span class="self">self</span>.label())
}
}
<span class="kw">impl </span>str::FromStr <span class="kw">for </span>Charset {
<span class="kw">type </span><span class="prelude-val">Err </span>= <span class="kw">crate</span>::Error;
<span class="kw">fn </span>from_str(s: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;Charset, <span class="kw">crate</span>::Error&gt; {
<span class="prelude-val">Ok</span>(<span class="kw">match </span>s.to_ascii_uppercase().as_ref() {
<span class="string">"US-ASCII" </span>=&gt; Us_Ascii,
<span class="string">"ISO-8859-1" </span>=&gt; Iso_8859_1,
<span class="string">"ISO-8859-2" </span>=&gt; Iso_8859_2,
<span class="string">"ISO-8859-3" </span>=&gt; Iso_8859_3,
<span class="string">"ISO-8859-4" </span>=&gt; Iso_8859_4,
<span class="string">"ISO-8859-5" </span>=&gt; Iso_8859_5,
<span class="string">"ISO-8859-6" </span>=&gt; Iso_8859_6,
<span class="string">"ISO-8859-7" </span>=&gt; Iso_8859_7,
<span class="string">"ISO-8859-8" </span>=&gt; Iso_8859_8,
<span class="string">"ISO-8859-9" </span>=&gt; Iso_8859_9,
<span class="string">"ISO-8859-10" </span>=&gt; Iso_8859_10,
<span class="string">"SHIFT-JIS" </span>=&gt; Shift_Jis,
<span class="string">"EUC-JP" </span>=&gt; Euc_Jp,
<span class="string">"ISO-2022-KR" </span>=&gt; Iso_2022_Kr,
<span class="string">"EUC-KR" </span>=&gt; Euc_Kr,
<span class="string">"ISO-2022-JP" </span>=&gt; Iso_2022_Jp,
<span class="string">"ISO-2022-JP-2" </span>=&gt; Iso_2022_Jp_2,
<span class="string">"ISO-8859-6-E" </span>=&gt; Iso_8859_6_E,
<span class="string">"ISO-8859-6-I" </span>=&gt; Iso_8859_6_I,
<span class="string">"ISO-8859-8-E" </span>=&gt; Iso_8859_8_E,
<span class="string">"ISO-8859-8-I" </span>=&gt; Iso_8859_8_I,
<span class="string">"GB2312" </span>=&gt; Gb2312,
<span class="string">"BIG5" </span>=&gt; Big5,
<span class="string">"KOI8-R" </span>=&gt; Koi8_R,
s =&gt; Ext(s.to_owned()),
})
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse() {
<span class="macro">assert_eq!</span>(Us_Ascii, <span class="string">"us-ascii"</span>.parse().unwrap());
<span class="macro">assert_eq!</span>(Us_Ascii, <span class="string">"US-Ascii"</span>.parse().unwrap());
<span class="macro">assert_eq!</span>(Us_Ascii, <span class="string">"US-ASCII"</span>.parse().unwrap());
<span class="macro">assert_eq!</span>(Shift_Jis, <span class="string">"Shift-JIS"</span>.parse().unwrap());
<span class="macro">assert_eq!</span>(Ext(<span class="string">"ABCD"</span>.to_owned()), <span class="string">"abcd"</span>.parse().unwrap());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_display() {
<span class="macro">assert_eq!</span>(<span class="string">"US-ASCII"</span>, <span class="macro">format!</span>(<span class="string">"{}"</span>, Us_Ascii));
<span class="macro">assert_eq!</span>(<span class="string">"ABCD"</span>, <span class="macro">format!</span>(<span class="string">"{}"</span>, Ext(<span class="string">"ABCD"</span>.to_owned())));
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,247 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/shared/content_encoding.rs`."><title>content_encoding.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::str::FromStr;
<span class="kw">use </span>derive_more::{Display, Error};
<span class="kw">use </span>http::header::InvalidHeaderValue;
<span class="kw">use crate</span>::{
error::ParseError,
header::{<span class="self">self</span>, from_one_raw_str, Header, HeaderName, HeaderValue, TryIntoHeaderValue},
HttpMessage,
};
<span class="doccomment">/// Error returned when a content encoding is unknown.
</span><span class="attr">#[derive(Debug, Display, Error)]
#[display(fmt = <span class="string">"unsupported content encoding"</span>)]
</span><span class="kw">pub struct </span>ContentEncodingParseError;
<span class="doccomment">/// Represents a supported content encoding.
///
/// Includes a commonly-used subset of media types appropriate for use as HTTP content encodings.
/// See [IANA HTTP Content Coding Registry].
///
/// [IANA HTTP Content Coding Registry]: https://www.iana.org/assignments/http-parameters/http-parameters.xhtml
</span><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>ContentEncoding {
<span class="doccomment">/// Indicates the no-op identity encoding.
///
/// I.e., no compression or modification.
</span>Identity,
<span class="doccomment">/// A format using the Brotli algorithm.
</span>Brotli,
<span class="doccomment">/// A format using the zlib structure with deflate algorithm.
</span>Deflate,
<span class="doccomment">/// Gzip algorithm.
</span>Gzip,
<span class="doccomment">/// Zstd algorithm.
</span>Zstd,
}
<span class="kw">impl </span>ContentEncoding {
<span class="doccomment">/// Convert content encoding to string.
</span><span class="attr">#[inline]
</span><span class="kw">pub const fn </span>as_str(<span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<span class="kw">match </span><span class="self">self </span>{
ContentEncoding::Brotli =&gt; <span class="string">"br"</span>,
ContentEncoding::Gzip =&gt; <span class="string">"gzip"</span>,
ContentEncoding::Deflate =&gt; <span class="string">"deflate"</span>,
ContentEncoding::Zstd =&gt; <span class="string">"zstd"</span>,
ContentEncoding::Identity =&gt; <span class="string">"identity"</span>,
}
}
<span class="doccomment">/// Convert content encoding to header value.
</span><span class="attr">#[inline]
</span><span class="kw">pub const fn </span>to_header_value(<span class="self">self</span>) -&gt; HeaderValue {
<span class="kw">match </span><span class="self">self </span>{
ContentEncoding::Brotli =&gt; HeaderValue::from_static(<span class="string">"br"</span>),
ContentEncoding::Gzip =&gt; HeaderValue::from_static(<span class="string">"gzip"</span>),
ContentEncoding::Deflate =&gt; HeaderValue::from_static(<span class="string">"deflate"</span>),
ContentEncoding::Zstd =&gt; HeaderValue::from_static(<span class="string">"zstd"</span>),
ContentEncoding::Identity =&gt; HeaderValue::from_static(<span class="string">"identity"</span>),
}
}
}
<span class="kw">impl </span>Default <span class="kw">for </span>ContentEncoding {
<span class="attr">#[inline]
</span><span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::Identity
}
}
<span class="kw">impl </span>FromStr <span class="kw">for </span>ContentEncoding {
<span class="kw">type </span><span class="prelude-val">Err </span>= ContentEncodingParseError;
<span class="kw">fn </span>from_str(enc: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, <span class="self">Self</span>::Err&gt; {
<span class="kw">let </span>enc = enc.trim();
<span class="kw">if </span>enc.eq_ignore_ascii_case(<span class="string">"br"</span>) {
<span class="prelude-val">Ok</span>(ContentEncoding::Brotli)
} <span class="kw">else if </span>enc.eq_ignore_ascii_case(<span class="string">"gzip"</span>) {
<span class="prelude-val">Ok</span>(ContentEncoding::Gzip)
} <span class="kw">else if </span>enc.eq_ignore_ascii_case(<span class="string">"deflate"</span>) {
<span class="prelude-val">Ok</span>(ContentEncoding::Deflate)
} <span class="kw">else if </span>enc.eq_ignore_ascii_case(<span class="string">"identity"</span>) {
<span class="prelude-val">Ok</span>(ContentEncoding::Identity)
} <span class="kw">else if </span>enc.eq_ignore_ascii_case(<span class="string">"zstd"</span>) {
<span class="prelude-val">Ok</span>(ContentEncoding::Zstd)
} <span class="kw">else </span>{
<span class="prelude-val">Err</span>(ContentEncodingParseError)
}
}
}
<span class="kw">impl </span>TryFrom&lt;<span class="kw-2">&amp;</span>str&gt; <span class="kw">for </span>ContentEncoding {
<span class="kw">type </span>Error = ContentEncodingParseError;
<span class="kw">fn </span>try_from(val: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, <span class="self">Self</span>::Error&gt; {
val.parse()
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>ContentEncoding {
<span class="kw">type </span>Error = InvalidHeaderValue;
<span class="kw">fn </span>try_into_value(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;http::HeaderValue, <span class="self">Self</span>::Error&gt; {
<span class="prelude-val">Ok</span>(HeaderValue::from_static(<span class="self">self</span>.as_str()))
}
}
<span class="kw">impl </span>Header <span class="kw">for </span>ContentEncoding {
<span class="kw">fn </span>name() -&gt; HeaderName {
header::CONTENT_ENCODING
}
<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; {
from_one_raw_str(msg.headers().get(<span class="self">Self</span>::name()))
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,389 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/shared/extended.rs`."><title>extended.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Originally taken from `hyper::header::parsing`.
</span><span class="kw">use </span>std::{fmt, str::FromStr};
<span class="kw">use </span>language_tags::LanguageTag;
<span class="kw">use </span><span class="kw">crate</span>::header::{Charset, HTTP_VALUE};
<span class="doccomment">/// The value part of an extended parameter consisting of three parts:
/// - The REQUIRED character set name (`charset`).
/// - The OPTIONAL language information (`language_tag`).
/// - A character sequence representing the actual value (`value`), separated by single quotes.
///
/// It is defined in [RFC 5987 §3.2](https://datatracker.ietf.org/doc/html/rfc5987#section-3.2).
</span><span class="attr">#[derive(Clone, Debug, PartialEq, Eq)]
</span><span class="kw">pub struct </span>ExtendedValue {
<span class="doccomment">/// The character set that is used to encode the `value` to a string.
</span><span class="kw">pub </span>charset: Charset,
<span class="doccomment">/// The human language details of the `value`, if available.
</span><span class="kw">pub </span>language_tag: <span class="prelude-ty">Option</span>&lt;LanguageTag&gt;,
<span class="doccomment">/// The parameter value, as expressed in octets.
</span><span class="kw">pub </span>value: Vec&lt;u8&gt;,
}
<span class="doccomment">/// Parses extended header parameter values (`ext-value`), as defined
/// in [RFC 5987 §3.2](https://datatracker.ietf.org/doc/html/rfc5987#section-3.2).
///
/// Extended values are denoted by parameter names that end with `*`.
///
/// ## ABNF
///
/// ```plain
/// ext-value = charset "'" [ language ] "'" value-chars
/// ; like RFC 2231's &lt;extended-initial-value&gt;
/// ; (see [RFC 2231 §7])
///
/// charset = "UTF-8" / "ISO-8859-1" / mime-charset
///
/// mime-charset = 1*mime-charsetc
/// mime-charsetc = ALPHA / DIGIT
/// / "!" / "#" / "$" / "%" / "&amp;"
/// / "+" / "-" / "^" / "_" / "`"
/// / "{" / "}" / "~"
/// ; as &lt;mime-charset&gt; in [RFC 2978 §2.3]
/// ; except that the single quote is not included
/// ; SHOULD be registered in the IANA charset registry
///
/// language = &lt;Language-Tag, defined in [RFC 5646 §2.1]&gt;
///
/// value-chars = *( pct-encoded / attr-char )
///
/// pct-encoded = "%" HEXDIG HEXDIG
/// ; see [RFC 3986 §2.1]
///
/// attr-char = ALPHA / DIGIT
/// / "!" / "#" / "$" / "&amp;" / "+" / "-" / "."
/// / "^" / "_" / "`" / "|" / "~"
/// ; token except ( "*" / "'" / "%" )
/// ```
///
/// [RFC 2231 §7]: https://datatracker.ietf.org/doc/html/rfc2231#section-7
/// [RFC 2978 §2.3]: https://datatracker.ietf.org/doc/html/rfc2978#section-2.3
/// [RFC 3986 §2.1]: https://datatracker.ietf.org/doc/html/rfc5646#section-2.1
</span><span class="kw">pub fn </span>parse_extended_value(val: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;ExtendedValue, <span class="kw">crate</span>::error::ParseError&gt; {
<span class="comment">// Break into three pieces separated by the single-quote character
</span><span class="kw">let </span><span class="kw-2">mut </span>parts = val.splitn(<span class="number">3</span>, <span class="string">'\''</span>);
<span class="comment">// Interpret the first piece as a Charset
</span><span class="kw">let </span>charset: Charset = <span class="kw">match </span>parts.next() {
<span class="prelude-val">None </span>=&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="kw">crate</span>::error::ParseError::Header),
<span class="prelude-val">Some</span>(n) =&gt; FromStr::from_str(n).map_err(|<span class="kw">_</span>| <span class="kw">crate</span>::error::ParseError::Header)<span class="question-mark">?</span>,
};
<span class="comment">// Interpret the second piece as a language tag
</span><span class="kw">let </span>language_tag: <span class="prelude-ty">Option</span>&lt;LanguageTag&gt; = <span class="kw">match </span>parts.next() {
<span class="prelude-val">None </span>=&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="kw">crate</span>::error::ParseError::Header),
<span class="prelude-val">Some</span>(<span class="string">""</span>) =&gt; <span class="prelude-val">None</span>,
<span class="prelude-val">Some</span>(s) =&gt; <span class="kw">match </span>s.parse() {
<span class="prelude-val">Ok</span>(lt) =&gt; <span class="prelude-val">Some</span>(lt),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="kw">crate</span>::error::ParseError::Header),
},
};
<span class="comment">// Interpret the third piece as a sequence of value characters
</span><span class="kw">let </span>value: Vec&lt;u8&gt; = <span class="kw">match </span>parts.next() {
<span class="prelude-val">None </span>=&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="kw">crate</span>::error::ParseError::Header),
<span class="prelude-val">Some</span>(v) =&gt; percent_encoding::percent_decode(v.as_bytes()).collect(),
};
<span class="prelude-val">Ok</span>(ExtendedValue {
charset,
language_tag,
value,
})
}
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>ExtendedValue {
<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">'_</span>&gt;) -&gt; fmt::Result {
<span class="kw">let </span>encoded_value = percent_encoding::percent_encode(<span class="kw-2">&amp;</span><span class="self">self</span>.value[..], HTTP_VALUE);
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>lang) = <span class="self">self</span>.language_tag {
<span class="macro">write!</span>(f, <span class="string">"{}'{}'{}"</span>, <span class="self">self</span>.charset, lang, encoded_value)
} <span class="kw">else </span>{
<span class="macro">write!</span>(f, <span class="string">"{}''{}"</span>, <span class="self">self</span>.charset, encoded_value)
}
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_extended_value_with_encoding_and_language_tag() {
<span class="kw">let </span>expected_language_tag = <span class="string">"en"</span>.parse::&lt;LanguageTag&gt;().unwrap();
<span class="comment">// RFC 5987, Section 3.2.2
// Extended notation, using the Unicode character U+00A3 (POUND SIGN)
</span><span class="kw">let </span>result = parse_extended_value(<span class="string">"iso-8859-1'en'%A3%20rates"</span>);
<span class="macro">assert!</span>(result.is_ok());
<span class="kw">let </span>extended_value = result.unwrap();
<span class="macro">assert_eq!</span>(Charset::Iso_8859_1, extended_value.charset);
<span class="macro">assert!</span>(extended_value.language_tag.is_some());
<span class="macro">assert_eq!</span>(expected_language_tag, extended_value.language_tag.unwrap());
<span class="macro">assert_eq!</span>(
<span class="macro">vec!</span>[<span class="number">163</span>, <span class="string">b' '</span>, <span class="string">b'r'</span>, <span class="string">b'a'</span>, <span class="string">b't'</span>, <span class="string">b'e'</span>, <span class="string">b's'</span>],
extended_value.value
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_extended_value_with_encoding() {
<span class="comment">// RFC 5987, Section 3.2.2
// Extended notation, using the Unicode characters U+00A3 (POUND SIGN)
// and U+20AC (EURO SIGN)
</span><span class="kw">let </span>result = parse_extended_value(<span class="string">"UTF-8''%c2%a3%20and%20%e2%82%ac%20rates"</span>);
<span class="macro">assert!</span>(result.is_ok());
<span class="kw">let </span>extended_value = result.unwrap();
<span class="macro">assert_eq!</span>(Charset::Ext(<span class="string">"UTF-8"</span>.to_string()), extended_value.charset);
<span class="macro">assert!</span>(extended_value.language_tag.is_none());
<span class="macro">assert_eq!</span>(
<span class="macro">vec!</span>[
<span class="number">194</span>, <span class="number">163</span>, <span class="string">b' '</span>, <span class="string">b'a'</span>, <span class="string">b'n'</span>, <span class="string">b'd'</span>, <span class="string">b' '</span>, <span class="number">226</span>, <span class="number">130</span>, <span class="number">172</span>, <span class="string">b' '</span>, <span class="string">b'r'</span>, <span class="string">b'a'</span>, <span class="string">b't'</span>,
<span class="string">b'e'</span>, <span class="string">b's'</span>,
],
extended_value.value
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_extended_value_missing_language_tag_and_encoding() {
<span class="comment">// From: https://greenbytes.de/tech/tc2231/#attwithfn2231quot2
</span><span class="kw">let </span>result = parse_extended_value(<span class="string">"foo%20bar.html"</span>);
<span class="macro">assert!</span>(result.is_err());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_extended_value_partially_formatted() {
<span class="kw">let </span>result = parse_extended_value(<span class="string">"UTF-8'missing third part"</span>);
<span class="macro">assert!</span>(result.is_err());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_extended_value_partially_formatted_blank() {
<span class="kw">let </span>result = parse_extended_value(<span class="string">"blank second part'"</span>);
<span class="macro">assert!</span>(result.is_err());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_fmt_extended_value_with_encoding_and_language_tag() {
<span class="kw">let </span>extended_value = ExtendedValue {
charset: Charset::Iso_8859_1,
language_tag: <span class="prelude-val">Some</span>(<span class="string">"en"</span>.parse().expect(<span class="string">"Could not parse language tag"</span>)),
value: <span class="macro">vec!</span>[<span class="number">163</span>, <span class="string">b' '</span>, <span class="string">b'r'</span>, <span class="string">b'a'</span>, <span class="string">b't'</span>, <span class="string">b'e'</span>, <span class="string">b's'</span>],
};
<span class="macro">assert_eq!</span>(<span class="string">"ISO-8859-1'en'%A3%20rates"</span>, <span class="macro">format!</span>(<span class="string">"{}"</span>, extended_value));
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_fmt_extended_value_with_encoding() {
<span class="kw">let </span>extended_value = ExtendedValue {
charset: Charset::Ext(<span class="string">"UTF-8"</span>.to_string()),
language_tag: <span class="prelude-val">None</span>,
value: <span class="macro">vec!</span>[
<span class="number">194</span>, <span class="number">163</span>, <span class="string">b' '</span>, <span class="string">b'a'</span>, <span class="string">b'n'</span>, <span class="string">b'd'</span>, <span class="string">b' '</span>, <span class="number">226</span>, <span class="number">130</span>, <span class="number">172</span>, <span class="string">b' '</span>, <span class="string">b'r'</span>, <span class="string">b'a'</span>, <span class="string">b't'</span>,
<span class="string">b'e'</span>, <span class="string">b's'</span>,
],
};
<span class="macro">assert_eq!</span>(
<span class="string">"UTF-8''%C2%A3%20and%20%E2%82%AC%20rates"</span>,
<span class="macro">format!</span>(<span class="string">"{}"</span>, extended_value)
);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,161 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/shared/http_date.rs`."><title>http_date.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{fmt, io::Write, str::FromStr, time::SystemTime};
<span class="kw">use </span>bytes::BytesMut;
<span class="kw">use </span>http::header::{HeaderValue, InvalidHeaderValue};
<span class="kw">use crate</span>::{
date::DATE_VALUE_LENGTH, error::ParseError, header::TryIntoHeaderValue, helpers::MutWriter,
};
<span class="doccomment">/// A timestamp with HTTP-style formatting and parsing.
</span><span class="attr">#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
</span><span class="kw">pub struct </span>HttpDate(SystemTime);
<span class="kw">impl </span>FromStr <span class="kw">for </span>HttpDate {
<span class="kw">type </span><span class="prelude-val">Err </span>= ParseError;
<span class="kw">fn </span>from_str(s: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;HttpDate, ParseError&gt; {
<span class="kw">match </span>httpdate::parse_http_date(s) {
<span class="prelude-val">Ok</span>(sys_time) =&gt; <span class="prelude-val">Ok</span>(HttpDate(sys_time)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(ParseError::Header),
}
}
}
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>HttpDate {
<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">'_</span>&gt;) -&gt; fmt::Result {
httpdate::HttpDate::from(<span class="self">self</span>.<span class="number">0</span>).fmt(f)
}
}
<span class="kw">impl </span>TryIntoHeaderValue <span class="kw">for </span>HttpDate {
<span class="kw">type </span>Error = InvalidHeaderValue;
<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>buf = BytesMut::with_capacity(DATE_VALUE_LENGTH);
<span class="kw">let </span><span class="kw-2">mut </span>wrt = MutWriter(<span class="kw-2">&amp;mut </span>buf);
<span class="comment">// unwrap: date output is known to be well formed and of known length
</span><span class="macro">write!</span>(wrt, <span class="string">"{}"</span>, <span class="self">self</span>).unwrap();
HeaderValue::from_maybe_shared(buf.split().freeze())
}
}
<span class="kw">impl </span>From&lt;SystemTime&gt; <span class="kw">for </span>HttpDate {
<span class="kw">fn </span>from(sys_time: SystemTime) -&gt; HttpDate {
HttpDate(sys_time)
}
}
<span class="kw">impl </span>From&lt;HttpDate&gt; <span class="kw">for </span>SystemTime {
<span class="kw">fn </span>from(HttpDate(sys_time): HttpDate) -&gt; SystemTime {
sys_time
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::time::Duration;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>date_header() {
<span class="macro">macro_rules!</span> assert_parsed_date {
(<span class="macro-nonterminal">$case</span>:expr, <span class="macro-nonterminal">$exp</span>:expr) =&gt; {
<span class="macro">assert_eq!</span>(<span class="macro-nonterminal">$case</span>.parse::&lt;HttpDate&gt;().unwrap(), <span class="macro-nonterminal">$exp</span>);
};
}
<span class="comment">// 784198117 = SystemTime::from(datetime!(1994-11-07 08:48:37).assume_utc()).duration_since(SystemTime::UNIX_EPOCH));
</span><span class="kw">let </span>nov_07 = HttpDate(SystemTime::UNIX_EPOCH + Duration::from_secs(<span class="number">784198117</span>));
<span class="macro">assert_parsed_date!</span>(<span class="string">"Mon, 07 Nov 1994 08:48:37 GMT"</span>, nov_07);
<span class="macro">assert_parsed_date!</span>(<span class="string">"Monday, 07-Nov-94 08:48:37 GMT"</span>, nov_07);
<span class="macro">assert_parsed_date!</span>(<span class="string">"Mon Nov 7 08:48:37 1994"</span>, nov_07);
<span class="macro">assert!</span>(<span class="string">"this-is-no-date"</span>.parse::&lt;HttpDate&gt;().is_err());
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,39 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/shared/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Originally taken from `hyper::header::shared`.
</span><span class="kw">pub use </span>language_tags::LanguageTag;
<span class="kw">mod </span>charset;
<span class="kw">mod </span>content_encoding;
<span class="kw">mod </span>extended;
<span class="kw">mod </span>http_date;
<span class="kw">mod </span>quality;
<span class="kw">mod </span>quality_item;
<span class="kw">pub use </span><span class="self">self</span>::{
charset::Charset,
content_encoding::ContentEncoding,
extended::{parse_extended_value, ExtendedValue},
http_date::HttpDate,
quality::{q, Quality},
quality_item::QualityItem,
};
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,445 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/shared/quality.rs`."><title>quality.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::fmt;
<span class="kw">use </span>derive_more::{Display, Error};
<span class="kw">const </span>MAX_QUALITY_INT: u16 = <span class="number">1000</span>;
<span class="kw">const </span>MAX_QUALITY_FLOAT: f32 = <span class="number">1.0</span>;
<span class="doccomment">/// Represents a quality used in q-factor values.
///
/// The default value is equivalent to `q=1.0` (the [max](Self::MAX) value).
///
/// # Implementation notes
/// The quality value is defined as a number between 0.0 and 1.0 with three decimal places.
/// This means there are 1001 possible values. Since floating point numbers are not exact and the
/// smallest floating point data type (`f32`) consumes four bytes, we use an `u16` value to store
/// the quality internally.
///
/// [RFC 7231 §5.3.1] gives more information on quality values in HTTP header fields.
///
/// # Examples
/// ```
/// use actix_http::header::{Quality, q};
/// assert_eq!(q(1.0), Quality::MAX);
///
/// assert_eq!(q(0.42).to_string(), "0.42");
/// assert_eq!(q(1.0).to_string(), "1");
/// assert_eq!(Quality::MIN.to_string(), "0.001");
/// assert_eq!(Quality::ZERO.to_string(), "0");
/// ```
///
/// [RFC 7231 §5.3.1]: https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1
</span><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
</span><span class="kw">pub struct </span>Quality(<span class="kw">pub</span>(<span class="kw">super</span>) u16);
<span class="kw">impl </span>Quality {
<span class="doccomment">/// The maximum quality value, equivalent to `q=1.0`.
</span><span class="kw">pub const </span>MAX: Quality = Quality(MAX_QUALITY_INT);
<span class="doccomment">/// The minimum, non-zero quality value, equivalent to `q=0.001`.
</span><span class="kw">pub const </span>MIN: Quality = Quality(<span class="number">1</span>);
<span class="doccomment">/// The zero quality value, equivalent to `q=0.0`.
</span><span class="kw">pub const </span>ZERO: Quality = Quality(<span class="number">0</span>);
<span class="doccomment">/// Converts a float in the range 0.01.0 to a `Quality`.
///
/// Intentionally private. External uses should rely on the `TryFrom` impl.
///
/// # Panics
/// Panics in debug mode when value is not in the range 0.0 &lt;= n &lt;= 1.0.
</span><span class="kw">fn </span>from_f32(value: f32) -&gt; <span class="self">Self </span>{
<span class="comment">// Check that `value` is within range should be done before calling this method.
// Just in case, this debug_assert should catch if we were forgetful.
</span><span class="macro">debug_assert!</span>(
(<span class="number">0.0</span>..=MAX_QUALITY_FLOAT).contains(<span class="kw-2">&amp;</span>value),
<span class="string">"q value must be between 0.0 and 1.0"
</span>);
Quality((value * MAX_QUALITY_INT <span class="kw">as </span>f32) <span class="kw">as </span>u16)
}
}
<span class="doccomment">/// The default value is [`Quality::MAX`].
</span><span class="kw">impl </span>Default <span class="kw">for </span>Quality {
<span class="kw">fn </span>default() -&gt; Quality {
Quality::MAX
}
}
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>Quality {
<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">'_</span>&gt;) -&gt; fmt::Result {
<span class="kw">match </span><span class="self">self</span>.<span class="number">0 </span>{
<span class="number">0 </span>=&gt; f.write_str(<span class="string">"0"</span>),
MAX_QUALITY_INT =&gt; f.write_str(<span class="string">"1"</span>),
<span class="comment">// some number in the range 1999
</span>x =&gt; {
f.write_str(<span class="string">"0."</span>)<span class="question-mark">?</span>;
<span class="comment">// This implementation avoids string allocation for removing trailing zeroes.
// In benchmarks it is twice as fast as approach using something like
// `format!("{}").trim_end_matches('0')` for non-fast-path quality values.
</span><span class="kw">if </span>x &lt; <span class="number">10 </span>{
<span class="comment">// x in is range 19
</span>f.write_str(<span class="string">"00"</span>)<span class="question-mark">?</span>;
<span class="comment">// 0 is already handled so it's not possible to have a trailing 0 in this range
// we can just write the integer
</span>itoa_fmt(f, x)
} <span class="kw">else if </span>x &lt; <span class="number">100 </span>{
<span class="comment">// x in is range 1099
</span>f.write_str(<span class="string">"0"</span>)<span class="question-mark">?</span>;
<span class="kw">if </span>x % <span class="number">10 </span>== <span class="number">0 </span>{
<span class="comment">// trailing 0, divide by 10 and write
</span>itoa_fmt(f, x / <span class="number">10</span>)
} <span class="kw">else </span>{
itoa_fmt(f, x)
}
} <span class="kw">else </span>{
<span class="comment">// x is in range 100999
</span><span class="kw">if </span>x % <span class="number">100 </span>== <span class="number">0 </span>{
<span class="comment">// two trailing 0s, divide by 100 and write
</span>itoa_fmt(f, x / <span class="number">100</span>)
} <span class="kw">else if </span>x % <span class="number">10 </span>== <span class="number">0 </span>{
<span class="comment">// one trailing 0, divide by 10 and write
</span>itoa_fmt(f, x / <span class="number">10</span>)
} <span class="kw">else </span>{
itoa_fmt(f, x)
}
}
}
}
}
}
<span class="doccomment">/// Write integer to a `fmt::Write`.
</span><span class="kw">pub fn </span>itoa_fmt&lt;W: fmt::Write, V: itoa::Integer&gt;(<span class="kw-2">mut </span>wr: W, value: V) -&gt; fmt::Result {
<span class="kw">let </span><span class="kw-2">mut </span>buf = itoa::Buffer::new();
wr.write_str(buf.format(value))
}
<span class="attr">#[derive(Debug, Clone, Display, Error)]
#[display(fmt = <span class="string">"quality out of bounds"</span>)]
#[non_exhaustive]
</span><span class="kw">pub struct </span>QualityOutOfBounds;
<span class="kw">impl </span>TryFrom&lt;f32&gt; <span class="kw">for </span>Quality {
<span class="kw">type </span>Error = QualityOutOfBounds;
<span class="attr">#[inline]
</span><span class="kw">fn </span>try_from(value: f32) -&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>(<span class="number">0.0</span>..=MAX_QUALITY_FLOAT).contains(<span class="kw-2">&amp;</span>value) {
<span class="prelude-val">Ok</span>(Quality::from_f32(value))
} <span class="kw">else </span>{
<span class="prelude-val">Err</span>(QualityOutOfBounds)
}
}
}
<span class="doccomment">/// Convenience function to create a [`Quality`] from an `f32` (0.01.0).
///
/// Not recommended for use with user input. Rely on the `TryFrom` impls where possible.
///
/// # Panics
/// Panics if value is out of range.
///
/// # Examples
/// ```
/// # use actix_http::header::{q, Quality};
/// let q1 = q(1.0);
/// assert_eq!(q1, Quality::MAX);
///
/// let q2 = q(0.001);
/// assert_eq!(q2, Quality::MIN);
///
/// let q3 = q(0.0);
/// assert_eq!(q3, Quality::ZERO);
///
/// let q4 = q(0.42);
/// ```
///
/// An out-of-range `f32` quality will panic.
/// ```should_panic
/// # use actix_http::header::q;
/// let _q2 = q(1.42);
/// ```
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>q&lt;T&gt;(quality: T) -&gt; Quality
<span class="kw">where
</span>T: TryInto&lt;Quality&gt;,
T::Error: fmt::Debug,
{
quality.try_into().expect(<span class="string">"quality value was out of bounds"</span>)
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>q_helper() {
<span class="macro">assert_eq!</span>(q(<span class="number">0.5</span>), Quality(<span class="number">500</span>));
}
<span class="attr">#[test]
</span><span class="kw">fn </span>display_output() {
<span class="macro">assert_eq!</span>(Quality::ZERO.to_string(), <span class="string">"0"</span>);
<span class="macro">assert_eq!</span>(Quality::MIN.to_string(), <span class="string">"0.001"</span>);
<span class="macro">assert_eq!</span>(Quality::MAX.to_string(), <span class="string">"1"</span>);
<span class="macro">assert_eq!</span>(q(<span class="number">0.0</span>).to_string(), <span class="string">"0"</span>);
<span class="macro">assert_eq!</span>(q(<span class="number">1.0</span>).to_string(), <span class="string">"1"</span>);
<span class="macro">assert_eq!</span>(q(<span class="number">0.001</span>).to_string(), <span class="string">"0.001"</span>);
<span class="macro">assert_eq!</span>(q(<span class="number">0.5</span>).to_string(), <span class="string">"0.5"</span>);
<span class="macro">assert_eq!</span>(q(<span class="number">0.22</span>).to_string(), <span class="string">"0.22"</span>);
<span class="macro">assert_eq!</span>(q(<span class="number">0.123</span>).to_string(), <span class="string">"0.123"</span>);
<span class="macro">assert_eq!</span>(q(<span class="number">0.999</span>).to_string(), <span class="string">"0.999"</span>);
<span class="kw">for </span>x <span class="kw">in </span><span class="number">0</span>..=<span class="number">1000 </span>{
<span class="comment">// if trailing zeroes are handled correctly, we would not expect the serialized length
// to ever exceed "0." + 3 decimal places = 5 in length
</span><span class="macro">assert!</span>(q(x <span class="kw">as </span>f32 / <span class="number">1000.0</span>).to_string().len() &lt;= <span class="number">5</span>);
}
}
<span class="attr">#[test]
#[should_panic]
</span><span class="kw">fn </span>negative_quality() {
q(-<span class="number">1.0</span>);
}
<span class="attr">#[test]
#[should_panic]
</span><span class="kw">fn </span>quality_out_of_bounds() {
q(<span class="number">2.0</span>);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,611 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/shared/quality_item.rs`."><title>quality_item.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{cmp, fmt, str};
<span class="kw">use </span><span class="kw">super</span>::Quality;
<span class="kw">use </span><span class="kw">crate</span>::error::ParseError;
<span class="doccomment">/// Represents an item with a quality value as defined
/// in [RFC 7231 §5.3.1](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1).
///
/// # Parsing and Formatting
/// This wrapper be used to parse header value items that have a q-factor annotation as well as
/// serialize items with a their q-factor.
///
/// # Ordering
/// Since this context of use for this type is header value items, ordering is defined for
/// `QualityItem`s but _only_ considers the item's quality. Order of appearance should be used as
/// the secondary sorting parameter; i.e., a stable sort over the quality values will produce a
/// correctly sorted sequence.
///
/// # Examples
/// ```
/// # use actix_http::header::{QualityItem, q};
/// let q_item: QualityItem&lt;String&gt; = "hello;q=0.3".parse().unwrap();
/// assert_eq!(&amp;q_item.item, "hello");
/// assert_eq!(q_item.quality, q(0.3));
///
/// // note that format is normalized compared to parsed item
/// assert_eq!(q_item.to_string(), "hello; q=0.3");
///
/// // item with q=0.3 is greater than item with q=0.1
/// let q_item_fallback: QualityItem&lt;String&gt; = "abc;q=0.1".parse().unwrap();
/// assert!(q_item &gt; q_item_fallback);
/// ```
</span><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq)]
</span><span class="kw">pub struct </span>QualityItem&lt;T&gt; {
<span class="doccomment">/// The wrapped contents of the field.
</span><span class="kw">pub </span>item: T,
<span class="doccomment">/// The quality (client or server preference) for the value.
</span><span class="kw">pub </span>quality: Quality,
}
<span class="kw">impl</span>&lt;T&gt; QualityItem&lt;T&gt; {
<span class="doccomment">/// Constructs a new `QualityItem` from an item and a quality value.
///
/// The item can be of any type. The quality should be a value in the range [0, 1].
</span><span class="kw">pub fn </span>new(item: T, quality: Quality) -&gt; <span class="self">Self </span>{
QualityItem { item, quality }
}
<span class="doccomment">/// Constructs a new `QualityItem` from an item, using the maximum q-value.
</span><span class="kw">pub fn </span>max(item: T) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(item, Quality::MAX)
}
<span class="doccomment">/// Constructs a new `QualityItem` from an item, using the minimum, non-zero q-value.
</span><span class="kw">pub fn </span>min(item: T) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(item, Quality::MIN)
}
<span class="doccomment">/// Constructs a new `QualityItem` from an item, using zero q-value of zero.
</span><span class="kw">pub fn </span>zero(item: T) -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(item, Quality::ZERO)
}
}
<span class="kw">impl</span>&lt;T: PartialEq&gt; PartialOrd <span class="kw">for </span>QualityItem&lt;T&gt; {
<span class="kw">fn </span>partial_cmp(<span class="kw-2">&amp;</span><span class="self">self</span>, other: <span class="kw-2">&amp;</span>QualityItem&lt;T&gt;) -&gt; <span class="prelude-ty">Option</span>&lt;cmp::Ordering&gt; {
<span class="self">self</span>.quality.partial_cmp(<span class="kw-2">&amp;</span>other.quality)
}
}
<span class="kw">impl</span>&lt;T: fmt::Display&gt; fmt::Display <span class="kw">for </span>QualityItem&lt;T&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">'_</span>&gt;) -&gt; fmt::Result {
fmt::Display::fmt(<span class="kw-2">&amp;</span><span class="self">self</span>.item, f)<span class="question-mark">?</span>;
<span class="kw">match </span><span class="self">self</span>.quality {
<span class="comment">// q-factor value is implied for max value
</span>Quality::MAX =&gt; <span class="prelude-val">Ok</span>(()),
<span class="comment">// fast path for zero
</span>Quality::ZERO =&gt; f.write_str(<span class="string">"; q=0"</span>),
<span class="comment">// quality formatting is already using itoa
</span>q =&gt; <span class="macro">write!</span>(f, <span class="string">"; q={}"</span>, q),
}
}
}
<span class="kw">impl</span>&lt;T: str::FromStr&gt; str::FromStr <span class="kw">for </span>QualityItem&lt;T&gt; {
<span class="kw">type </span><span class="prelude-val">Err </span>= ParseError;
<span class="kw">fn </span>from_str(q_item_str: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, <span class="self">Self</span>::Err&gt; {
<span class="kw">if </span>!q_item_str.is_ascii() {
<span class="kw">return </span><span class="prelude-val">Err</span>(ParseError::Header);
}
<span class="comment">// set defaults used if quality-item parsing fails, i.e., item has no q attribute
</span><span class="kw">let </span><span class="kw-2">mut </span>raw_item = q_item_str;
<span class="kw">let </span><span class="kw-2">mut </span>quality = Quality::MAX;
<span class="kw">let </span>parts = q_item_str
.rsplit_once(<span class="string">';'</span>)
.map(|(item, q_attr)| (item.trim(), q_attr.trim()));
<span class="kw">if let </span><span class="prelude-val">Some</span>((val, q_attr)) = parts {
<span class="comment">// example for item with q-factor:
//
// gzip;q=0.65
// ^^^^ val
// ^^^^^^ q_attr
// ^^ q
// ^^^^ q_val
</span><span class="kw">if </span>q_attr.len() &lt; <span class="number">2 </span>{
<span class="comment">// Can't possibly be an attribute since an attribute needs at least a name followed
// by an equals sign. And bare identifiers are forbidden.
</span><span class="kw">return </span><span class="prelude-val">Err</span>(ParseError::Header);
}
<span class="kw">let </span>q = <span class="kw-2">&amp;</span>q_attr[<span class="number">0</span>..<span class="number">2</span>];
<span class="kw">if </span>q == <span class="string">"q=" </span>|| q == <span class="string">"Q=" </span>{
<span class="kw">let </span>q_val = <span class="kw-2">&amp;</span>q_attr[<span class="number">2</span>..];
<span class="kw">if </span>q_val.len() &gt; <span class="number">5 </span>{
<span class="comment">// longer than 5 indicates an over-precise q-factor
</span><span class="kw">return </span><span class="prelude-val">Err</span>(ParseError::Header);
}
<span class="kw">let </span>q_value = q_val.parse::&lt;f32&gt;().map_err(|<span class="kw">_</span>| ParseError::Header)<span class="question-mark">?</span>;
<span class="kw">let </span>q_value = Quality::try_from(q_value).map_err(|<span class="kw">_</span>| ParseError::Header)<span class="question-mark">?</span>;
quality = q_value;
raw_item = val;
}
}
<span class="kw">let </span>item = raw_item.parse::&lt;T&gt;().map_err(|<span class="kw">_</span>| ParseError::Header)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(QualityItem::new(item, quality))
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="comment">// copy of encoding from actix-web headers
</span><span class="attr">#[allow(clippy::enum_variant_names)] </span><span class="comment">// allow Encoding prefix on EncodingExt
</span><span class="attr">#[derive(Debug, Clone, PartialEq, Eq)]
</span><span class="kw">pub enum </span>Encoding {
Chunked,
Brotli,
Gzip,
Deflate,
Compress,
Identity,
Trailers,
EncodingExt(String),
}
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>Encoding {
<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">'_</span>&gt;) -&gt; fmt::Result {
<span class="kw">use </span>Encoding::<span class="kw-2">*</span>;
f.write_str(<span class="kw">match </span><span class="kw-2">*</span><span class="self">self </span>{
Chunked =&gt; <span class="string">"chunked"</span>,
Brotli =&gt; <span class="string">"br"</span>,
Gzip =&gt; <span class="string">"gzip"</span>,
Deflate =&gt; <span class="string">"deflate"</span>,
Compress =&gt; <span class="string">"compress"</span>,
Identity =&gt; <span class="string">"identity"</span>,
Trailers =&gt; <span class="string">"trailers"</span>,
EncodingExt(<span class="kw-2">ref </span>s) =&gt; s.as_ref(),
})
}
}
<span class="kw">impl </span>str::FromStr <span class="kw">for </span>Encoding {
<span class="kw">type </span><span class="prelude-val">Err </span>= <span class="kw">crate</span>::error::ParseError;
<span class="kw">fn </span>from_str(s: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;Encoding, <span class="kw">crate</span>::error::ParseError&gt; {
<span class="kw">use </span>Encoding::<span class="kw-2">*</span>;
<span class="kw">match </span>s {
<span class="string">"chunked" </span>=&gt; <span class="prelude-val">Ok</span>(Chunked),
<span class="string">"br" </span>=&gt; <span class="prelude-val">Ok</span>(Brotli),
<span class="string">"deflate" </span>=&gt; <span class="prelude-val">Ok</span>(Deflate),
<span class="string">"gzip" </span>=&gt; <span class="prelude-val">Ok</span>(Gzip),
<span class="string">"compress" </span>=&gt; <span class="prelude-val">Ok</span>(Compress),
<span class="string">"identity" </span>=&gt; <span class="prelude-val">Ok</span>(Identity),
<span class="string">"trailers" </span>=&gt; <span class="prelude-val">Ok</span>(Trailers),
<span class="kw">_ </span>=&gt; <span class="prelude-val">Ok</span>(EncodingExt(s.to_owned())),
}
}
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_quality_item_fmt_q_1() {
<span class="kw">use </span>Encoding::<span class="kw-2">*</span>;
<span class="kw">let </span>x = QualityItem::max(Chunked);
<span class="macro">assert_eq!</span>(<span class="macro">format!</span>(<span class="string">"{}"</span>, x), <span class="string">"chunked"</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_quality_item_fmt_q_0001() {
<span class="kw">use </span>Encoding::<span class="kw-2">*</span>;
<span class="kw">let </span>x = QualityItem::new(Chunked, Quality(<span class="number">1</span>));
<span class="macro">assert_eq!</span>(<span class="macro">format!</span>(<span class="string">"{}"</span>, x), <span class="string">"chunked; q=0.001"</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_quality_item_fmt_q_05() {
<span class="kw">use </span>Encoding::<span class="kw-2">*</span>;
<span class="comment">// Custom value
</span><span class="kw">let </span>x = QualityItem {
item: EncodingExt(<span class="string">"identity"</span>.to_owned()),
quality: Quality(<span class="number">500</span>),
};
<span class="macro">assert_eq!</span>(<span class="macro">format!</span>(<span class="string">"{}"</span>, x), <span class="string">"identity; q=0.5"</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_quality_item_fmt_q_0() {
<span class="kw">use </span>Encoding::<span class="kw-2">*</span>;
<span class="comment">// Custom value
</span><span class="kw">let </span>x = QualityItem {
item: EncodingExt(<span class="string">"identity"</span>.to_owned()),
quality: Quality(<span class="number">0</span>),
};
<span class="macro">assert_eq!</span>(x.to_string(), <span class="string">"identity; q=0"</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_quality_item_from_str1() {
<span class="kw">use </span>Encoding::<span class="kw-2">*</span>;
<span class="kw">let </span>x: <span class="prelude-ty">Result</span>&lt;QualityItem&lt;Encoding&gt;, <span class="kw">_</span>&gt; = <span class="string">"chunked"</span>.parse();
<span class="macro">assert_eq!</span>(
x.unwrap(),
QualityItem {
item: Chunked,
quality: Quality(<span class="number">1000</span>),
}
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_quality_item_from_str2() {
<span class="kw">use </span>Encoding::<span class="kw-2">*</span>;
<span class="kw">let </span>x: <span class="prelude-ty">Result</span>&lt;QualityItem&lt;Encoding&gt;, <span class="kw">_</span>&gt; = <span class="string">"chunked; q=1"</span>.parse();
<span class="macro">assert_eq!</span>(
x.unwrap(),
QualityItem {
item: Chunked,
quality: Quality(<span class="number">1000</span>),
}
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_quality_item_from_str3() {
<span class="kw">use </span>Encoding::<span class="kw-2">*</span>;
<span class="kw">let </span>x: <span class="prelude-ty">Result</span>&lt;QualityItem&lt;Encoding&gt;, <span class="kw">_</span>&gt; = <span class="string">"gzip; q=0.5"</span>.parse();
<span class="macro">assert_eq!</span>(
x.unwrap(),
QualityItem {
item: Gzip,
quality: Quality(<span class="number">500</span>),
}
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_quality_item_from_str4() {
<span class="kw">use </span>Encoding::<span class="kw-2">*</span>;
<span class="kw">let </span>x: <span class="prelude-ty">Result</span>&lt;QualityItem&lt;Encoding&gt;, <span class="kw">_</span>&gt; = <span class="string">"gzip; q=0.273"</span>.parse();
<span class="macro">assert_eq!</span>(
x.unwrap(),
QualityItem {
item: Gzip,
quality: Quality(<span class="number">273</span>),
}
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_quality_item_from_str5() {
<span class="kw">let </span>x: <span class="prelude-ty">Result</span>&lt;QualityItem&lt;Encoding&gt;, <span class="kw">_</span>&gt; = <span class="string">"gzip; q=0.2739999"</span>.parse();
<span class="macro">assert!</span>(x.is_err());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_quality_item_from_str6() {
<span class="kw">let </span>x: <span class="prelude-ty">Result</span>&lt;QualityItem&lt;Encoding&gt;, <span class="kw">_</span>&gt; = <span class="string">"gzip; q=2"</span>.parse();
<span class="macro">assert!</span>(x.is_err());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_quality_item_ordering() {
<span class="kw">let </span>x: QualityItem&lt;Encoding&gt; = <span class="string">"gzip; q=0.5"</span>.parse().ok().unwrap();
<span class="kw">let </span>y: QualityItem&lt;Encoding&gt; = <span class="string">"gzip; q=0.273"</span>.parse().ok().unwrap();
<span class="kw">let </span>comparison_result: bool = x.gt(<span class="kw-2">&amp;</span>y);
<span class="macro">assert!</span>(comparison_result)
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_fuzzing_bugs() {
<span class="macro">assert!</span>(<span class="string">"99999;"</span>.parse::&lt;QualityItem&lt;String&gt;&gt;().is_err());
<span class="macro">assert!</span>(<span class="string">"\x0d;;;=\u{d6aa}=="</span>.parse::&lt;QualityItem&lt;String&gt;&gt;().is_err())
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,209 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/header/utils.rs`."><title>utils.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Header parsing utilities.
</span><span class="kw">use </span>std::{fmt, str::FromStr};
<span class="kw">use </span><span class="kw">super</span>::HeaderValue;
<span class="kw">use crate</span>::{error::ParseError, header::HTTP_VALUE};
<span class="doccomment">/// Reads a comma-delimited raw header into a Vec.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>from_comma_delimited&lt;<span class="lifetime">'a</span>, I, T&gt;(all: I) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;T&gt;, ParseError&gt;
<span class="kw">where
</span>I: Iterator&lt;Item = <span class="kw-2">&amp;</span><span class="lifetime">'a </span>HeaderValue&gt; + <span class="lifetime">'a</span>,
T: FromStr,
{
<span class="kw">let </span>size_guess = all.size_hint().<span class="number">1</span>.unwrap_or(<span class="number">2</span>);
<span class="kw">let </span><span class="kw-2">mut </span>result = Vec::with_capacity(size_guess);
<span class="kw">for </span>h <span class="kw">in </span>all {
<span class="kw">let </span>s = h.to_str().map_err(|<span class="kw">_</span>| ParseError::Header)<span class="question-mark">?</span>;
result.extend(
s.split(<span class="string">','</span>)
.filter_map(|x| <span class="kw">match </span>x.trim() {
<span class="string">"" </span>=&gt; <span class="prelude-val">None</span>,
y =&gt; <span class="prelude-val">Some</span>(y),
})
.filter_map(|x| x.trim().parse().ok()),
)
}
<span class="prelude-val">Ok</span>(result)
}
<span class="doccomment">/// Reads a single string when parsing a header.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>from_one_raw_str&lt;T: FromStr&gt;(val: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>HeaderValue&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;T, ParseError&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(line) = val {
<span class="kw">let </span>line = line.to_str().map_err(|<span class="kw">_</span>| ParseError::Header)<span class="question-mark">?</span>;
<span class="kw">if </span>!line.is_empty() {
<span class="kw">return </span>T::from_str(line).or(<span class="prelude-val">Err</span>(ParseError::Header));
}
}
<span class="prelude-val">Err</span>(ParseError::Header)
}
<span class="doccomment">/// Format an array into a comma-delimited string.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>fmt_comma_delimited&lt;T&gt;(f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;, parts: <span class="kw-2">&amp;</span>[T]) -&gt; fmt::Result
<span class="kw">where
</span>T: fmt::Display,
{
<span class="kw">let </span><span class="kw-2">mut </span>iter = parts.iter();
<span class="kw">if let </span><span class="prelude-val">Some</span>(part) = iter.next() {
fmt::Display::fmt(part, f)<span class="question-mark">?</span>;
}
<span class="kw">for </span>part <span class="kw">in </span>iter {
f.write_str(<span class="string">", "</span>)<span class="question-mark">?</span>;
fmt::Display::fmt(part, f)<span class="question-mark">?</span>;
}
<span class="prelude-val">Ok</span>(())
}
<span class="doccomment">/// Percent encode a sequence of bytes with a character set defined in [RFC 5987 §3.2].
///
/// [RFC 5987 §3.2]: https://datatracker.ietf.org/doc/html/rfc5987#section-3.2
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>http_percent_encode(f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;, bytes: <span class="kw-2">&amp;</span>[u8]) -&gt; fmt::Result {
<span class="kw">let </span>encoded = percent_encoding::percent_encode(bytes, HTTP_VALUE);
fmt::Display::fmt(<span class="kw-2">&amp;</span>encoded, f)
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>comma_delimited_parsing() {
<span class="kw">let </span>headers = [];
<span class="kw">let </span>res: Vec&lt;usize&gt; = from_comma_delimited(headers.iter()).unwrap();
<span class="macro">assert_eq!</span>(res, <span class="macro">vec!</span>[<span class="number">0</span>; <span class="number">0</span>]);
<span class="kw">let </span>headers = [
HeaderValue::from_static(<span class="string">"1, 2"</span>),
HeaderValue::from_static(<span class="string">"3,4"</span>),
];
<span class="kw">let </span>res: Vec&lt;usize&gt; = from_comma_delimited(headers.iter()).unwrap();
<span class="macro">assert_eq!</span>(res, <span class="macro">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]);
<span class="kw">let </span>headers = [
HeaderValue::from_static(<span class="string">""</span>),
HeaderValue::from_static(<span class="string">","</span>),
HeaderValue::from_static(<span class="string">" "</span>),
HeaderValue::from_static(<span class="string">"1 ,"</span>),
HeaderValue::from_static(<span class="string">""</span>),
];
<span class="kw">let </span>res: Vec&lt;usize&gt; = from_comma_delimited(headers.iter()).unwrap();
<span class="macro">assert_eq!</span>(res, <span class="macro">vec!</span>[<span class="number">1</span>]);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,385 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/helpers.rs`."><title>helpers.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::io;
<span class="kw">use </span>bytes::BufMut;
<span class="kw">use </span>http::Version;
<span class="kw">const </span>DIGITS_START: u8 = <span class="string">b'0'</span>;
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>write_status_line&lt;B: BufMut&gt;(version: Version, n: u16, buf: <span class="kw-2">&amp;mut </span>B) {
<span class="kw">match </span>version {
Version::HTTP_11 =&gt; buf.put_slice(<span class="string">b"HTTP/1.1 "</span>),
Version::HTTP_10 =&gt; buf.put_slice(<span class="string">b"HTTP/1.0 "</span>),
Version::HTTP_09 =&gt; buf.put_slice(<span class="string">b"HTTP/0.9 "</span>),
<span class="kw">_ </span>=&gt; {
<span class="comment">// other HTTP version handlers do not use this method
</span>}
}
<span class="kw">let </span>d100 = (n / <span class="number">100</span>) <span class="kw">as </span>u8;
<span class="kw">let </span>d10 = ((n / <span class="number">10</span>) % <span class="number">10</span>) <span class="kw">as </span>u8;
<span class="kw">let </span>d1 = (n % <span class="number">10</span>) <span class="kw">as </span>u8;
buf.put_u8(DIGITS_START + d100);
buf.put_u8(DIGITS_START + d10);
buf.put_u8(DIGITS_START + d1);
<span class="comment">// trailing space before reason
</span>buf.put_u8(<span class="string">b' '</span>);
}
<span class="doccomment">/// Write out content length header.
///
/// Buffer must to contain enough space or be implicitly extendable.
</span><span class="kw">pub fn </span>write_content_length&lt;B: BufMut&gt;(n: u64, buf: <span class="kw-2">&amp;mut </span>B, camel_case: bool) {
<span class="kw">if </span>n == <span class="number">0 </span>{
<span class="kw">if </span>camel_case {
buf.put_slice(<span class="string">b"\r\nContent-Length: 0\r\n"</span>);
} <span class="kw">else </span>{
buf.put_slice(<span class="string">b"\r\ncontent-length: 0\r\n"</span>);
}
<span class="kw">return</span>;
}
<span class="kw">let </span><span class="kw-2">mut </span>buffer = itoa::Buffer::new();
<span class="kw">if </span>camel_case {
buf.put_slice(<span class="string">b"\r\nContent-Length: "</span>);
} <span class="kw">else </span>{
buf.put_slice(<span class="string">b"\r\ncontent-length: "</span>);
}
buf.put_slice(buffer.format(n).as_bytes());
buf.put_slice(<span class="string">b"\r\n"</span>);
}
<span class="doccomment">/// An `io::Write`r that only requires mutable reference and assumes that there is space available
/// in the buffer for every write operation or that it can be extended implicitly (like
/// `bytes::BytesMut`, for example).
///
/// This is slightly faster (~10%) than `bytes::buf::Writer` in such cases because it does not
/// perform a remaining length check before writing.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>MutWriter&lt;<span class="lifetime">'a</span>, B&gt;(<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw-2">&amp;</span><span class="lifetime">'a </span><span class="kw-2">mut </span>B);
<span class="kw">impl</span>&lt;<span class="lifetime">'a</span>, B&gt; io::Write <span class="kw">for </span>MutWriter&lt;<span class="lifetime">'a</span>, B&gt;
<span class="kw">where
</span>B: BufMut,
{
<span class="kw">fn </span>write(<span class="kw-2">&amp;mut </span><span class="self">self</span>, buf: <span class="kw-2">&amp;</span>[u8]) -&gt; io::Result&lt;usize&gt; {
<span class="self">self</span>.<span class="number">0</span>.put_slice(buf);
<span class="prelude-val">Ok</span>(buf.len())
}
<span class="kw">fn </span>flush(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; io::Result&lt;()&gt; {
<span class="prelude-val">Ok</span>(())
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::str::from_utf8;
<span class="kw">use </span>bytes::BytesMut;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>test_status_line() {
<span class="kw">let </span><span class="kw-2">mut </span>bytes = BytesMut::new();
bytes.reserve(<span class="number">50</span>);
write_status_line(Version::HTTP_11, <span class="number">200</span>, <span class="kw-2">&amp;mut </span>bytes);
<span class="macro">assert_eq!</span>(from_utf8(<span class="kw-2">&amp;</span>bytes.split().freeze()).unwrap(), <span class="string">"HTTP/1.1 200 "</span>);
<span class="kw">let </span><span class="kw-2">mut </span>bytes = BytesMut::new();
bytes.reserve(<span class="number">50</span>);
write_status_line(Version::HTTP_09, <span class="number">404</span>, <span class="kw-2">&amp;mut </span>bytes);
<span class="macro">assert_eq!</span>(from_utf8(<span class="kw-2">&amp;</span>bytes.split().freeze()).unwrap(), <span class="string">"HTTP/0.9 404 "</span>);
<span class="kw">let </span><span class="kw-2">mut </span>bytes = BytesMut::new();
bytes.reserve(<span class="number">50</span>);
write_status_line(Version::HTTP_09, <span class="number">515</span>, <span class="kw-2">&amp;mut </span>bytes);
<span class="macro">assert_eq!</span>(from_utf8(<span class="kw-2">&amp;</span>bytes.split().freeze()).unwrap(), <span class="string">"HTTP/0.9 515 "</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_write_content_length() {
<span class="kw">let </span><span class="kw-2">mut </span>bytes = BytesMut::new();
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">0</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 0\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">9</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 9\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">10</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 10\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">99</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 99\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">100</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 100\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">101</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 101\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">998</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 998\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">1000</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 1000\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">1001</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 1001\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">5909</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 5909\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">9999</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 9999\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">10001</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 10001\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">59094</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 59094\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">99999</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 99999\r\n"</span>[..]);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">590947</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(
bytes.split().freeze(),
<span class="string">b"\r\ncontent-length: 590947\r\n"</span>[..]
);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">999999</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(
bytes.split().freeze(),
<span class="string">b"\r\ncontent-length: 999999\r\n"</span>[..]
);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">5909471</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(
bytes.split().freeze(),
<span class="string">b"\r\ncontent-length: 5909471\r\n"</span>[..]
);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">59094718</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(
bytes.split().freeze(),
<span class="string">b"\r\ncontent-length: 59094718\r\n"</span>[..]
);
bytes.reserve(<span class="number">50</span>);
write_content_length(<span class="number">4294973728</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(
bytes.split().freeze(),
<span class="string">b"\r\ncontent-length: 4294973728\r\n"</span>[..]
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>write_content_length_camel_case() {
<span class="kw">let </span><span class="kw-2">mut </span>bytes = BytesMut::new();
write_content_length(<span class="number">0</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\ncontent-length: 0\r\n"</span>[..]);
<span class="kw">let </span><span class="kw-2">mut </span>bytes = BytesMut::new();
write_content_length(<span class="number">0</span>, <span class="kw-2">&amp;mut </span>bytes, <span class="bool-val">true</span>);
<span class="macro">assert_eq!</span>(bytes.split().freeze(), <span class="string">b"\r\nContent-Length: 0\r\n"</span>[..]);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,459 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/http_message.rs`."><title>http_message.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
cell::{Ref, RefMut},
str,
};
<span class="kw">use </span>encoding_rs::{Encoding, UTF_8};
<span class="kw">use </span>http::header;
<span class="kw">use </span>mime::Mime;
<span class="kw">use crate</span>::{
error::{ContentTypeError, ParseError},
header::{Header, HeaderMap},
payload::Payload,
Extensions,
};
<span class="doccomment">/// Trait that implements general purpose operations on HTTP messages.
</span><span class="kw">pub trait </span>HttpMessage: Sized {
<span class="doccomment">/// Type of message payload stream
</span><span class="kw">type </span>Stream;
<span class="doccomment">/// Read the message headers.
</span><span class="kw">fn </span>headers(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>HeaderMap;
<span class="doccomment">/// Message payload stream
</span><span class="kw">fn </span>take_payload(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; Payload&lt;<span class="self">Self</span>::Stream&gt;;
<span class="doccomment">/// Returns a reference to the request-local data/extensions container.
</span><span class="kw">fn </span>extensions(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Ref&lt;<span class="lifetime">'_</span>, Extensions&gt;;
<span class="doccomment">/// Returns a mutable reference to the request-local data/extensions container.
</span><span class="kw">fn </span>extensions_mut(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; RefMut&lt;<span class="lifetime">'_</span>, Extensions&gt;;
<span class="doccomment">/// Get a header.
</span><span class="attr">#[doc(hidden)]
</span><span class="kw">fn </span>get_header&lt;H: Header&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;H&gt;
<span class="kw">where
</span><span class="self">Self</span>: Sized,
{
<span class="kw">if </span><span class="self">self</span>.headers().contains_key(H::name()) {
H::parse(<span class="self">self</span>).ok()
} <span class="kw">else </span>{
<span class="prelude-val">None
</span>}
}
<span class="doccomment">/// Read the request content type. If request did not contain a *Content-Type* header, an empty
/// string is returned.
</span><span class="kw">fn </span>content_type(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="kw">if let </span><span class="prelude-val">Some</span>(content_type) = <span class="self">self</span>.headers().get(header::CONTENT_TYPE) {
<span class="kw">if let </span><span class="prelude-val">Ok</span>(content_type) = content_type.to_str() {
<span class="kw">return </span>content_type.split(<span class="string">';'</span>).next().unwrap().trim();
}
}
<span class="string">""
</span>}
<span class="doccomment">/// Get content type encoding.
///
/// UTF-8 is used by default, If request charset is not set.
</span><span class="kw">fn </span>encoding(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="kw-2">&amp;</span><span class="lifetime">'static </span>Encoding, ContentTypeError&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(mime_type) = <span class="self">self</span>.mime_type()<span class="question-mark">? </span>{
<span class="kw">if let </span><span class="prelude-val">Some</span>(charset) = mime_type.get_param(<span class="string">"charset"</span>) {
<span class="kw">if let </span><span class="prelude-val">Some</span>(enc) = Encoding::for_label_no_replacement(charset.as_str().as_bytes()) {
<span class="prelude-val">Ok</span>(enc)
} <span class="kw">else </span>{
<span class="prelude-val">Err</span>(ContentTypeError::UnknownEncoding)
}
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(UTF_8)
}
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(UTF_8)
}
}
<span class="doccomment">/// Convert the request content type to a known mime type.
</span><span class="kw">fn </span>mime_type(<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;Mime&gt;, ContentTypeError&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(content_type) = <span class="self">self</span>.headers().get(header::CONTENT_TYPE) {
<span class="kw">if let </span><span class="prelude-val">Ok</span>(content_type) = content_type.to_str() {
<span class="kw">return match </span>content_type.parse() {
<span class="prelude-val">Ok</span>(mt) =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(mt)),
<span class="prelude-val">Err</span>(<span class="kw">_</span>) =&gt; <span class="prelude-val">Err</span>(ContentTypeError::ParseError),
};
} <span class="kw">else </span>{
<span class="kw">return </span><span class="prelude-val">Err</span>(ContentTypeError::ParseError);
}
}
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
<span class="doccomment">/// Check if request has chunked transfer encoding.
</span><span class="kw">fn </span>chunked(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;bool, ParseError&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(encodings) = <span class="self">self</span>.headers().get(header::TRANSFER_ENCODING) {
<span class="kw">if let </span><span class="prelude-val">Ok</span>(s) = encodings.to_str() {
<span class="prelude-val">Ok</span>(s.to_lowercase().contains(<span class="string">"chunked"</span>))
} <span class="kw">else </span>{
<span class="prelude-val">Err</span>(ParseError::Header)
}
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="bool-val">false</span>)
}
}
}
<span class="kw">impl</span>&lt;<span class="lifetime">'a</span>, T&gt; HttpMessage <span class="kw">for </span><span class="kw-2">&amp;</span><span class="lifetime">'a </span><span class="kw-2">mut </span>T
<span class="kw">where
</span>T: HttpMessage,
{
<span class="kw">type </span>Stream = T::Stream;
<span class="kw">fn </span>headers(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>HeaderMap {
(<span class="kw-2">**</span><span class="self">self</span>).headers()
}
<span class="doccomment">/// Message payload stream
</span><span class="kw">fn </span>take_payload(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; Payload&lt;<span class="self">Self</span>::Stream&gt; {
(<span class="kw-2">**</span><span class="self">self</span>).take_payload()
}
<span class="doccomment">/// Request's extensions container
</span><span class="kw">fn </span>extensions(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Ref&lt;<span class="lifetime">'_</span>, Extensions&gt; {
(<span class="kw-2">**</span><span class="self">self</span>).extensions()
}
<span class="doccomment">/// Mutable reference to a the request's extensions container
</span><span class="kw">fn </span>extensions_mut(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; RefMut&lt;<span class="lifetime">'_</span>, Extensions&gt; {
(<span class="kw-2">**</span><span class="self">self</span>).extensions_mut()
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use </span>encoding_rs::ISO_8859_2;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use </span><span class="kw">crate</span>::test::TestRequest;
<span class="attr">#[test]
</span><span class="kw">fn </span>test_content_type() {
<span class="kw">let </span>req = TestRequest::default()
.insert_header((<span class="string">"content-type"</span>, <span class="string">"text/plain"</span>))
.finish();
<span class="macro">assert_eq!</span>(req.content_type(), <span class="string">"text/plain"</span>);
<span class="kw">let </span>req = TestRequest::default()
.insert_header((<span class="string">"content-type"</span>, <span class="string">"application/json; charset=utf-8"</span>))
.finish();
<span class="macro">assert_eq!</span>(req.content_type(), <span class="string">"application/json"</span>);
<span class="kw">let </span>req = TestRequest::default().finish();
<span class="macro">assert_eq!</span>(req.content_type(), <span class="string">""</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_mime_type() {
<span class="kw">let </span>req = TestRequest::default()
.insert_header((<span class="string">"content-type"</span>, <span class="string">"application/json"</span>))
.finish();
<span class="macro">assert_eq!</span>(req.mime_type().unwrap(), <span class="prelude-val">Some</span>(mime::APPLICATION_JSON));
<span class="kw">let </span>req = TestRequest::default().finish();
<span class="macro">assert_eq!</span>(req.mime_type().unwrap(), <span class="prelude-val">None</span>);
<span class="kw">let </span>req = TestRequest::default()
.insert_header((<span class="string">"content-type"</span>, <span class="string">"application/json; charset=utf-8"</span>))
.finish();
<span class="kw">let </span>mt = req.mime_type().unwrap().unwrap();
<span class="macro">assert_eq!</span>(mt.get_param(mime::CHARSET), <span class="prelude-val">Some</span>(mime::UTF_8));
<span class="macro">assert_eq!</span>(mt.type_(), mime::APPLICATION);
<span class="macro">assert_eq!</span>(mt.subtype(), mime::JSON);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_mime_type_error() {
<span class="kw">let </span>req = TestRequest::default()
.insert_header((<span class="string">"content-type"</span>, <span class="string">"applicationadfadsfasdflknadsfklnadsfjson"</span>))
.finish();
<span class="macro">assert_eq!</span>(<span class="prelude-val">Err</span>(ContentTypeError::ParseError), req.mime_type());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_encoding() {
<span class="kw">let </span>req = TestRequest::default().finish();
<span class="macro">assert_eq!</span>(UTF_8.name(), req.encoding().unwrap().name());
<span class="kw">let </span>req = TestRequest::default()
.insert_header((<span class="string">"content-type"</span>, <span class="string">"application/json"</span>))
.finish();
<span class="macro">assert_eq!</span>(UTF_8.name(), req.encoding().unwrap().name());
<span class="kw">let </span>req = TestRequest::default()
.insert_header((<span class="string">"content-type"</span>, <span class="string">"application/json; charset=ISO-8859-2"</span>))
.finish();
<span class="macro">assert_eq!</span>(ISO_8859_2, req.encoding().unwrap());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_encoding_error() {
<span class="kw">let </span>req = TestRequest::default()
.insert_header((<span class="string">"content-type"</span>, <span class="string">"applicatjson"</span>))
.finish();
<span class="macro">assert_eq!</span>(<span class="prelude-val">Some</span>(ContentTypeError::ParseError), req.encoding().err());
<span class="kw">let </span>req = TestRequest::default()
.insert_header((<span class="string">"content-type"</span>, <span class="string">"application/json; charset=kkkttktk"</span>))
.finish();
<span class="macro">assert_eq!</span>(
<span class="prelude-val">Some</span>(ContentTypeError::UnknownEncoding),
req.encoding().err()
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_chunked() {
<span class="kw">let </span>req = TestRequest::default().finish();
<span class="macro">assert!</span>(!req.chunked().unwrap());
<span class="kw">let </span>req = TestRequest::default()
.insert_header((header::TRANSFER_ENCODING, <span class="string">"chunked"</span>))
.finish();
<span class="macro">assert!</span>(req.chunked().unwrap());
<span class="kw">let </span>req = TestRequest::default()
.insert_header((
header::TRANSFER_ENCODING,
Bytes::from_static(<span class="string">b"some va\xadscc\xacas0xsdasdlue"</span>),
))
.finish();
<span class="macro">assert!</span>(req.chunked().is_err());
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,169 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/keep_alive.rs`."><title>keep_alive.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::time::Duration;
<span class="doccomment">/// Connection keep-alive config.
</span><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq)]
</span><span class="kw">pub enum </span>KeepAlive {
<span class="doccomment">/// Keep-alive duration.
///
/// `KeepAlive::Timeout(Duration::ZERO)` is mapped to `KeepAlive::Disabled`.
</span>Timeout(Duration),
<span class="doccomment">/// Rely on OS to shutdown TCP connection.
///
/// Some defaults can be very long, check your OS documentation.
</span>Os,
<span class="doccomment">/// Keep-alive is disabled.
///
/// Connections will be closed immediately.
</span>Disabled,
}
<span class="kw">impl </span>KeepAlive {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>enabled(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
!<span class="macro">matches!</span>(<span class="self">self</span>, <span class="self">Self</span>::Disabled)
}
<span class="attr">#[allow(unused)] </span><span class="comment">// used with `http2` feature flag
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>duration(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;Duration&gt; {
<span class="kw">match </span><span class="self">self </span>{
KeepAlive::Timeout(dur) =&gt; <span class="prelude-val">Some</span>(<span class="kw-2">*</span>dur),
<span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
}
}
<span class="doccomment">/// Map zero duration to disabled.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>normalize(<span class="self">self</span>) -&gt; KeepAlive {
<span class="kw">match </span><span class="self">self </span>{
KeepAlive::Timeout(Duration::ZERO) =&gt; KeepAlive::Disabled,
ka =&gt; ka,
}
}
}
<span class="kw">impl </span>Default <span class="kw">for </span>KeepAlive {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::Timeout(Duration::from_secs(<span class="number">5</span>))
}
}
<span class="kw">impl </span>From&lt;Duration&gt; <span class="kw">for </span>KeepAlive {
<span class="kw">fn </span>from(dur: Duration) -&gt; <span class="self">Self </span>{
KeepAlive::Timeout(dur).normalize()
}
}
<span class="kw">impl </span>From&lt;<span class="prelude-ty">Option</span>&lt;Duration&gt;&gt; <span class="kw">for </span>KeepAlive {
<span class="kw">fn </span>from(ka_dur: <span class="prelude-ty">Option</span>&lt;Duration&gt;) -&gt; <span class="self">Self </span>{
<span class="kw">match </span>ka_dur {
<span class="prelude-val">Some</span>(dur) =&gt; KeepAlive::from(dur),
<span class="prelude-val">None </span>=&gt; KeepAlive::Disabled,
}
.normalize()
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>from_impls() {
<span class="kw">let </span>test: KeepAlive = Duration::from_secs(<span class="number">1</span>).into();
<span class="macro">assert_eq!</span>(test, KeepAlive::Timeout(Duration::from_secs(<span class="number">1</span>)));
<span class="kw">let </span>test: KeepAlive = Duration::from_secs(<span class="number">0</span>).into();
<span class="macro">assert_eq!</span>(test, KeepAlive::Disabled);
<span class="kw">let </span>test: KeepAlive = <span class="prelude-val">Some</span>(Duration::from_secs(<span class="number">0</span>)).into();
<span class="macro">assert_eq!</span>(test, KeepAlive::Disabled);
<span class="kw">let </span>test: KeepAlive = <span class="prelude-val">None</span>.into();
<span class="macro">assert_eq!</span>(test, KeepAlive::Disabled);
}
}
</code></pre></div></section></main></body></html>

233
src/actix_http/lib.rs.html Normal file
View File

@ -0,0 +1,233 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! HTTP types and services for the Actix ecosystem.
//!
//! ## Crate Features
//!
//! | Feature | Functionality |
//! | ------------------- | ------------------------------------------- |
//! | `http2` | HTTP/2 support via [h2]. |
//! | `openssl` | TLS support via [OpenSSL]. |
//! | `rustls` | TLS support via [rustls] 0.20. |
//! | `rustls-0_21` | TLS support via [rustls] 0.21. |
//! | `rustls-0_22` | TLS support via [rustls] 0.22. |
//! | `rustls-0_23` | TLS support via [rustls] 0.23. |
//! | `compress-brotli` | Payload compression support: Brotli. |
//! | `compress-gzip` | Payload compression support: Deflate, Gzip. |
//! | `compress-zstd` | Payload compression support: Zstd. |
//! | `trust-dns` | Use [trust-dns] as the client DNS resolver. |
//!
//! [h2]: https://crates.io/crates/h2
//! [OpenSSL]: https://crates.io/crates/openssl
//! [rustls]: https://crates.io/crates/rustls
//! [trust-dns]: https://crates.io/crates/trust-dns
</span><span class="attr">#![deny(rust_2018_idioms, nonstandard_style)]
#![warn(future_incompatible)]
#![allow(
clippy::type_complexity,
clippy::too_many_arguments,
clippy::borrow_interior_mutable_const
)]
#![doc(html_logo_url = <span class="string">"https://actix.rs/img/logo.png"</span>)]
#![doc(html_favicon_url = <span class="string">"https://actix.rs/favicon.ico"</span>)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
</span><span class="kw">pub use </span>http::{uri, uri::Uri, Method, StatusCode, Version};
<span class="kw">pub mod </span>body;
<span class="kw">mod </span>builder;
<span class="kw">mod </span>config;
<span class="kw">mod </span>date;
<span class="attr">#[cfg(feature = <span class="string">"__compress"</span>)]
</span><span class="kw">pub mod </span>encoding;
<span class="kw">pub mod </span>error;
<span class="kw">mod </span>extensions;
<span class="kw">pub mod </span>h1;
<span class="attr">#[cfg(feature = <span class="string">"http2"</span>)]
</span><span class="kw">pub mod </span>h2;
<span class="kw">pub mod </span>header;
<span class="kw">mod </span>helpers;
<span class="kw">mod </span>http_message;
<span class="kw">mod </span>keep_alive;
<span class="kw">mod </span>message;
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>notify_on_drop;
<span class="kw">mod </span>payload;
<span class="kw">mod </span>requests;
<span class="kw">mod </span>responses;
<span class="kw">mod </span>service;
<span class="kw">pub mod </span>test;
<span class="attr">#[cfg(feature = <span class="string">"ws"</span>)]
</span><span class="kw">pub mod </span>ws;
<span class="attr">#[allow(deprecated)]
</span><span class="kw">pub use </span><span class="self">self</span>::payload::PayloadStream;
<span class="attr">#[cfg(any(
feature = <span class="string">"openssl"</span>,
feature = <span class="string">"rustls-0_20"</span>,
feature = <span class="string">"rustls-0_21"</span>,
feature = <span class="string">"rustls-0_22"</span>,
feature = <span class="string">"rustls-0_23"</span>,
))]
</span><span class="kw">pub use </span><span class="self">self</span>::service::TlsAcceptorConfig;
<span class="kw">pub use </span><span class="self">self</span>::{
builder::HttpServiceBuilder,
config::ServiceConfig,
error::Error,
extensions::Extensions,
header::ContentEncoding,
http_message::HttpMessage,
keep_alive::KeepAlive,
message::{ConnectionType, Message},
payload::{BoxedPayloadStream, Payload},
requests::{Request, RequestHead, RequestHeadType},
responses::{Response, ResponseBuilder, ResponseHead},
service::HttpService,
};
<span class="doccomment">/// A major HTTP protocol version.
</span><span class="attr">#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>Protocol {
Http1,
Http2,
Http3,
}
<span class="kw">type </span>ConnectCallback&lt;IO&gt; = <span class="kw">dyn </span>Fn(<span class="kw-2">&amp;</span>IO, <span class="kw-2">&amp;mut </span>Extensions);
<span class="doccomment">/// Container for data that extract with ConnectCallback.
///
/// # Implementation Details
/// Uses Option to reduce necessary allocations when merging with request extensions.
</span><span class="attr">#[derive(Default)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>OnConnectData(<span class="prelude-ty">Option</span>&lt;Extensions&gt;);
<span class="kw">impl </span>OnConnectData {
<span class="doccomment">/// Construct by calling the on-connect callback with the underlying transport I/O.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>from_io&lt;T&gt;(io: <span class="kw-2">&amp;</span>T, on_connect_ext: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>ConnectCallback&lt;T&gt;&gt;) -&gt; <span class="self">Self </span>{
<span class="kw">let </span>ext = on_connect_ext.map(|handler| {
<span class="kw">let </span><span class="kw-2">mut </span>extensions = Extensions::default();
handler(io, <span class="kw-2">&amp;mut </span>extensions);
extensions
});
<span class="self">Self</span>(ext)
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,215 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/message.rs`."><title>message.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{cell::RefCell, ops, rc::Rc};
<span class="kw">use </span>bitflags::bitflags;
<span class="doccomment">/// Represents various types of connection
</span><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq)]
</span><span class="kw">pub enum </span>ConnectionType {
<span class="doccomment">/// Close connection after response.
</span>Close,
<span class="doccomment">/// Keep connection alive after response.
</span>KeepAlive,
<span class="doccomment">/// Connection is upgraded to different type.
</span>Upgrade,
}
<span class="macro">bitflags!</span> {
<span class="attr">#[derive(Debug, Clone, Copy)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>Flags: u8 {
<span class="kw">const </span>CLOSE = <span class="number">0b0000_0001</span>;
<span class="kw">const </span>KEEP_ALIVE = <span class="number">0b0000_0010</span>;
<span class="kw">const </span>UPGRADE = <span class="number">0b0000_0100</span>;
<span class="kw">const </span>EXPECT = <span class="number">0b0000_1000</span>;
<span class="kw">const </span>NO_CHUNKING = <span class="number">0b0001_0000</span>;
<span class="kw">const </span>CAMEL_CASE = <span class="number">0b0010_0000</span>;
}
}
<span class="attr">#[doc(hidden)]
</span><span class="kw">pub trait </span>Head: Default + <span class="lifetime">'static </span>{
<span class="kw">fn </span>clear(<span class="kw-2">&amp;mut </span><span class="self">self</span>);
<span class="kw">fn </span>with_pool&lt;F, R&gt;(f: F) -&gt; R
<span class="kw">where
</span>F: FnOnce(<span class="kw-2">&amp;</span>MessagePool&lt;<span class="self">Self</span>&gt;) -&gt; R;
}
<span class="kw">pub struct </span>Message&lt;T: Head&gt; {
<span class="doccomment">/// Rc here should not be cloned by anyone.
/// It's used to reuse allocation of T and no shared ownership is allowed.
</span>head: Rc&lt;T&gt;,
}
<span class="kw">impl</span>&lt;T: Head&gt; Message&lt;T&gt; {
<span class="doccomment">/// Get new message from the pool of objects
</span><span class="attr">#[allow(clippy::new_without_default)]
</span><span class="kw">pub fn </span>new() -&gt; <span class="self">Self </span>{
T::with_pool(MessagePool::get_message)
}
}
<span class="kw">impl</span>&lt;T: Head&gt; ops::Deref <span class="kw">for </span>Message&lt;T&gt; {
<span class="kw">type </span>Target = T;
<span class="kw">fn </span>deref(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="self">Self</span>::Target {
<span class="self">self</span>.head.as_ref()
}
}
<span class="kw">impl</span>&lt;T: Head&gt; ops::DerefMut <span class="kw">for </span>Message&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><span class="self">Self</span>::Target {
Rc::get_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>.head).expect(<span class="string">"Multiple copies exist"</span>)
}
}
<span class="kw">impl</span>&lt;T: Head&gt; Drop <span class="kw">for </span>Message&lt;T&gt; {
<span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
T::with_pool(|p| p.release(<span class="self">self</span>.head.clone()))
}
}
<span class="doccomment">/// Generic `Head` object pool.
</span><span class="attr">#[doc(hidden)]
</span><span class="kw">pub struct </span>MessagePool&lt;T: Head&gt;(RefCell&lt;Vec&lt;Rc&lt;T&gt;&gt;&gt;);
<span class="kw">impl</span>&lt;T: Head&gt; MessagePool&lt;T&gt; {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>create() -&gt; MessagePool&lt;T&gt; {
MessagePool(RefCell::new(Vec::with_capacity(<span class="number">128</span>)))
}
<span class="doccomment">/// Get message from the pool
</span><span class="attr">#[inline]
</span><span class="kw">fn </span>get_message(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Message&lt;T&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">mut </span>msg) = <span class="self">self</span>.<span class="number">0</span>.borrow_mut().pop() {
<span class="comment">// Message is put in pool only when it's the last copy.
// which means it's guaranteed to be unique when popped out.
</span>Rc::get_mut(<span class="kw-2">&amp;mut </span>msg)
.expect(<span class="string">"Multiple copies exist"</span>)
.clear();
Message { head: msg }
} <span class="kw">else </span>{
Message {
head: Rc::new(T::default()),
}
}
}
<span class="attr">#[inline]
</span><span class="doccomment">/// Release message instance
</span><span class="kw">fn </span>release(<span class="kw-2">&amp;</span><span class="self">self</span>, msg: Rc&lt;T&gt;) {
<span class="kw">let </span>pool = <span class="kw-2">&amp;mut </span><span class="self">self</span>.<span class="number">0</span>.borrow_mut();
<span class="kw">if </span>pool.len() &lt; <span class="number">128 </span>{
pool.push(msg);
}
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,213 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/payload.rs`."><title>payload.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
mem,
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use </span>futures_core::Stream;
<span class="kw">use </span>pin_project_lite::pin_project;
<span class="kw">use </span><span class="kw">crate</span>::error::PayloadError;
<span class="doccomment">/// A boxed payload stream.
</span><span class="kw">pub type </span>BoxedPayloadStream = Pin&lt;Box&lt;<span class="kw">dyn </span>Stream&lt;Item = <span class="prelude-ty">Result</span>&lt;Bytes, PayloadError&gt;&gt;&gt;&gt;;
<span class="attr">#[doc(hidden)]
#[deprecated(since = <span class="string">"3.0.0"</span>, note = <span class="string">"Renamed to `BoxedPayloadStream`."</span>)]
</span><span class="kw">pub type </span>PayloadStream = BoxedPayloadStream;
<span class="attr">#[cfg(not(feature = <span class="string">"http2"</span>))]
</span><span class="macro">pin_project!</span> {
<span class="doccomment">/// A streaming payload.
</span><span class="attr">#[project = PayloadProj]
</span><span class="kw">pub enum </span>Payload&lt;S = BoxedPayloadStream&gt; {
<span class="prelude-val">None</span>,
H1 { payload: <span class="kw">crate</span>::h1::Payload },
Stream { <span class="attr">#[pin] </span>payload: S },
}
}
<span class="attr">#[cfg(feature = <span class="string">"http2"</span>)]
</span><span class="macro">pin_project!</span> {
<span class="doccomment">/// A streaming payload.
</span><span class="attr">#[project = PayloadProj]
</span><span class="kw">pub enum </span>Payload&lt;S = BoxedPayloadStream&gt; {
<span class="prelude-val">None</span>,
H1 { payload: <span class="kw">crate</span>::h1::Payload },
H2 { payload: <span class="kw">crate</span>::h2::Payload },
Stream { <span class="attr">#[pin] </span>payload: S },
}
}
<span class="kw">impl</span>&lt;S&gt; From&lt;<span class="kw">crate</span>::h1::Payload&gt; <span class="kw">for </span>Payload&lt;S&gt; {
<span class="kw">fn </span>from(payload: <span class="kw">crate</span>::h1::Payload) -&gt; <span class="self">Self </span>{
Payload::H1 { payload }
}
}
<span class="attr">#[cfg(feature = <span class="string">"http2"</span>)]
</span><span class="kw">impl</span>&lt;S&gt; From&lt;<span class="kw">crate</span>::h2::Payload&gt; <span class="kw">for </span>Payload&lt;S&gt; {
<span class="kw">fn </span>from(payload: <span class="kw">crate</span>::h2::Payload) -&gt; <span class="self">Self </span>{
Payload::H2 { payload }
}
}
<span class="attr">#[cfg(feature = <span class="string">"http2"</span>)]
</span><span class="kw">impl</span>&lt;S&gt; From&lt;::h2::RecvStream&gt; <span class="kw">for </span>Payload&lt;S&gt; {
<span class="kw">fn </span>from(stream: ::h2::RecvStream) -&gt; <span class="self">Self </span>{
Payload::H2 {
payload: <span class="kw">crate</span>::h2::Payload::new(stream),
}
}
}
<span class="kw">impl </span>From&lt;BoxedPayloadStream&gt; <span class="kw">for </span>Payload {
<span class="kw">fn </span>from(payload: BoxedPayloadStream) -&gt; <span class="self">Self </span>{
Payload::Stream { payload }
}
}
<span class="kw">impl</span>&lt;S&gt; Payload&lt;S&gt; {
<span class="doccomment">/// Takes current payload and replaces it with `None` value
</span><span class="kw">pub fn </span>take(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; Payload&lt;S&gt; {
mem::replace(<span class="self">self</span>, Payload::None)
}
}
<span class="kw">impl</span>&lt;S&gt; Stream <span class="kw">for </span>Payload&lt;S&gt;
<span class="kw">where
</span>S: Stream&lt;Item = <span class="prelude-ty">Result</span>&lt;Bytes, PayloadError&gt;&gt;,
{
<span class="kw">type </span>Item = <span class="prelude-ty">Result</span>&lt;Bytes, PayloadError&gt;;
<span class="attr">#[inline]
</span><span class="kw">fn </span>poll_next(<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;<span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt;&gt; {
<span class="kw">match </span><span class="self">self</span>.project() {
PayloadProj::None =&gt; Poll::Ready(<span class="prelude-val">None</span>),
PayloadProj::H1 { payload } =&gt; Pin::new(payload).poll_next(cx),
<span class="attr">#[cfg(feature = <span class="string">"http2"</span>)]
</span>PayloadProj::H2 { payload } =&gt; Pin::new(payload).poll_next(cx),
PayloadProj::Stream { payload } =&gt; payload.poll_next(cx),
}
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>static_assertions::{assert_impl_all, assert_not_impl_any};
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="macro">assert_impl_all!</span>(Payload: Unpin);
<span class="macro">assert_not_impl_any!</span>(Payload: Send, Sync);
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,355 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/requests/head.rs`."><title>head.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{net, rc::Rc};
<span class="kw">use crate</span>::{
header::{<span class="self">self</span>, HeaderMap},
message::{Flags, Head, MessagePool},
ConnectionType, Method, Uri, Version,
};
<span class="macro">thread_local!</span> {
<span class="kw">static </span>REQUEST_POOL: MessagePool&lt;RequestHead&gt; = MessagePool::&lt;RequestHead&gt;::create()
}
<span class="attr">#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>RequestHead {
<span class="kw">pub </span>method: Method,
<span class="kw">pub </span>uri: Uri,
<span class="kw">pub </span>version: Version,
<span class="kw">pub </span>headers: HeaderMap,
<span class="doccomment">/// Will only be None when called in unit tests unless set manually.
</span><span class="kw">pub </span>peer_addr: <span class="prelude-ty">Option</span>&lt;net::SocketAddr&gt;,
flags: Flags,
}
<span class="kw">impl </span>Default <span class="kw">for </span>RequestHead {
<span class="kw">fn </span>default() -&gt; RequestHead {
RequestHead {
method: Method::default(),
uri: Uri::default(),
version: Version::HTTP_11,
headers: HeaderMap::with_capacity(<span class="number">16</span>),
peer_addr: <span class="prelude-val">None</span>,
flags: Flags::empty(),
}
}
}
<span class="kw">impl </span>Head <span class="kw">for </span>RequestHead {
<span class="kw">fn </span>clear(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="self">self</span>.flags = Flags::empty();
<span class="self">self</span>.headers.clear();
}
<span class="kw">fn </span>with_pool&lt;F, R&gt;(f: F) -&gt; R
<span class="kw">where
</span>F: FnOnce(<span class="kw-2">&amp;</span>MessagePool&lt;<span class="self">Self</span>&gt;) -&gt; R,
{
REQUEST_POOL.with(|p| f(p))
}
}
<span class="kw">impl </span>RequestHead {
<span class="doccomment">/// Read the message headers.
</span><span class="kw">pub fn </span>headers(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>HeaderMap {
<span class="kw-2">&amp;</span><span class="self">self</span>.headers
}
<span class="doccomment">/// Mutable reference to the message headers.
</span><span class="kw">pub fn </span>headers_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>HeaderMap {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.headers
}
<span class="doccomment">/// Is to uppercase headers with Camel-Case.
/// Default is `false`
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>camel_case_headers(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.flags.contains(Flags::CAMEL_CASE)
}
<span class="doccomment">/// Set `true` to send headers which are formatted as Camel-Case.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>set_camel_case_headers(<span class="kw-2">&amp;mut </span><span class="self">self</span>, val: bool) {
<span class="kw">if </span>val {
<span class="self">self</span>.flags.insert(Flags::CAMEL_CASE);
} <span class="kw">else </span>{
<span class="self">self</span>.flags.remove(Flags::CAMEL_CASE);
}
}
<span class="attr">#[inline]
</span><span class="doccomment">/// Set connection type of the message
</span><span class="kw">pub fn </span>set_connection_type(<span class="kw-2">&amp;mut </span><span class="self">self</span>, ctype: ConnectionType) {
<span class="kw">match </span>ctype {
ConnectionType::Close =&gt; <span class="self">self</span>.flags.insert(Flags::CLOSE),
ConnectionType::KeepAlive =&gt; <span class="self">self</span>.flags.insert(Flags::KEEP_ALIVE),
ConnectionType::Upgrade =&gt; <span class="self">self</span>.flags.insert(Flags::UPGRADE),
}
}
<span class="attr">#[inline]
</span><span class="doccomment">/// Connection type
</span><span class="kw">pub fn </span>connection_type(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; ConnectionType {
<span class="kw">if </span><span class="self">self</span>.flags.contains(Flags::CLOSE) {
ConnectionType::Close
} <span class="kw">else if </span><span class="self">self</span>.flags.contains(Flags::KEEP_ALIVE) {
ConnectionType::KeepAlive
} <span class="kw">else if </span><span class="self">self</span>.flags.contains(Flags::UPGRADE) {
ConnectionType::Upgrade
} <span class="kw">else if </span><span class="self">self</span>.version &lt; Version::HTTP_11 {
ConnectionType::Close
} <span class="kw">else </span>{
ConnectionType::KeepAlive
}
}
<span class="doccomment">/// Connection upgrade status
</span><span class="kw">pub fn </span>upgrade(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.headers()
.get(header::CONNECTION)
.map(|hdr| {
<span class="kw">if let </span><span class="prelude-val">Ok</span>(s) = hdr.to_str() {
s.to_ascii_lowercase().contains(<span class="string">"upgrade"</span>)
} <span class="kw">else </span>{
<span class="bool-val">false
</span>}
})
.unwrap_or(<span class="bool-val">false</span>)
}
<span class="attr">#[inline]
</span><span class="doccomment">/// Get response body chunking state
</span><span class="kw">pub fn </span>chunked(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
!<span class="self">self</span>.flags.contains(Flags::NO_CHUNKING)
}
<span class="attr">#[inline]
</span><span class="kw">pub fn </span>no_chunking(<span class="kw-2">&amp;mut </span><span class="self">self</span>, val: bool) {
<span class="kw">if </span>val {
<span class="self">self</span>.flags.insert(Flags::NO_CHUNKING);
} <span class="kw">else </span>{
<span class="self">self</span>.flags.remove(Flags::NO_CHUNKING);
}
}
<span class="doccomment">/// Request contains `EXPECT` header.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>expect(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.flags.contains(Flags::EXPECT)
}
<span class="attr">#[inline]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>set_expect(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="self">self</span>.flags.insert(Flags::EXPECT);
}
}
<span class="attr">#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
</span><span class="kw">pub enum </span>RequestHeadType {
Owned(RequestHead),
Rc(Rc&lt;RequestHead&gt;, <span class="prelude-ty">Option</span>&lt;HeaderMap&gt;),
}
<span class="kw">impl </span>RequestHeadType {
<span class="kw">pub fn </span>extra_headers(<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>HeaderMap&gt; {
<span class="kw">match </span><span class="self">self </span>{
RequestHeadType::Owned(<span class="kw">_</span>) =&gt; <span class="prelude-val">None</span>,
RequestHeadType::Rc(<span class="kw">_</span>, headers) =&gt; headers.as_ref(),
}
}
}
<span class="kw">impl </span>AsRef&lt;RequestHead&gt; <span class="kw">for </span>RequestHeadType {
<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>RequestHead {
<span class="kw">match </span><span class="self">self </span>{
RequestHeadType::Owned(head) =&gt; head,
RequestHeadType::Rc(head, <span class="kw">_</span>) =&gt; head.as_ref(),
}
}
}
<span class="kw">impl </span>From&lt;RequestHead&gt; <span class="kw">for </span>RequestHeadType {
<span class="kw">fn </span>from(head: RequestHead) -&gt; <span class="self">Self </span>{
RequestHeadType::Owned(head)
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/requests/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! HTTP requests.
</span><span class="kw">mod </span>head;
<span class="kw">mod </span>request;
<span class="kw">pub use </span><span class="self">self</span>::{
head::{RequestHead, RequestHeadType},
request::Request,
};
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,509 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/requests/request.rs`."><title>request.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! HTTP requests.
</span><span class="kw">use </span>std::{
cell::{Ref, RefCell, RefMut},
fmt, mem, net,
rc::Rc,
str,
};
<span class="kw">use </span>http::{header, Method, Uri, Version};
<span class="kw">use crate</span>::{
header::HeaderMap, BoxedPayloadStream, Extensions, HttpMessage, Message, Payload, RequestHead,
};
<span class="doccomment">/// An HTTP request.
</span><span class="kw">pub struct </span>Request&lt;P = BoxedPayloadStream&gt; {
<span class="kw">pub</span>(<span class="kw">crate</span>) payload: Payload&lt;P&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) head: Message&lt;RequestHead&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) conn_data: <span class="prelude-ty">Option</span>&lt;Rc&lt;Extensions&gt;&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) extensions: RefCell&lt;Extensions&gt;,
}
<span class="kw">impl</span>&lt;P&gt; HttpMessage <span class="kw">for </span>Request&lt;P&gt; {
<span class="kw">type </span>Stream = P;
<span class="attr">#[inline]
</span><span class="kw">fn </span>headers(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>HeaderMap {
<span class="kw-2">&amp;</span><span class="self">self</span>.head().headers
}
<span class="kw">fn </span>take_payload(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; Payload&lt;P&gt; {
mem::replace(<span class="kw-2">&amp;mut </span><span class="self">self</span>.payload, Payload::None)
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>extensions(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Ref&lt;<span class="lifetime">'_</span>, Extensions&gt; {
<span class="self">self</span>.extensions.borrow()
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>extensions_mut(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; RefMut&lt;<span class="lifetime">'_</span>, Extensions&gt; {
<span class="self">self</span>.extensions.borrow_mut()
}
}
<span class="kw">impl </span>From&lt;Message&lt;RequestHead&gt;&gt; <span class="kw">for </span>Request&lt;BoxedPayloadStream&gt; {
<span class="kw">fn </span>from(head: Message&lt;RequestHead&gt;) -&gt; <span class="self">Self </span>{
Request {
head,
payload: Payload::None,
extensions: RefCell::new(Extensions::default()),
conn_data: <span class="prelude-val">None</span>,
}
}
}
<span class="kw">impl </span>Request&lt;BoxedPayloadStream&gt; {
<span class="doccomment">/// Create new Request instance
</span><span class="attr">#[allow(clippy::new_without_default)]
</span><span class="kw">pub fn </span>new() -&gt; Request&lt;BoxedPayloadStream&gt; {
Request {
head: Message::new(),
payload: Payload::None,
extensions: RefCell::new(Extensions::default()),
conn_data: <span class="prelude-val">None</span>,
}
}
}
<span class="kw">impl</span>&lt;P&gt; Request&lt;P&gt; {
<span class="doccomment">/// Create new Request instance
</span><span class="kw">pub fn </span>with_payload(payload: Payload&lt;P&gt;) -&gt; Request&lt;P&gt; {
Request {
payload,
head: Message::new(),
extensions: RefCell::new(Extensions::default()),
conn_data: <span class="prelude-val">None</span>,
}
}
<span class="doccomment">/// Create new Request instance
</span><span class="kw">pub fn </span>replace_payload&lt;P1&gt;(<span class="self">self</span>, payload: Payload&lt;P1&gt;) -&gt; (Request&lt;P1&gt;, Payload&lt;P&gt;) {
<span class="kw">let </span>pl = <span class="self">self</span>.payload;
(
Request {
payload,
head: <span class="self">self</span>.head,
extensions: <span class="self">self</span>.extensions,
conn_data: <span class="self">self</span>.conn_data,
},
pl,
)
}
<span class="doccomment">/// Get request's payload
</span><span class="kw">pub fn </span>payload(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>Payload&lt;P&gt; {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.payload
}
<span class="doccomment">/// Get request's payload
</span><span class="kw">pub fn </span>take_payload(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; Payload&lt;P&gt; {
mem::replace(<span class="kw-2">&amp;mut </span><span class="self">self</span>.payload, Payload::None)
}
<span class="doccomment">/// Split request into request head and payload
</span><span class="kw">pub fn </span>into_parts(<span class="self">self</span>) -&gt; (Message&lt;RequestHead&gt;, Payload&lt;P&gt;) {
(<span class="self">self</span>.head, <span class="self">self</span>.payload)
}
<span class="attr">#[inline]
</span><span class="doccomment">/// Http message part of the request
</span><span class="kw">pub fn </span>head(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>RequestHead {
<span class="kw-2">&amp;</span><span class="self">self</span>.head
}
<span class="attr">#[inline]
#[doc(hidden)]
</span><span class="doccomment">/// Mutable reference to a HTTP message part of the request
</span><span class="kw">pub fn </span>head_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>RequestHead {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.head
}
<span class="doccomment">/// Mutable reference to the message's headers.
</span><span class="kw">pub fn </span>headers_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>HeaderMap {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.head.headers
}
<span class="doccomment">/// Request's uri.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>uri(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>Uri {
<span class="kw-2">&amp;</span><span class="self">self</span>.head().uri
}
<span class="doccomment">/// Mutable reference to the request's uri.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>uri_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>Uri {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.head.uri
}
<span class="doccomment">/// Read the Request method.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>method(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>Method {
<span class="kw-2">&amp;</span><span class="self">self</span>.head().method
}
<span class="doccomment">/// Read the Request Version.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>version(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Version {
<span class="self">self</span>.head().version
}
<span class="doccomment">/// The target path of this Request.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>path(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="self">self</span>.head().uri.path()
}
<span class="doccomment">/// Check if request requires connection upgrade
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>upgrade(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="kw">if let </span><span class="prelude-val">Some</span>(conn) = <span class="self">self</span>.head().headers.get(header::CONNECTION) {
<span class="kw">if let </span><span class="prelude-val">Ok</span>(s) = conn.to_str() {
<span class="kw">return </span>s.to_lowercase().contains(<span class="string">"upgrade"</span>);
}
}
<span class="self">self</span>.head().method == Method::CONNECT
}
<span class="doccomment">/// Peer socket address.
///
/// Peer address is the directly connected peer's socket address. If a proxy is used in front of
/// the Actix Web server, then it would be address of this proxy.
///
/// Will only return None when called in unit tests unless set manually.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>peer_addr(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;net::SocketAddr&gt; {
<span class="self">self</span>.head().peer_addr
}
<span class="doccomment">/// Returns a reference a piece of connection data set in an [on-connect] callback.
///
/// ```ignore
/// let opt_t = req.conn_data::&lt;PeerCertificate&gt;();
/// ```
///
/// [on-connect]: crate::HttpServiceBuilder::on_connect_ext
</span><span class="kw">pub fn </span>conn_data&lt;T: <span class="lifetime">'static</span>&gt;(<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="self">self</span>.conn_data
.as_deref()
.and_then(|container| container.get::&lt;T&gt;())
}
<span class="doccomment">/// Returns the connection-level data/extensions container if an [on-connect] callback was
/// registered, leaving an empty one in its place.
///
/// [on-connect]: crate::HttpServiceBuilder::on_connect_ext
</span><span class="kw">pub fn </span>take_conn_data(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;Rc&lt;Extensions&gt;&gt; {
<span class="self">self</span>.conn_data.take()
}
<span class="doccomment">/// Returns the request-local data/extensions container, leaving an empty one in its place.
</span><span class="kw">pub fn </span>take_req_data(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; Extensions {
mem::take(<span class="self">self</span>.extensions.get_mut())
}
}
<span class="kw">impl</span>&lt;P&gt; fmt::Debug <span class="kw">for </span>Request&lt;P&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">'_</span>&gt;) -&gt; fmt::Result {
<span class="macro">writeln!</span>(
f,
<span class="string">"\nRequest {:?} {}:{}"</span>,
<span class="self">self</span>.version(),
<span class="self">self</span>.method(),
<span class="self">self</span>.path()
)<span class="question-mark">?</span>;
<span class="kw">if let </span><span class="prelude-val">Some</span>(q) = <span class="self">self</span>.uri().query().as_ref() {
<span class="macro">writeln!</span>(f, <span class="string">" query: ?{:?}"</span>, q)<span class="question-mark">?</span>;
}
<span class="macro">writeln!</span>(f, <span class="string">" headers:"</span>)<span class="question-mark">?</span>;
<span class="kw">for </span>(key, val) <span class="kw">in </span><span class="self">self</span>.headers().iter() {
<span class="macro">writeln!</span>(f, <span class="string">" {:?}: {:?}"</span>, key, val)<span class="question-mark">?</span>;
}
<span class="prelude-val">Ok</span>(())
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>test_basics() {
<span class="kw">let </span>msg = Message::new();
<span class="kw">let </span><span class="kw-2">mut </span>req = Request::from(msg);
req.headers_mut().insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static(<span class="string">"text/plain"</span>),
);
<span class="macro">assert!</span>(req.headers().contains_key(header::CONTENT_TYPE));
<span class="kw-2">*</span>req.uri_mut() = Uri::try_from(<span class="string">"/index.html?q=1"</span>).unwrap();
<span class="macro">assert_eq!</span>(req.uri().path(), <span class="string">"/index.html"</span>);
<span class="macro">assert_eq!</span>(req.uri().query(), <span class="prelude-val">Some</span>(<span class="string">"q=1"</span>));
<span class="kw">let </span>s = <span class="macro">format!</span>(<span class="string">"{:?}"</span>, req);
<span class="macro">assert!</span>(s.contains(<span class="string">"Request HTTP/1.1 GET:/index.html"</span>));
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,859 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/responses/builder.rs`."><title>builder.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
<a href="#339" id="339">339</a>
<a href="#340" id="340">340</a>
<a href="#341" id="341">341</a>
<a href="#342" id="342">342</a>
<a href="#343" id="343">343</a>
<a href="#344" id="344">344</a>
<a href="#345" id="345">345</a>
<a href="#346" id="346">346</a>
<a href="#347" id="347">347</a>
<a href="#348" id="348">348</a>
<a href="#349" id="349">349</a>
<a href="#350" id="350">350</a>
<a href="#351" id="351">351</a>
<a href="#352" id="352">352</a>
<a href="#353" id="353">353</a>
<a href="#354" id="354">354</a>
<a href="#355" id="355">355</a>
<a href="#356" id="356">356</a>
<a href="#357" id="357">357</a>
<a href="#358" id="358">358</a>
<a href="#359" id="359">359</a>
<a href="#360" id="360">360</a>
<a href="#361" id="361">361</a>
<a href="#362" id="362">362</a>
<a href="#363" id="363">363</a>
<a href="#364" id="364">364</a>
<a href="#365" id="365">365</a>
<a href="#366" id="366">366</a>
<a href="#367" id="367">367</a>
<a href="#368" id="368">368</a>
<a href="#369" id="369">369</a>
<a href="#370" id="370">370</a>
<a href="#371" id="371">371</a>
<a href="#372" id="372">372</a>
<a href="#373" id="373">373</a>
<a href="#374" id="374">374</a>
<a href="#375" id="375">375</a>
<a href="#376" id="376">376</a>
<a href="#377" id="377">377</a>
<a href="#378" id="378">378</a>
<a href="#379" id="379">379</a>
<a href="#380" id="380">380</a>
<a href="#381" id="381">381</a>
<a href="#382" id="382">382</a>
<a href="#383" id="383">383</a>
<a href="#384" id="384">384</a>
<a href="#385" id="385">385</a>
<a href="#386" id="386">386</a>
<a href="#387" id="387">387</a>
<a href="#388" id="388">388</a>
<a href="#389" id="389">389</a>
<a href="#390" id="390">390</a>
<a href="#391" id="391">391</a>
<a href="#392" id="392">392</a>
<a href="#393" id="393">393</a>
<a href="#394" id="394">394</a>
<a href="#395" id="395">395</a>
<a href="#396" id="396">396</a>
<a href="#397" id="397">397</a>
<a href="#398" id="398">398</a>
<a href="#399" id="399">399</a>
<a href="#400" id="400">400</a>
<a href="#401" id="401">401</a>
<a href="#402" id="402">402</a>
<a href="#403" id="403">403</a>
<a href="#404" id="404">404</a>
<a href="#405" id="405">405</a>
<a href="#406" id="406">406</a>
<a href="#407" id="407">407</a>
<a href="#408" id="408">408</a>
<a href="#409" id="409">409</a>
<a href="#410" id="410">410</a>
<a href="#411" id="411">411</a>
<a href="#412" id="412">412</a>
<a href="#413" id="413">413</a>
<a href="#414" id="414">414</a>
<a href="#415" id="415">415</a>
<a href="#416" id="416">416</a>
<a href="#417" id="417">417</a>
<a href="#418" id="418">418</a>
<a href="#419" id="419">419</a>
<a href="#420" id="420">420</a>
<a href="#421" id="421">421</a>
<a href="#422" id="422">422</a>
<a href="#423" id="423">423</a>
<a href="#424" id="424">424</a>
<a href="#425" id="425">425</a>
<a href="#426" id="426">426</a>
<a href="#427" id="427">427</a>
<a href="#428" id="428">428</a>
<a href="#429" id="429">429</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! HTTP response builder.
</span><span class="kw">use </span>std::{cell::RefCell, fmt, str};
<span class="kw">use crate</span>::{
body::{EitherBody, MessageBody},
error::{Error, HttpError},
header::{<span class="self">self</span>, TryIntoHeaderPair, TryIntoHeaderValue},
responses::{BoxedResponseHead, ResponseHead},
ConnectionType, Extensions, Response, StatusCode,
};
<span class="doccomment">/// An HTTP response builder.
///
/// Used to construct an instance of `Response` using a builder pattern. Response builders are often
/// created using [`Response::build`].
///
/// # Examples
/// ```
/// use actix_http::{Response, ResponseBuilder, StatusCode, body, header};
///
/// # actix_rt::System::new().block_on(async {
/// let mut res: Response&lt;_&gt; = Response::build(StatusCode::OK)
/// .content_type(mime::APPLICATION_JSON)
/// .insert_header((header::SERVER, "my-app/1.0"))
/// .append_header((header::SET_COOKIE, "a=1"))
/// .append_header((header::SET_COOKIE, "b=2"))
/// .body("1234");
///
/// assert_eq!(res.status(), StatusCode::OK);
///
/// assert!(res.headers().contains_key("server"));
/// assert_eq!(res.headers().get_all("set-cookie").count(), 2);
///
/// assert_eq!(body::to_bytes(res.into_body()).await.unwrap(), &amp;b"1234"[..]);
/// # })
/// ```
</span><span class="kw">pub struct </span>ResponseBuilder {
head: <span class="prelude-ty">Option</span>&lt;BoxedResponseHead&gt;,
err: <span class="prelude-ty">Option</span>&lt;HttpError&gt;,
}
<span class="kw">impl </span>ResponseBuilder {
<span class="doccomment">/// Create response builder
///
/// # Examples
/// ```
/// use actix_http::{Response, ResponseBuilder, StatusCode};
/// let res: Response&lt;_&gt; = ResponseBuilder::default().finish();
/// assert_eq!(res.status(), StatusCode::OK);
/// ```
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>new(status: StatusCode) -&gt; <span class="self">Self </span>{
ResponseBuilder {
head: <span class="prelude-val">Some</span>(BoxedResponseHead::new(status)),
err: <span class="prelude-val">None</span>,
}
}
<span class="doccomment">/// Set HTTP status code of this response.
///
/// # Examples
/// ```
/// use actix_http::{ResponseBuilder, StatusCode};
/// let res = ResponseBuilder::default().status(StatusCode::NOT_FOUND).finish();
/// assert_eq!(res.status(), StatusCode::NOT_FOUND);
/// ```
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>status(<span class="kw-2">&amp;mut </span><span class="self">self</span>, status: StatusCode) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="kw">if let </span><span class="prelude-val">Some</span>(parts) = <span class="self">self</span>.inner() {
parts.status = status;
}
<span class="self">self
</span>}
<span class="doccomment">/// Insert a header, replacing any that were set with an equivalent field name.
///
/// # Examples
/// ```
/// use actix_http::{ResponseBuilder, header};
///
/// let res = ResponseBuilder::default()
/// .insert_header((header::CONTENT_TYPE, mime::APPLICATION_JSON))
/// .insert_header(("X-TEST", "value"))
/// .finish();
///
/// assert!(res.headers().contains_key("content-type"));
/// assert!(res.headers().contains_key("x-test"));
/// ```
</span><span class="kw">pub fn </span>insert_header(<span class="kw-2">&amp;mut </span><span class="self">self</span>, header: <span class="kw">impl </span>TryIntoHeaderPair) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="kw">if let </span><span class="prelude-val">Some</span>(parts) = <span class="self">self</span>.inner() {
<span class="kw">match </span>header.try_into_pair() {
<span class="prelude-val">Ok</span>((key, value)) =&gt; {
parts.headers.insert(key, value);
}
<span class="prelude-val">Err</span>(err) =&gt; <span class="self">self</span>.err = <span class="prelude-val">Some</span>(err.into()),
};
}
<span class="self">self
</span>}
<span class="doccomment">/// Append a header, keeping any that were set with an equivalent field name.
///
/// # Examples
/// ```
/// use actix_http::{ResponseBuilder, header};
///
/// let res = ResponseBuilder::default()
/// .append_header((header::CONTENT_TYPE, mime::APPLICATION_JSON))
/// .append_header(("X-TEST", "value1"))
/// .append_header(("X-TEST", "value2"))
/// .finish();
///
/// assert_eq!(res.headers().get_all("content-type").count(), 1);
/// assert_eq!(res.headers().get_all("x-test").count(), 2);
/// ```
</span><span class="kw">pub fn </span>append_header(<span class="kw-2">&amp;mut </span><span class="self">self</span>, header: <span class="kw">impl </span>TryIntoHeaderPair) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="kw">if let </span><span class="prelude-val">Some</span>(parts) = <span class="self">self</span>.inner() {
<span class="kw">match </span>header.try_into_pair() {
<span class="prelude-val">Ok</span>((key, value)) =&gt; parts.headers.append(key, value),
<span class="prelude-val">Err</span>(err) =&gt; <span class="self">self</span>.err = <span class="prelude-val">Some</span>(err.into()),
};
}
<span class="self">self
</span>}
<span class="doccomment">/// Set the custom reason for the response.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>reason(<span class="kw-2">&amp;mut </span><span class="self">self</span>, reason: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="kw">if let </span><span class="prelude-val">Some</span>(parts) = <span class="self">self</span>.inner() {
parts.reason = <span class="prelude-val">Some</span>(reason);
}
<span class="self">self
</span>}
<span class="doccomment">/// Set connection type to KeepAlive
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>keep_alive(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="kw">if let </span><span class="prelude-val">Some</span>(parts) = <span class="self">self</span>.inner() {
parts.set_connection_type(ConnectionType::KeepAlive);
}
<span class="self">self
</span>}
<span class="doccomment">/// Set connection type to `Upgrade`.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>upgrade&lt;V&gt;(<span class="kw-2">&amp;mut </span><span class="self">self</span>, value: V) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self
</span><span class="kw">where
</span>V: TryIntoHeaderValue,
{
<span class="kw">if let </span><span class="prelude-val">Some</span>(parts) = <span class="self">self</span>.inner() {
parts.set_connection_type(ConnectionType::Upgrade);
}
<span class="kw">if let </span><span class="prelude-val">Ok</span>(value) = value.try_into_value() {
<span class="self">self</span>.insert_header((header::UPGRADE, value));
}
<span class="self">self
</span>}
<span class="doccomment">/// Force-close connection, even if it is marked as keep-alive.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>force_close(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="kw">if let </span><span class="prelude-val">Some</span>(parts) = <span class="self">self</span>.inner() {
parts.set_connection_type(ConnectionType::Close);
}
<span class="self">self
</span>}
<span class="doccomment">/// Disable chunked transfer encoding for HTTP/1.1 streaming responses.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>no_chunking(<span class="kw-2">&amp;mut </span><span class="self">self</span>, len: u64) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="kw">let </span><span class="kw-2">mut </span>buf = itoa::Buffer::new();
<span class="self">self</span>.insert_header((header::CONTENT_LENGTH, buf.format(len)));
<span class="kw">if let </span><span class="prelude-val">Some</span>(parts) = <span class="self">self</span>.inner() {
parts.no_chunking(<span class="bool-val">true</span>);
}
<span class="self">self
</span>}
<span class="doccomment">/// Set response content type.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>content_type&lt;V&gt;(<span class="kw-2">&amp;mut </span><span class="self">self</span>, value: V) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self
</span><span class="kw">where
</span>V: TryIntoHeaderValue,
{
<span class="kw">if let </span><span class="prelude-val">Some</span>(parts) = <span class="self">self</span>.inner() {
<span class="kw">match </span>value.try_into_value() {
<span class="prelude-val">Ok</span>(value) =&gt; {
parts.headers.insert(header::CONTENT_TYPE, value);
}
<span class="prelude-val">Err</span>(err) =&gt; <span class="self">self</span>.err = <span class="prelude-val">Some</span>(err.into()),
};
}
<span class="self">self
</span>}
<span class="doccomment">/// Generate response with a wrapped body.
///
/// This `ResponseBuilder` will be left in a useless state.
</span><span class="kw">pub fn </span>body&lt;B&gt;(<span class="kw-2">&amp;mut </span><span class="self">self</span>, body: B) -&gt; Response&lt;EitherBody&lt;B&gt;&gt;
<span class="kw">where
</span>B: MessageBody + <span class="lifetime">'static</span>,
{
<span class="kw">match </span><span class="self">self</span>.message_body(body) {
<span class="prelude-val">Ok</span>(res) =&gt; res.map_body(|<span class="kw">_</span>, body| EitherBody::left(body)),
<span class="prelude-val">Err</span>(err) =&gt; Response::from(err).map_body(|<span class="kw">_</span>, body| EitherBody::right(body)),
}
}
<span class="doccomment">/// Generate response with a body.
///
/// This `ResponseBuilder` will be left in a useless state.
</span><span class="kw">pub fn </span>message_body&lt;B&gt;(<span class="kw-2">&amp;mut </span><span class="self">self</span>, body: B) -&gt; <span class="prelude-ty">Result</span>&lt;Response&lt;B&gt;, Error&gt; {
<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><span class="prelude-val">Err</span>(Error::new_http().with_cause(err));
}
<span class="kw">let </span>head = <span class="self">self</span>.head.take().expect(<span class="string">"cannot reuse response builder"</span>);
<span class="prelude-val">Ok</span>(Response {
head,
body,
extensions: RefCell::new(Extensions::new()),
})
}
<span class="doccomment">/// Generate response with an empty body.
///
/// This `ResponseBuilder` will be left in a useless state.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; Response&lt;EitherBody&lt;()&gt;&gt; {
<span class="self">self</span>.body(())
}
<span class="doccomment">/// Create an owned `ResponseBuilder`, leaving the original in a useless state.
</span><span class="kw">pub fn </span>take(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; ResponseBuilder {
ResponseBuilder {
head: <span class="self">self</span>.head.take(),
err: <span class="self">self</span>.err.take(),
}
}
<span class="doccomment">/// Get access to the inner response head if there has been no error.
</span><span class="kw">fn </span>inner(<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>ResponseHead&gt; {
<span class="kw">if </span><span class="self">self</span>.err.is_some() {
<span class="kw">return </span><span class="prelude-val">None</span>;
}
<span class="self">self</span>.head.as_deref_mut()
}
}
<span class="kw">impl </span>Default <span class="kw">for </span>ResponseBuilder {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(StatusCode::OK)
}
}
<span class="doccomment">/// Convert `Response` to a `ResponseBuilder`. Body get dropped.
</span><span class="kw">impl</span>&lt;B&gt; From&lt;Response&lt;B&gt;&gt; <span class="kw">for </span>ResponseBuilder {
<span class="kw">fn </span>from(res: Response&lt;B&gt;) -&gt; ResponseBuilder {
ResponseBuilder {
head: <span class="prelude-val">Some</span>(res.head),
err: <span class="prelude-val">None</span>,
}
}
}
<span class="doccomment">/// Convert `ResponseHead` to a `ResponseBuilder`
</span><span class="kw">impl</span>&lt;<span class="lifetime">'a</span>&gt; From&lt;<span class="kw-2">&amp;</span><span class="lifetime">'a </span>ResponseHead&gt; <span class="kw">for </span>ResponseBuilder {
<span class="kw">fn </span>from(head: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>ResponseHead) -&gt; ResponseBuilder {
<span class="kw">let </span><span class="kw-2">mut </span>msg = BoxedResponseHead::new(head.status);
msg.version = head.version;
msg.reason = head.reason;
<span class="kw">for </span>(k, v) <span class="kw">in </span>head.headers.iter() {
msg.headers.append(k.clone(), v.clone());
}
msg.no_chunking(!head.chunked());
ResponseBuilder {
head: <span class="prelude-val">Some</span>(msg),
err: <span class="prelude-val">None</span>,
}
}
}
<span class="kw">impl </span>fmt::Debug <span class="kw">for </span>ResponseBuilder {
<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">'_</span>&gt;) -&gt; fmt::Result {
<span class="kw">let </span>head = <span class="self">self</span>.head.as_ref().unwrap();
<span class="kw">let </span>res = <span class="macro">writeln!</span>(
f,
<span class="string">"\nResponseBuilder {:?} {}{}"</span>,
head.version,
head.status,
head.reason.unwrap_or(<span class="string">""</span>),
);
<span class="kw">let _ </span>= <span class="macro">writeln!</span>(f, <span class="string">" headers:"</span>);
<span class="kw">for </span>(key, val) <span class="kw">in </span>head.headers.iter() {
<span class="kw">let _ </span>= <span class="macro">writeln!</span>(f, <span class="string">" {:?}: {:?}"</span>, key, val);
}
res
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use </span><span class="kw">crate</span>::header::{HeaderName, HeaderValue, CONTENT_TYPE};
<span class="attr">#[test]
</span><span class="kw">fn </span>test_basic_builder() {
<span class="kw">let </span>resp = Response::build(StatusCode::OK)
.insert_header((<span class="string">"X-TEST"</span>, <span class="string">"value"</span>))
.finish();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::OK);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_upgrade() {
<span class="kw">let </span>resp = Response::build(StatusCode::OK)
.upgrade(<span class="string">"websocket"</span>)
.finish();
<span class="macro">assert!</span>(resp.upgrade());
<span class="macro">assert_eq!</span>(
resp.headers().get(header::UPGRADE).unwrap(),
HeaderValue::from_static(<span class="string">"websocket"</span>)
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_force_close() {
<span class="kw">let </span>resp = Response::build(StatusCode::OK).force_close().finish();
<span class="macro">assert!</span>(!resp.keep_alive());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_content_type() {
<span class="kw">let </span>resp = Response::build(StatusCode::OK)
.content_type(<span class="string">"text/plain"</span>)
.body(Bytes::new());
<span class="macro">assert_eq!</span>(resp.headers().get(CONTENT_TYPE).unwrap(), <span class="string">"text/plain"</span>);
<span class="kw">let </span>resp = Response::build(StatusCode::OK)
.content_type(mime::APPLICATION_JAVASCRIPT_UTF_8)
.body(Bytes::new());
<span class="macro">assert_eq!</span>(
resp.headers().get(CONTENT_TYPE).unwrap(),
<span class="string">"application/javascript; charset=utf-8"
</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_into_builder() {
<span class="kw">let </span><span class="kw-2">mut </span>resp: Response&lt;<span class="kw">_</span>&gt; = <span class="string">"test"</span>.into();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::OK);
resp.headers_mut().insert(
HeaderName::from_static(<span class="string">"cookie"</span>),
HeaderValue::from_static(<span class="string">"cookie1=val100"</span>),
);
<span class="kw">let </span><span class="kw-2">mut </span>builder: ResponseBuilder = resp.into();
<span class="kw">let </span>resp = builder.status(StatusCode::BAD_REQUEST).finish();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::BAD_REQUEST);
<span class="kw">let </span>cookie = resp.headers().get_all(<span class="string">"Cookie"</span>).next().unwrap();
<span class="macro">assert_eq!</span>(cookie.to_str().unwrap(), <span class="string">"cookie1=val100"</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>response_builder_header_insert_kv() {
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::build(StatusCode::OK);
res.insert_header((<span class="string">"Content-Type"</span>, <span class="string">"application/octet-stream"</span>));
<span class="kw">let </span>res = res.finish();
<span class="macro">assert_eq!</span>(
res.headers().get(<span class="string">"Content-Type"</span>),
<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>HeaderValue::from_static(<span class="string">"application/octet-stream"</span>))
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>response_builder_header_insert_typed() {
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::build(StatusCode::OK);
res.insert_header((header::CONTENT_TYPE, mime::APPLICATION_OCTET_STREAM));
<span class="kw">let </span>res = res.finish();
<span class="macro">assert_eq!</span>(
res.headers().get(<span class="string">"Content-Type"</span>),
<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>HeaderValue::from_static(<span class="string">"application/octet-stream"</span>))
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>response_builder_header_append_kv() {
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::build(StatusCode::OK);
res.append_header((<span class="string">"Content-Type"</span>, <span class="string">"application/octet-stream"</span>));
res.append_header((<span class="string">"Content-Type"</span>, <span class="string">"application/json"</span>));
<span class="kw">let </span>res = res.finish();
<span class="kw">let </span>headers: Vec&lt;<span class="kw">_</span>&gt; = res.headers().get_all(<span class="string">"Content-Type"</span>).cloned().collect();
<span class="macro">assert_eq!</span>(headers.len(), <span class="number">2</span>);
<span class="macro">assert!</span>(headers.contains(<span class="kw-2">&amp;</span>HeaderValue::from_static(<span class="string">"application/octet-stream"</span>)));
<span class="macro">assert!</span>(headers.contains(<span class="kw-2">&amp;</span>HeaderValue::from_static(<span class="string">"application/json"</span>)));
}
<span class="attr">#[test]
</span><span class="kw">fn </span>response_builder_header_append_typed() {
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::build(StatusCode::OK);
res.append_header((header::CONTENT_TYPE, mime::APPLICATION_OCTET_STREAM));
res.append_header((header::CONTENT_TYPE, mime::APPLICATION_JSON));
<span class="kw">let </span>res = res.finish();
<span class="kw">let </span>headers: Vec&lt;<span class="kw">_</span>&gt; = res.headers().get_all(<span class="string">"Content-Type"</span>).cloned().collect();
<span class="macro">assert_eq!</span>(headers.len(), <span class="number">2</span>);
<span class="macro">assert!</span>(headers.contains(<span class="kw-2">&amp;</span>HeaderValue::from_static(<span class="string">"application/octet-stream"</span>)));
<span class="macro">assert!</span>(headers.contains(<span class="kw-2">&amp;</span>HeaderValue::from_static(<span class="string">"application/json"</span>)));
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,539 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/responses/head.rs`."><title>head.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Response head type and caching pool.
</span><span class="kw">use </span>std::{cell::RefCell, ops};
<span class="kw">use crate</span>::{header::HeaderMap, message::Flags, ConnectionType, StatusCode, Version};
<span class="macro">thread_local!</span> {
<span class="kw">static </span>RESPONSE_POOL: BoxedResponsePool = BoxedResponsePool::create();
}
<span class="attr">#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>ResponseHead {
<span class="kw">pub </span>version: Version,
<span class="kw">pub </span>status: StatusCode,
<span class="kw">pub </span>headers: HeaderMap,
<span class="kw">pub </span>reason: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span><span class="lifetime">'static </span>str&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) flags: Flags,
}
<span class="kw">impl </span>ResponseHead {
<span class="doccomment">/// Create new instance of `ResponseHead` type
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>new(status: StatusCode) -&gt; ResponseHead {
ResponseHead {
status,
version: Version::HTTP_11,
headers: HeaderMap::with_capacity(<span class="number">12</span>),
reason: <span class="prelude-val">None</span>,
flags: Flags::empty(),
}
}
<span class="doccomment">/// Read the message headers.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>headers(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>HeaderMap {
<span class="kw-2">&amp;</span><span class="self">self</span>.headers
}
<span class="doccomment">/// Mutable reference to the message headers.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>headers_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>HeaderMap {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.headers
}
<span class="doccomment">/// Sets the flag that controls whether to send headers formatted as Camel-Case.
///
/// Only applicable to HTTP/1.x responses; HTTP/2 header names are always lowercase.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>set_camel_case_headers(<span class="kw-2">&amp;mut </span><span class="self">self</span>, camel_case: bool) {
<span class="kw">if </span>camel_case {
<span class="self">self</span>.flags.insert(Flags::CAMEL_CASE);
} <span class="kw">else </span>{
<span class="self">self</span>.flags.remove(Flags::CAMEL_CASE);
}
}
<span class="doccomment">/// Set connection type of the message
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>set_connection_type(<span class="kw-2">&amp;mut </span><span class="self">self</span>, ctype: ConnectionType) {
<span class="kw">match </span>ctype {
ConnectionType::Close =&gt; <span class="self">self</span>.flags.insert(Flags::CLOSE),
ConnectionType::KeepAlive =&gt; <span class="self">self</span>.flags.insert(Flags::KEEP_ALIVE),
ConnectionType::Upgrade =&gt; <span class="self">self</span>.flags.insert(Flags::UPGRADE),
}
}
<span class="attr">#[inline]
</span><span class="kw">pub fn </span>connection_type(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; ConnectionType {
<span class="kw">if </span><span class="self">self</span>.flags.contains(Flags::CLOSE) {
ConnectionType::Close
} <span class="kw">else if </span><span class="self">self</span>.flags.contains(Flags::KEEP_ALIVE) {
ConnectionType::KeepAlive
} <span class="kw">else if </span><span class="self">self</span>.flags.contains(Flags::UPGRADE) {
ConnectionType::Upgrade
} <span class="kw">else if </span><span class="self">self</span>.version &lt; Version::HTTP_11 {
ConnectionType::Close
} <span class="kw">else </span>{
ConnectionType::KeepAlive
}
}
<span class="doccomment">/// Check if keep-alive is enabled
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>keep_alive(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.connection_type() == ConnectionType::KeepAlive
}
<span class="doccomment">/// Check upgrade status of this message
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>upgrade(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.connection_type() == ConnectionType::Upgrade
}
<span class="doccomment">/// Get custom reason for the response
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>reason(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="self">self</span>.reason.unwrap_or_else(|| {
<span class="self">self</span>.status
.canonical_reason()
.unwrap_or(<span class="string">"&lt;unknown status code&gt;"</span>)
})
}
<span class="attr">#[inline]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>conn_type(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;ConnectionType&gt; {
<span class="kw">if </span><span class="self">self</span>.flags.contains(Flags::CLOSE) {
<span class="prelude-val">Some</span>(ConnectionType::Close)
} <span class="kw">else if </span><span class="self">self</span>.flags.contains(Flags::KEEP_ALIVE) {
<span class="prelude-val">Some</span>(ConnectionType::KeepAlive)
} <span class="kw">else if </span><span class="self">self</span>.flags.contains(Flags::UPGRADE) {
<span class="prelude-val">Some</span>(ConnectionType::Upgrade)
} <span class="kw">else </span>{
<span class="prelude-val">None
</span>}
}
<span class="doccomment">/// Get response body chunking state
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>chunked(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
!<span class="self">self</span>.flags.contains(Flags::NO_CHUNKING)
}
<span class="doccomment">/// Set no chunking for payload
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>no_chunking(<span class="kw-2">&amp;mut </span><span class="self">self</span>, val: bool) {
<span class="kw">if </span>val {
<span class="self">self</span>.flags.insert(Flags::NO_CHUNKING);
} <span class="kw">else </span>{
<span class="self">self</span>.flags.remove(Flags::NO_CHUNKING);
}
}
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>BoxedResponseHead {
head: <span class="prelude-ty">Option</span>&lt;Box&lt;ResponseHead&gt;&gt;,
}
<span class="kw">impl </span>BoxedResponseHead {
<span class="doccomment">/// Get new message from the pool of objects
</span><span class="kw">pub fn </span>new(status: StatusCode) -&gt; <span class="self">Self </span>{
RESPONSE_POOL.with(|p| p.get_message(status))
}
}
<span class="kw">impl </span>ops::Deref <span class="kw">for </span>BoxedResponseHead {
<span class="kw">type </span>Target = ResponseHead;
<span class="kw">fn </span>deref(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="self">Self</span>::Target {
<span class="self">self</span>.head.as_ref().unwrap()
}
}
<span class="kw">impl </span>ops::DerefMut <span class="kw">for </span>BoxedResponseHead {
<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><span class="self">Self</span>::Target {
<span class="self">self</span>.head.as_mut().unwrap()
}
}
<span class="kw">impl </span>Drop <span class="kw">for </span>BoxedResponseHead {
<span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="kw">if let </span><span class="prelude-val">Some</span>(head) = <span class="self">self</span>.head.take() {
RESPONSE_POOL.with(<span class="kw">move </span>|p| p.release(head))
}
}
}
<span class="doccomment">/// Response head object pool.
</span><span class="attr">#[doc(hidden)]
</span><span class="kw">pub struct </span>BoxedResponsePool(<span class="attr">#[allow(clippy::vec_box)] </span>RefCell&lt;Vec&lt;Box&lt;ResponseHead&gt;&gt;&gt;);
<span class="kw">impl </span>BoxedResponsePool {
<span class="kw">fn </span>create() -&gt; BoxedResponsePool {
BoxedResponsePool(RefCell::new(Vec::with_capacity(<span class="number">128</span>)))
}
<span class="doccomment">/// Get message from the pool.
</span><span class="attr">#[inline]
</span><span class="kw">fn </span>get_message(<span class="kw-2">&amp;</span><span class="self">self</span>, status: StatusCode) -&gt; BoxedResponseHead {
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">mut </span>head) = <span class="self">self</span>.<span class="number">0</span>.borrow_mut().pop() {
head.reason = <span class="prelude-val">None</span>;
head.status = status;
head.headers.clear();
head.flags = Flags::empty();
BoxedResponseHead { head: <span class="prelude-val">Some</span>(head) }
} <span class="kw">else </span>{
BoxedResponseHead {
head: <span class="prelude-val">Some</span>(Box::new(ResponseHead::new(status))),
}
}
}
<span class="doccomment">/// Release request instance.
</span><span class="attr">#[inline]
</span><span class="kw">fn </span>release(<span class="kw-2">&amp;</span><span class="self">self</span>, msg: Box&lt;ResponseHead&gt;) {
<span class="kw">let </span>pool = <span class="kw-2">&amp;mut </span><span class="self">self</span>.<span class="number">0</span>.borrow_mut();
<span class="kw">if </span>pool.len() &lt; <span class="number">128 </span>{
pool.push(msg);
}
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::{
io::{Read <span class="kw">as _</span>, Write <span class="kw">as _</span>},
net,
};
<span class="kw">use </span>memchr::memmem;
<span class="kw">use crate</span>::{
h1::H1Service,
header::{HeaderName, HeaderValue},
Error, Request, Response, ServiceConfig,
};
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>camel_case_headers() {
<span class="kw">let </span><span class="kw-2">mut </span>srv = actix_http_test::test_server(|| {
H1Service::with_config(ServiceConfig::default(), |req: Request| <span class="kw">async move </span>{
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::ok();
<span class="kw">if </span>req.path().contains(<span class="string">"camel"</span>) {
res.head_mut().set_camel_case_headers(<span class="bool-val">true</span>);
}
res.headers_mut().insert(
HeaderName::from_static(<span class="string">"foo-bar"</span>),
HeaderValue::from_static(<span class="string">"baz"</span>),
);
<span class="prelude-val">Ok</span>::&lt;<span class="kw">_</span>, Error&gt;(res)
})
.tcp()
})
.<span class="kw">await</span>;
<span class="kw">let </span><span class="kw-2">mut </span>stream = net::TcpStream::connect(srv.addr()).unwrap();
stream
.write_all(<span class="string">b"GET /camel HTTP/1.1\r\nConnection: Close\r\n\r\n"</span>)
.unwrap();
<span class="kw">let </span><span class="kw-2">mut </span>data = <span class="macro">vec!</span>[];
<span class="kw">let _ </span>= stream.read_to_end(<span class="kw-2">&amp;mut </span>data).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>data[..<span class="number">17</span>], <span class="string">b"HTTP/1.1 200 OK\r\n"</span>);
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>data, <span class="string">b"Foo-Bar"</span>).is_some());
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>data, <span class="string">b"foo-bar"</span>).is_none());
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>data, <span class="string">b"Date"</span>).is_some());
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>data, <span class="string">b"date"</span>).is_none());
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>data, <span class="string">b"Content-Length"</span>).is_some());
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>data, <span class="string">b"content-length"</span>).is_none());
<span class="kw">let </span><span class="kw-2">mut </span>stream = net::TcpStream::connect(srv.addr()).unwrap();
stream
.write_all(<span class="string">b"GET /lower HTTP/1.1\r\nConnection: Close\r\n\r\n"</span>)
.unwrap();
<span class="kw">let </span><span class="kw-2">mut </span>data = <span class="macro">vec!</span>[];
<span class="kw">let _ </span>= stream.read_to_end(<span class="kw-2">&amp;mut </span>data).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>data[..<span class="number">17</span>], <span class="string">b"HTTP/1.1 200 OK\r\n"</span>);
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>data, <span class="string">b"Foo-Bar"</span>).is_none());
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>data, <span class="string">b"foo-bar"</span>).is_some());
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>data, <span class="string">b"Date"</span>).is_none());
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>data, <span class="string">b"date"</span>).is_some());
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>data, <span class="string">b"Content-Length"</span>).is_none());
<span class="macro">assert!</span>(memmem::find(<span class="kw-2">&amp;</span>data, <span class="string">b"content-length"</span>).is_some());
srv.stop().<span class="kw">await</span>;
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/responses/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! HTTP response.
</span><span class="kw">mod </span>builder;
<span class="kw">mod </span>head;
<span class="attr">#[allow(clippy::module_inception)]
</span><span class="kw">mod </span>response;
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">use </span><span class="self">self</span>::head::BoxedResponseHead;
<span class="kw">pub use </span><span class="self">self</span>::{builder::ResponseBuilder, head::ResponseHead, response::Response};
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,877 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/responses/response.rs`."><title>response.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
<a href="#339" id="339">339</a>
<a href="#340" id="340">340</a>
<a href="#341" id="341">341</a>
<a href="#342" id="342">342</a>
<a href="#343" id="343">343</a>
<a href="#344" id="344">344</a>
<a href="#345" id="345">345</a>
<a href="#346" id="346">346</a>
<a href="#347" id="347">347</a>
<a href="#348" id="348">348</a>
<a href="#349" id="349">349</a>
<a href="#350" id="350">350</a>
<a href="#351" id="351">351</a>
<a href="#352" id="352">352</a>
<a href="#353" id="353">353</a>
<a href="#354" id="354">354</a>
<a href="#355" id="355">355</a>
<a href="#356" id="356">356</a>
<a href="#357" id="357">357</a>
<a href="#358" id="358">358</a>
<a href="#359" id="359">359</a>
<a href="#360" id="360">360</a>
<a href="#361" id="361">361</a>
<a href="#362" id="362">362</a>
<a href="#363" id="363">363</a>
<a href="#364" id="364">364</a>
<a href="#365" id="365">365</a>
<a href="#366" id="366">366</a>
<a href="#367" id="367">367</a>
<a href="#368" id="368">368</a>
<a href="#369" id="369">369</a>
<a href="#370" id="370">370</a>
<a href="#371" id="371">371</a>
<a href="#372" id="372">372</a>
<a href="#373" id="373">373</a>
<a href="#374" id="374">374</a>
<a href="#375" id="375">375</a>
<a href="#376" id="376">376</a>
<a href="#377" id="377">377</a>
<a href="#378" id="378">378</a>
<a href="#379" id="379">379</a>
<a href="#380" id="380">380</a>
<a href="#381" id="381">381</a>
<a href="#382" id="382">382</a>
<a href="#383" id="383">383</a>
<a href="#384" id="384">384</a>
<a href="#385" id="385">385</a>
<a href="#386" id="386">386</a>
<a href="#387" id="387">387</a>
<a href="#388" id="388">388</a>
<a href="#389" id="389">389</a>
<a href="#390" id="390">390</a>
<a href="#391" id="391">391</a>
<a href="#392" id="392">392</a>
<a href="#393" id="393">393</a>
<a href="#394" id="394">394</a>
<a href="#395" id="395">395</a>
<a href="#396" id="396">396</a>
<a href="#397" id="397">397</a>
<a href="#398" id="398">398</a>
<a href="#399" id="399">399</a>
<a href="#400" id="400">400</a>
<a href="#401" id="401">401</a>
<a href="#402" id="402">402</a>
<a href="#403" id="403">403</a>
<a href="#404" id="404">404</a>
<a href="#405" id="405">405</a>
<a href="#406" id="406">406</a>
<a href="#407" id="407">407</a>
<a href="#408" id="408">408</a>
<a href="#409" id="409">409</a>
<a href="#410" id="410">410</a>
<a href="#411" id="411">411</a>
<a href="#412" id="412">412</a>
<a href="#413" id="413">413</a>
<a href="#414" id="414">414</a>
<a href="#415" id="415">415</a>
<a href="#416" id="416">416</a>
<a href="#417" id="417">417</a>
<a href="#418" id="418">418</a>
<a href="#419" id="419">419</a>
<a href="#420" id="420">420</a>
<a href="#421" id="421">421</a>
<a href="#422" id="422">422</a>
<a href="#423" id="423">423</a>
<a href="#424" id="424">424</a>
<a href="#425" id="425">425</a>
<a href="#426" id="426">426</a>
<a href="#427" id="427">427</a>
<a href="#428" id="428">428</a>
<a href="#429" id="429">429</a>
<a href="#430" id="430">430</a>
<a href="#431" id="431">431</a>
<a href="#432" id="432">432</a>
<a href="#433" id="433">433</a>
<a href="#434" id="434">434</a>
<a href="#435" id="435">435</a>
<a href="#436" id="436">436</a>
<a href="#437" id="437">437</a>
<a href="#438" id="438">438</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! HTTP response.
</span><span class="kw">use </span>std::{
cell::{Ref, RefCell, RefMut},
fmt, str,
};
<span class="kw">use </span>bytes::{Bytes, BytesMut};
<span class="kw">use </span>bytestring::ByteString;
<span class="kw">use crate</span>::{
body::{BoxBody, EitherBody, MessageBody},
header::{<span class="self">self</span>, HeaderMap, TryIntoHeaderValue},
responses::BoxedResponseHead,
Error, Extensions, ResponseBuilder, ResponseHead, StatusCode,
};
<span class="doccomment">/// An HTTP response.
</span><span class="kw">pub struct </span>Response&lt;B&gt; {
<span class="kw">pub</span>(<span class="kw">crate</span>) head: BoxedResponseHead,
<span class="kw">pub</span>(<span class="kw">crate</span>) body: B,
<span class="kw">pub</span>(<span class="kw">crate</span>) extensions: RefCell&lt;Extensions&gt;,
}
<span class="kw">impl </span>Response&lt;BoxBody&gt; {
<span class="doccomment">/// Constructs a new response with default body.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>new(status: StatusCode) -&gt; <span class="self">Self </span>{
Response {
head: BoxedResponseHead::new(status),
body: BoxBody::new(()),
extensions: RefCell::new(Extensions::new()),
}
}
<span class="doccomment">/// Constructs a new response builder.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>build(status: StatusCode) -&gt; ResponseBuilder {
ResponseBuilder::new(status)
}
<span class="comment">// just a couple frequently used shortcuts
// this list should not grow larger than a few
</span><span class="doccomment">/// Constructs a new response with status 200 OK.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>ok() -&gt; <span class="self">Self </span>{
Response::new(StatusCode::OK)
}
<span class="doccomment">/// Constructs a new response with status 400 Bad Request.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>bad_request() -&gt; <span class="self">Self </span>{
Response::new(StatusCode::BAD_REQUEST)
}
<span class="doccomment">/// Constructs a new response with status 404 Not Found.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>not_found() -&gt; <span class="self">Self </span>{
Response::new(StatusCode::NOT_FOUND)
}
<span class="doccomment">/// Constructs a new response with status 500 Internal Server Error.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>internal_server_error() -&gt; <span class="self">Self </span>{
Response::new(StatusCode::INTERNAL_SERVER_ERROR)
}
<span class="comment">// end shortcuts
</span>}
<span class="kw">impl</span>&lt;B&gt; Response&lt;B&gt; {
<span class="doccomment">/// Constructs a new response with given body.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>with_body(status: StatusCode, body: B) -&gt; Response&lt;B&gt; {
Response {
head: BoxedResponseHead::new(status),
body,
extensions: RefCell::new(Extensions::new()),
}
}
<span class="doccomment">/// Returns a reference to the head of this response.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>head(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ResponseHead {
<span class="kw-2">&amp;</span><span class="self">self</span>.head
}
<span class="doccomment">/// Returns a mutable reference to the head of this response.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>head_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>ResponseHead {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.head
}
<span class="doccomment">/// Returns the status code of this response.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>status(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
<span class="self">self</span>.head.status
}
<span class="doccomment">/// Returns a mutable reference the status code of this response.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>status_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>.head.status
}
<span class="doccomment">/// Returns a reference to response headers.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>headers(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>HeaderMap {
<span class="kw-2">&amp;</span><span class="self">self</span>.head.headers
}
<span class="doccomment">/// Returns a mutable reference to response headers.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>headers_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>HeaderMap {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.head.headers
}
<span class="doccomment">/// Returns true if connection upgrade is enabled.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>upgrade(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.head.upgrade()
}
<span class="doccomment">/// Returns true if keep-alive is enabled.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>keep_alive(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.head.keep_alive()
}
<span class="doccomment">/// Returns a reference to the request-local data/extensions container.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>extensions(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Ref&lt;<span class="lifetime">'_</span>, Extensions&gt; {
<span class="self">self</span>.extensions.borrow()
}
<span class="doccomment">/// Returns a mutable reference to the request-local data/extensions container.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>extensions_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; RefMut&lt;<span class="lifetime">'_</span>, Extensions&gt; {
<span class="self">self</span>.extensions.borrow_mut()
}
<span class="doccomment">/// Returns a reference to the body of this response.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>body(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>B {
<span class="kw-2">&amp;</span><span class="self">self</span>.body
}
<span class="doccomment">/// Sets new body.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>set_body&lt;B2&gt;(<span class="self">self</span>, body: B2) -&gt; Response&lt;B2&gt; {
Response {
head: <span class="self">self</span>.head,
body,
extensions: <span class="self">self</span>.extensions,
}
}
<span class="doccomment">/// Drops body and returns new response.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>drop_body(<span class="self">self</span>) -&gt; Response&lt;()&gt; {
<span class="self">self</span>.set_body(())
}
<span class="doccomment">/// Sets new body, returning new response and previous body value.
</span><span class="attr">#[inline]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>replace_body&lt;B2&gt;(<span class="self">self</span>, body: B2) -&gt; (Response&lt;B2&gt;, B) {
(
Response {
head: <span class="self">self</span>.head,
body,
extensions: <span class="self">self</span>.extensions,
},
<span class="self">self</span>.body,
)
}
<span class="doccomment">/// Returns split head and body.
///
/// # Implementation Notes
/// Due to internal performance optimizations, the first element of the returned tuple is a
/// `Response` as well but only contains the head of the response this was called on.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>into_parts(<span class="self">self</span>) -&gt; (Response&lt;()&gt;, B) {
<span class="self">self</span>.replace_body(())
}
<span class="doccomment">/// Map the current body type to another using a closure, returning a new response.
///
/// Closure receives the response head and the current body type.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>map_body&lt;F, B2&gt;(<span class="kw-2">mut </span><span class="self">self</span>, f: F) -&gt; Response&lt;B2&gt;
<span class="kw">where
</span>F: FnOnce(<span class="kw-2">&amp;mut </span>ResponseHead, B) -&gt; B2,
{
<span class="kw">let </span>body = f(<span class="kw-2">&amp;mut </span><span class="self">self</span>.head, <span class="self">self</span>.body);
Response {
head: <span class="self">self</span>.head,
body,
extensions: <span class="self">self</span>.extensions,
}
}
<span class="doccomment">/// Map the current body to a type-erased `BoxBody`.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>map_into_boxed_body(<span class="self">self</span>) -&gt; Response&lt;BoxBody&gt;
<span class="kw">where
</span>B: MessageBody + <span class="lifetime">'static</span>,
{
<span class="self">self</span>.map_body(|<span class="kw">_</span>, body| body.boxed())
}
<span class="doccomment">/// Returns the response body, dropping all other parts.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>into_body(<span class="self">self</span>) -&gt; B {
<span class="self">self</span>.body
}
}
<span class="kw">impl</span>&lt;B&gt; fmt::Debug <span class="kw">for </span>Response&lt;B&gt;
<span class="kw">where
</span>B: MessageBody,
{
<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">'_</span>&gt;) -&gt; fmt::Result {
<span class="kw">let </span>res = <span class="macro">writeln!</span>(
f,
<span class="string">"\nResponse {:?} {}{}"</span>,
<span class="self">self</span>.head.version,
<span class="self">self</span>.head.status,
<span class="self">self</span>.head.reason.unwrap_or(<span class="string">""</span>),
);
<span class="kw">let _ </span>= <span class="macro">writeln!</span>(f, <span class="string">" headers:"</span>);
<span class="kw">for </span>(key, val) <span class="kw">in </span><span class="self">self</span>.head.headers.iter() {
<span class="kw">let _ </span>= <span class="macro">writeln!</span>(f, <span class="string">" {:?}: {:?}"</span>, key, val);
}
<span class="kw">let _ </span>= <span class="macro">writeln!</span>(f, <span class="string">" body: {:?}"</span>, <span class="self">self</span>.body.size());
res
}
}
<span class="kw">impl</span>&lt;B: Default&gt; Default <span class="kw">for </span>Response&lt;B&gt; {
<span class="attr">#[inline]
</span><span class="kw">fn </span>default() -&gt; Response&lt;B&gt; {
Response::with_body(StatusCode::default(), B::default())
}
}
<span class="kw">impl</span>&lt;I: Into&lt;Response&lt;BoxBody&gt;&gt;, E: Into&lt;Error&gt;&gt; From&lt;<span class="prelude-ty">Result</span>&lt;I, E&gt;&gt; <span class="kw">for </span>Response&lt;BoxBody&gt; {
<span class="kw">fn </span>from(res: <span class="prelude-ty">Result</span>&lt;I, E&gt;) -&gt; <span class="self">Self </span>{
<span class="kw">match </span>res {
<span class="prelude-val">Ok</span>(val) =&gt; val.into(),
<span class="prelude-val">Err</span>(err) =&gt; Response::from(err.into()),
}
}
}
<span class="kw">impl </span>From&lt;ResponseBuilder&gt; <span class="kw">for </span>Response&lt;EitherBody&lt;()&gt;&gt; {
<span class="kw">fn </span>from(<span class="kw-2">mut </span>builder: ResponseBuilder) -&gt; <span class="self">Self </span>{
builder.finish()
}
}
<span class="kw">impl </span>From&lt;std::convert::Infallible&gt; <span class="kw">for </span>Response&lt;BoxBody&gt; {
<span class="kw">fn </span>from(val: std::convert::Infallible) -&gt; <span class="self">Self </span>{
<span class="kw">match </span>val {}
}
}
<span class="kw">impl </span>From&lt;<span class="kw-2">&amp;</span><span class="lifetime">'static </span>str&gt; <span class="kw">for </span>Response&lt;<span class="kw-2">&amp;</span><span class="lifetime">'static </span>str&gt; {
<span class="kw">fn </span>from(val: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str) -&gt; <span class="self">Self </span>{
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::with_body(StatusCode::OK, val);
<span class="kw">let </span>mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
res.headers_mut().insert(header::CONTENT_TYPE, mime);
res
}
}
<span class="kw">impl </span>From&lt;<span class="kw-2">&amp;</span><span class="lifetime">'static </span>[u8]&gt; <span class="kw">for </span>Response&lt;<span class="kw-2">&amp;</span><span class="lifetime">'static </span>[u8]&gt; {
<span class="kw">fn </span>from(val: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>[u8]) -&gt; <span class="self">Self </span>{
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::with_body(StatusCode::OK, val);
<span class="kw">let </span>mime = mime::APPLICATION_OCTET_STREAM.try_into_value().unwrap();
res.headers_mut().insert(header::CONTENT_TYPE, mime);
res
}
}
<span class="kw">impl </span>From&lt;Vec&lt;u8&gt;&gt; <span class="kw">for </span>Response&lt;Vec&lt;u8&gt;&gt; {
<span class="kw">fn </span>from(val: Vec&lt;u8&gt;) -&gt; <span class="self">Self </span>{
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::with_body(StatusCode::OK, val);
<span class="kw">let </span>mime = mime::APPLICATION_OCTET_STREAM.try_into_value().unwrap();
res.headers_mut().insert(header::CONTENT_TYPE, mime);
res
}
}
<span class="kw">impl </span>From&lt;<span class="kw-2">&amp;</span>Vec&lt;u8&gt;&gt; <span class="kw">for </span>Response&lt;Vec&lt;u8&gt;&gt; {
<span class="kw">fn </span>from(val: <span class="kw-2">&amp;</span>Vec&lt;u8&gt;) -&gt; <span class="self">Self </span>{
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::with_body(StatusCode::OK, val.clone());
<span class="kw">let </span>mime = mime::APPLICATION_OCTET_STREAM.try_into_value().unwrap();
res.headers_mut().insert(header::CONTENT_TYPE, mime);
res
}
}
<span class="kw">impl </span>From&lt;String&gt; <span class="kw">for </span>Response&lt;String&gt; {
<span class="kw">fn </span>from(val: String) -&gt; <span class="self">Self </span>{
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::with_body(StatusCode::OK, val);
<span class="kw">let </span>mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
res.headers_mut().insert(header::CONTENT_TYPE, mime);
res
}
}
<span class="kw">impl </span>From&lt;<span class="kw-2">&amp;</span>String&gt; <span class="kw">for </span>Response&lt;String&gt; {
<span class="kw">fn </span>from(val: <span class="kw-2">&amp;</span>String) -&gt; <span class="self">Self </span>{
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::with_body(StatusCode::OK, val.clone());
<span class="kw">let </span>mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
res.headers_mut().insert(header::CONTENT_TYPE, mime);
res
}
}
<span class="kw">impl </span>From&lt;Bytes&gt; <span class="kw">for </span>Response&lt;Bytes&gt; {
<span class="kw">fn </span>from(val: Bytes) -&gt; <span class="self">Self </span>{
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::with_body(StatusCode::OK, val);
<span class="kw">let </span>mime = mime::APPLICATION_OCTET_STREAM.try_into_value().unwrap();
res.headers_mut().insert(header::CONTENT_TYPE, mime);
res
}
}
<span class="kw">impl </span>From&lt;BytesMut&gt; <span class="kw">for </span>Response&lt;BytesMut&gt; {
<span class="kw">fn </span>from(val: BytesMut) -&gt; <span class="self">Self </span>{
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::with_body(StatusCode::OK, val);
<span class="kw">let </span>mime = mime::APPLICATION_OCTET_STREAM.try_into_value().unwrap();
res.headers_mut().insert(header::CONTENT_TYPE, mime);
res
}
}
<span class="kw">impl </span>From&lt;ByteString&gt; <span class="kw">for </span>Response&lt;ByteString&gt; {
<span class="kw">fn </span>from(val: ByteString) -&gt; <span class="self">Self </span>{
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::with_body(StatusCode::OK, val);
<span class="kw">let </span>mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
res.headers_mut().insert(header::CONTENT_TYPE, mime);
res
}
}
<span class="attr">#[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>::{
body::to_bytes,
header::{HeaderValue, CONTENT_TYPE, COOKIE},
};
<span class="attr">#[test]
</span><span class="kw">fn </span>test_debug() {
<span class="kw">let </span>resp = Response::build(StatusCode::OK)
.append_header((COOKIE, HeaderValue::from_static(<span class="string">"cookie1=value1; "</span>)))
.append_header((COOKIE, HeaderValue::from_static(<span class="string">"cookie2=value2; "</span>)))
.finish();
<span class="kw">let </span>dbg = <span class="macro">format!</span>(<span class="string">"{:?}"</span>, resp);
<span class="macro">assert!</span>(dbg.contains(<span class="string">"Response"</span>));
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>test_into_response() {
<span class="kw">let </span>res = Response::from(<span class="string">"test"</span>);
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(
res.headers().get(CONTENT_TYPE).unwrap(),
HeaderValue::from_static(<span class="string">"text/plain; charset=utf-8"</span>)
);
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(to_bytes(res.into_body()).<span class="kw">await</span>.unwrap(), <span class="kw-2">&amp;</span><span class="string">b"test"</span>[..]);
<span class="kw">let </span>res = Response::from(<span class="string">b"test"</span>.as_ref());
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(
res.headers().get(CONTENT_TYPE).unwrap(),
HeaderValue::from_static(<span class="string">"application/octet-stream"</span>)
);
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(to_bytes(res.into_body()).<span class="kw">await</span>.unwrap(), <span class="kw-2">&amp;</span><span class="string">b"test"</span>[..]);
<span class="kw">let </span>res = Response::from(<span class="string">"test"</span>.to_owned());
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(
res.headers().get(CONTENT_TYPE).unwrap(),
HeaderValue::from_static(<span class="string">"text/plain; charset=utf-8"</span>)
);
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(to_bytes(res.into_body()).<span class="kw">await</span>.unwrap(), <span class="kw-2">&amp;</span><span class="string">b"test"</span>[..]);
<span class="kw">let </span>res = Response::from(<span class="string">"test"</span>.to_owned());
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(
res.headers().get(CONTENT_TYPE).unwrap(),
HeaderValue::from_static(<span class="string">"text/plain; charset=utf-8"</span>)
);
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(to_bytes(res.into_body()).<span class="kw">await</span>.unwrap(), <span class="kw-2">&amp;</span><span class="string">b"test"</span>[..]);
<span class="kw">let </span>b = Bytes::from_static(<span class="string">b"test"</span>);
<span class="kw">let </span>res = Response::from(b);
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(
res.headers().get(CONTENT_TYPE).unwrap(),
HeaderValue::from_static(<span class="string">"application/octet-stream"</span>)
);
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(to_bytes(res.into_body()).<span class="kw">await</span>.unwrap(), <span class="kw-2">&amp;</span><span class="string">b"test"</span>[..]);
<span class="kw">let </span>b = Bytes::from_static(<span class="string">b"test"</span>);
<span class="kw">let </span>res = Response::from(b);
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(
res.headers().get(CONTENT_TYPE).unwrap(),
HeaderValue::from_static(<span class="string">"application/octet-stream"</span>)
);
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(to_bytes(res.into_body()).<span class="kw">await</span>.unwrap(), <span class="kw-2">&amp;</span><span class="string">b"test"</span>[..]);
<span class="kw">let </span>b = BytesMut::from(<span class="string">"test"</span>);
<span class="kw">let </span>res = Response::from(b);
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(
res.headers().get(CONTENT_TYPE).unwrap(),
HeaderValue::from_static(<span class="string">"application/octet-stream"</span>)
);
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
<span class="macro">assert_eq!</span>(to_bytes(res.into_body()).<span class="kw">await</span>.unwrap(), <span class="kw-2">&amp;</span><span class="string">b"test"</span>[..]);
}
}
</code></pre></div></section></main></body></html>

File diff suppressed because it is too large Load Diff

749
src/actix_http/test.rs.html Normal file
View File

@ -0,0 +1,749 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/test.rs`."><title>test.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
<a href="#339" id="339">339</a>
<a href="#340" id="340">340</a>
<a href="#341" id="341">341</a>
<a href="#342" id="342">342</a>
<a href="#343" id="343">343</a>
<a href="#344" id="344">344</a>
<a href="#345" id="345">345</a>
<a href="#346" id="346">346</a>
<a href="#347" id="347">347</a>
<a href="#348" id="348">348</a>
<a href="#349" id="349">349</a>
<a href="#350" id="350">350</a>
<a href="#351" id="351">351</a>
<a href="#352" id="352">352</a>
<a href="#353" id="353">353</a>
<a href="#354" id="354">354</a>
<a href="#355" id="355">355</a>
<a href="#356" id="356">356</a>
<a href="#357" id="357">357</a>
<a href="#358" id="358">358</a>
<a href="#359" id="359">359</a>
<a href="#360" id="360">360</a>
<a href="#361" id="361">361</a>
<a href="#362" id="362">362</a>
<a href="#363" id="363">363</a>
<a href="#364" id="364">364</a>
<a href="#365" id="365">365</a>
<a href="#366" id="366">366</a>
<a href="#367" id="367">367</a>
<a href="#368" id="368">368</a>
<a href="#369" id="369">369</a>
<a href="#370" id="370">370</a>
<a href="#371" id="371">371</a>
<a href="#372" id="372">372</a>
<a href="#373" id="373">373</a>
<a href="#374" id="374">374</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Various testing helpers for use in internal and app tests.
</span><span class="kw">use </span>std::{
cell::{Ref, RefCell, RefMut},
io::{<span class="self">self</span>, Read, Write},
pin::Pin,
rc::Rc,
str::FromStr,
task::{Context, Poll},
};
<span class="kw">use </span>actix_codec::{AsyncRead, AsyncWrite, ReadBuf};
<span class="kw">use </span>bytes::{Bytes, BytesMut};
<span class="kw">use </span>http::{Method, Uri, Version};
<span class="kw">use crate</span>::{
header::{HeaderMap, TryIntoHeaderPair},
payload::Payload,
Request,
};
<span class="doccomment">/// Test `Request` builder.
</span><span class="kw">pub struct </span>TestRequest(<span class="prelude-ty">Option</span>&lt;Inner&gt;);
<span class="kw">struct </span>Inner {
version: Version,
method: Method,
uri: Uri,
headers: HeaderMap,
payload: <span class="prelude-ty">Option</span>&lt;Payload&gt;,
}
<span class="kw">impl </span>Default <span class="kw">for </span>TestRequest {
<span class="kw">fn </span>default() -&gt; TestRequest {
TestRequest(<span class="prelude-val">Some</span>(Inner {
method: Method::GET,
uri: Uri::from_str(<span class="string">"/"</span>).unwrap(),
version: Version::HTTP_11,
headers: HeaderMap::new(),
payload: <span class="prelude-val">None</span>,
}))
}
}
<span class="kw">impl </span>TestRequest {
<span class="doccomment">/// Create a default TestRequest and then set its URI.
</span><span class="kw">pub fn </span>with_uri(path: <span class="kw-2">&amp;</span>str) -&gt; TestRequest {
TestRequest::default().uri(path).take()
}
<span class="doccomment">/// Set HTTP version of this request.
</span><span class="kw">pub fn </span>version(<span class="kw-2">&amp;mut </span><span class="self">self</span>, ver: Version) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
parts(<span class="kw-2">&amp;mut </span><span class="self">self</span>.<span class="number">0</span>).version = ver;
<span class="self">self
</span>}
<span class="doccomment">/// Set HTTP method of this request.
</span><span class="kw">pub fn </span>method(<span class="kw-2">&amp;mut </span><span class="self">self</span>, meth: Method) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
parts(<span class="kw-2">&amp;mut </span><span class="self">self</span>.<span class="number">0</span>).method = meth;
<span class="self">self
</span>}
<span class="doccomment">/// Set URI of this request.
///
/// # Panics
/// If provided URI is invalid.
</span><span class="kw">pub fn </span>uri(<span class="kw-2">&amp;mut </span><span class="self">self</span>, path: <span class="kw-2">&amp;</span>str) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
parts(<span class="kw-2">&amp;mut </span><span class="self">self</span>.<span class="number">0</span>).uri = Uri::from_str(path).unwrap();
<span class="self">self
</span>}
<span class="doccomment">/// Insert a header, replacing any that were set with an equivalent field name.
</span><span class="kw">pub fn </span>insert_header(<span class="kw-2">&amp;mut </span><span class="self">self</span>, header: <span class="kw">impl </span>TryIntoHeaderPair) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="kw">match </span>header.try_into_pair() {
<span class="prelude-val">Ok</span>((key, value)) =&gt; {
parts(<span class="kw-2">&amp;mut </span><span class="self">self</span>.<span class="number">0</span>).headers.insert(key, value);
}
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="macro">panic!</span>(<span class="string">"Error inserting test header: {}."</span>, err.into());
}
}
<span class="self">self
</span>}
<span class="doccomment">/// Append a header, keeping any that were set with an equivalent field name.
</span><span class="kw">pub fn </span>append_header(<span class="kw-2">&amp;mut </span><span class="self">self</span>, header: <span class="kw">impl </span>TryIntoHeaderPair) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="kw">match </span>header.try_into_pair() {
<span class="prelude-val">Ok</span>((key, value)) =&gt; {
parts(<span class="kw-2">&amp;mut </span><span class="self">self</span>.<span class="number">0</span>).headers.append(key, value);
}
<span class="prelude-val">Err</span>(err) =&gt; {
<span class="macro">panic!</span>(<span class="string">"Error inserting test header: {}."</span>, err.into());
}
}
<span class="self">self
</span>}
<span class="doccomment">/// Set request payload.
</span><span class="kw">pub fn </span>set_payload(<span class="kw-2">&amp;mut </span><span class="self">self</span>, data: <span class="kw">impl </span>Into&lt;Bytes&gt;) -&gt; <span class="kw-2">&amp;mut </span><span class="self">Self </span>{
<span class="kw">let </span><span class="kw-2">mut </span>payload = <span class="kw">crate</span>::h1::Payload::empty();
payload.unread_data(data.into());
parts(<span class="kw-2">&amp;mut </span><span class="self">self</span>.<span class="number">0</span>).payload = <span class="prelude-val">Some</span>(payload.into());
<span class="self">self
</span>}
<span class="kw">pub fn </span>take(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; TestRequest {
TestRequest(<span class="self">self</span>.<span class="number">0</span>.take())
}
<span class="doccomment">/// Complete request creation and generate `Request` instance.
</span><span class="kw">pub fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; Request {
<span class="kw">let </span>inner = <span class="self">self</span>.<span class="number">0</span>.take().expect(<span class="string">"cannot reuse test request builder"</span>);
<span class="kw">let </span><span class="kw-2">mut </span>req = <span class="kw">if let </span><span class="prelude-val">Some</span>(pl) = inner.payload {
Request::with_payload(pl)
} <span class="kw">else </span>{
Request::with_payload(<span class="kw">crate</span>::h1::Payload::empty().into())
};
<span class="kw">let </span>head = req.head_mut();
head.uri = inner.uri;
head.method = inner.method;
head.version = inner.version;
head.headers = inner.headers;
req
}
}
<span class="attr">#[inline]
</span><span class="kw">fn </span>parts(parts: <span class="kw-2">&amp;mut </span><span class="prelude-ty">Option</span>&lt;Inner&gt;) -&gt; <span class="kw-2">&amp;mut </span>Inner {
parts.as_mut().expect(<span class="string">"cannot reuse test request builder"</span>)
}
<span class="doccomment">/// Async I/O test buffer.
</span><span class="attr">#[derive(Debug)]
</span><span class="kw">pub struct </span>TestBuffer {
<span class="kw">pub </span>read_buf: Rc&lt;RefCell&lt;BytesMut&gt;&gt;,
<span class="kw">pub </span>write_buf: Rc&lt;RefCell&lt;BytesMut&gt;&gt;,
<span class="kw">pub </span>err: <span class="prelude-ty">Option</span>&lt;Rc&lt;io::Error&gt;&gt;,
}
<span class="kw">impl </span>TestBuffer {
<span class="doccomment">/// Create new `TestBuffer` instance with initial read buffer.
</span><span class="kw">pub fn </span>new&lt;T&gt;(data: T) -&gt; <span class="self">Self
</span><span class="kw">where
</span>T: Into&lt;BytesMut&gt;,
{
<span class="self">Self </span>{
read_buf: Rc::new(RefCell::new(data.into())),
write_buf: Rc::new(RefCell::new(BytesMut::new())),
err: <span class="prelude-val">None</span>,
}
}
<span class="comment">// intentionally not using Clone trait
</span><span class="attr">#[allow(dead_code)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <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>{
read_buf: <span class="self">self</span>.read_buf.clone(),
write_buf: <span class="self">self</span>.write_buf.clone(),
err: <span class="self">self</span>.err.clone(),
}
}
<span class="doccomment">/// Create new empty `TestBuffer` instance.
</span><span class="kw">pub fn </span>empty() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(<span class="string">""</span>)
}
<span class="attr">#[allow(dead_code)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>read_buf_slice(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Ref&lt;<span class="lifetime">'_</span>, [u8]&gt; {
Ref::map(<span class="self">self</span>.read_buf.borrow(), |b| b.as_ref())
}
<span class="attr">#[allow(dead_code)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>read_buf_slice_mut(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; RefMut&lt;<span class="lifetime">'_</span>, [u8]&gt; {
RefMut::map(<span class="self">self</span>.read_buf.borrow_mut(), |b| b.as_mut())
}
<span class="attr">#[allow(dead_code)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>write_buf_slice(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Ref&lt;<span class="lifetime">'_</span>, [u8]&gt; {
Ref::map(<span class="self">self</span>.write_buf.borrow(), |b| b.as_ref())
}
<span class="attr">#[allow(dead_code)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>write_buf_slice_mut(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; RefMut&lt;<span class="lifetime">'_</span>, [u8]&gt; {
RefMut::map(<span class="self">self</span>.write_buf.borrow_mut(), |b| b.as_mut())
}
<span class="attr">#[allow(dead_code)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>take_write_buf(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Bytes {
<span class="self">self</span>.write_buf.borrow_mut().split().freeze()
}
<span class="doccomment">/// Add data to read buffer.
</span><span class="kw">pub fn </span>extend_read_buf&lt;T: AsRef&lt;[u8]&gt;&gt;(<span class="kw-2">&amp;mut </span><span class="self">self</span>, data: T) {
<span class="self">self</span>.read_buf.borrow_mut().extend_from_slice(data.as_ref())
}
}
<span class="kw">impl </span>io::Read <span class="kw">for </span>TestBuffer {
<span class="kw">fn </span>read(<span class="kw-2">&amp;mut </span><span class="self">self</span>, dst: <span class="kw-2">&amp;mut </span>[u8]) -&gt; <span class="prelude-ty">Result</span>&lt;usize, io::Error&gt; {
<span class="kw">if </span><span class="self">self</span>.read_buf.borrow().is_empty() {
<span class="kw">if </span><span class="self">self</span>.err.is_some() {
<span class="prelude-val">Err</span>(Rc::try_unwrap(<span class="self">self</span>.err.take().unwrap()).unwrap())
} <span class="kw">else </span>{
<span class="prelude-val">Err</span>(io::Error::new(io::ErrorKind::WouldBlock, <span class="string">""</span>))
}
} <span class="kw">else </span>{
<span class="kw">let </span>size = std::cmp::min(<span class="self">self</span>.read_buf.borrow().len(), dst.len());
<span class="kw">let </span>b = <span class="self">self</span>.read_buf.borrow_mut().split_to(size);
dst[..size].copy_from_slice(<span class="kw-2">&amp;</span>b);
<span class="prelude-val">Ok</span>(size)
}
}
}
<span class="kw">impl </span>io::Write <span class="kw">for </span>TestBuffer {
<span class="kw">fn </span>write(<span class="kw-2">&amp;mut </span><span class="self">self</span>, buf: <span class="kw-2">&amp;</span>[u8]) -&gt; io::Result&lt;usize&gt; {
<span class="self">self</span>.write_buf.borrow_mut().extend(buf);
<span class="prelude-val">Ok</span>(buf.len())
}
<span class="kw">fn </span>flush(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; io::Result&lt;()&gt; {
<span class="prelude-val">Ok</span>(())
}
}
<span class="kw">impl </span>AsyncRead <span class="kw">for </span>TestBuffer {
<span class="kw">fn </span>poll_read(
<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;,
<span class="kw">_</span>: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
buf: <span class="kw-2">&amp;mut </span>ReadBuf&lt;<span class="lifetime">'_</span>&gt;,
) -&gt; Poll&lt;io::Result&lt;()&gt;&gt; {
<span class="kw">let </span>dst = buf.initialize_unfilled();
<span class="kw">let </span>res = <span class="self">self</span>.get_mut().read(dst).map(|n| buf.advance(n));
Poll::Ready(res)
}
}
<span class="kw">impl </span>AsyncWrite <span class="kw">for </span>TestBuffer {
<span class="kw">fn </span>poll_write(
<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;,
<span class="kw">_</span>: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
buf: <span class="kw-2">&amp;</span>[u8],
) -&gt; Poll&lt;io::Result&lt;usize&gt;&gt; {
Poll::Ready(<span class="self">self</span>.get_mut().write(buf))
}
<span class="kw">fn </span>poll_flush(<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, <span class="kw">_</span>: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;io::Result&lt;()&gt;&gt; {
Poll::Ready(<span class="prelude-val">Ok</span>(()))
}
<span class="kw">fn </span>poll_shutdown(<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, <span class="kw">_</span>: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;io::Result&lt;()&gt;&gt; {
Poll::Ready(<span class="prelude-val">Ok</span>(()))
}
}
<span class="doccomment">/// Async I/O test buffer with ability to incrementally add to the read buffer.
</span><span class="attr">#[derive(Clone)]
</span><span class="kw">pub struct </span>TestSeqBuffer(Rc&lt;RefCell&lt;TestSeqInner&gt;&gt;);
<span class="kw">impl </span>TestSeqBuffer {
<span class="doccomment">/// Create new `TestBuffer` instance with initial read buffer.
</span><span class="kw">pub fn </span>new&lt;T&gt;(data: T) -&gt; <span class="self">Self
</span><span class="kw">where
</span>T: Into&lt;BytesMut&gt;,
{
<span class="self">Self</span>(Rc::new(RefCell::new(TestSeqInner {
read_buf: data.into(),
write_buf: BytesMut::new(),
err: <span class="prelude-val">None</span>,
})))
}
<span class="doccomment">/// Create new empty `TestBuffer` instance.
</span><span class="kw">pub fn </span>empty() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new(BytesMut::new())
}
<span class="kw">pub fn </span>read_buf(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Ref&lt;<span class="lifetime">'_</span>, BytesMut&gt; {
Ref::map(<span class="self">self</span>.<span class="number">0</span>.borrow(), |inner| <span class="kw-2">&amp;</span>inner.read_buf)
}
<span class="kw">pub fn </span>write_buf(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Ref&lt;<span class="lifetime">'_</span>, BytesMut&gt; {
Ref::map(<span class="self">self</span>.<span class="number">0</span>.borrow(), |inner| <span class="kw-2">&amp;</span>inner.write_buf)
}
<span class="kw">pub fn </span>err(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Ref&lt;<span class="lifetime">'_</span>, <span class="prelude-ty">Option</span>&lt;io::Error&gt;&gt; {
Ref::map(<span class="self">self</span>.<span class="number">0</span>.borrow(), |inner| <span class="kw-2">&amp;</span>inner.err)
}
<span class="doccomment">/// Add data to read buffer.
</span><span class="kw">pub fn </span>extend_read_buf&lt;T: AsRef&lt;[u8]&gt;&gt;(<span class="kw-2">&amp;mut </span><span class="self">self</span>, data: T) {
<span class="self">self</span>.<span class="number">0
</span>.borrow_mut()
.read_buf
.extend_from_slice(data.as_ref())
}
}
<span class="kw">pub struct </span>TestSeqInner {
read_buf: BytesMut,
write_buf: BytesMut,
err: <span class="prelude-ty">Option</span>&lt;io::Error&gt;,
}
<span class="kw">impl </span>io::Read <span class="kw">for </span>TestSeqBuffer {
<span class="kw">fn </span>read(<span class="kw-2">&amp;mut </span><span class="self">self</span>, dst: <span class="kw-2">&amp;mut </span>[u8]) -&gt; <span class="prelude-ty">Result</span>&lt;usize, io::Error&gt; {
<span class="kw">if </span><span class="self">self</span>.<span class="number">0</span>.borrow().read_buf.is_empty() {
<span class="kw">if </span><span class="self">self</span>.<span class="number">0</span>.borrow().err.is_some() {
<span class="prelude-val">Err</span>(<span class="self">self</span>.<span class="number">0</span>.borrow_mut().err.take().unwrap())
} <span class="kw">else </span>{
<span class="prelude-val">Err</span>(io::Error::new(io::ErrorKind::WouldBlock, <span class="string">""</span>))
}
} <span class="kw">else </span>{
<span class="kw">let </span>size = std::cmp::min(<span class="self">self</span>.<span class="number">0</span>.borrow().read_buf.len(), dst.len());
<span class="kw">let </span>b = <span class="self">self</span>.<span class="number">0</span>.borrow_mut().read_buf.split_to(size);
dst[..size].copy_from_slice(<span class="kw-2">&amp;</span>b);
<span class="prelude-val">Ok</span>(size)
}
}
}
<span class="kw">impl </span>io::Write <span class="kw">for </span>TestSeqBuffer {
<span class="kw">fn </span>write(<span class="kw-2">&amp;mut </span><span class="self">self</span>, buf: <span class="kw-2">&amp;</span>[u8]) -&gt; io::Result&lt;usize&gt; {
<span class="self">self</span>.<span class="number">0</span>.borrow_mut().write_buf.extend(buf);
<span class="prelude-val">Ok</span>(buf.len())
}
<span class="kw">fn </span>flush(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; io::Result&lt;()&gt; {
<span class="prelude-val">Ok</span>(())
}
}
<span class="kw">impl </span>AsyncRead <span class="kw">for </span>TestSeqBuffer {
<span class="kw">fn </span>poll_read(
<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;,
<span class="kw">_</span>: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
buf: <span class="kw-2">&amp;mut </span>ReadBuf&lt;<span class="lifetime">'_</span>&gt;,
) -&gt; Poll&lt;io::Result&lt;()&gt;&gt; {
<span class="kw">let </span>dst = buf.initialize_unfilled();
<span class="kw">let </span>r = <span class="self">self</span>.get_mut().read(dst);
<span class="kw">match </span>r {
<span class="prelude-val">Ok</span>(n) =&gt; {
buf.advance(n);
Poll::Ready(<span class="prelude-val">Ok</span>(()))
}
<span class="prelude-val">Err</span>(err) <span class="kw">if </span>err.kind() == io::ErrorKind::WouldBlock =&gt; Poll::Pending,
<span class="prelude-val">Err</span>(err) =&gt; Poll::Ready(<span class="prelude-val">Err</span>(err)),
}
}
}
<span class="kw">impl </span>AsyncWrite <span class="kw">for </span>TestSeqBuffer {
<span class="kw">fn </span>poll_write(
<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;,
<span class="kw">_</span>: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;,
buf: <span class="kw-2">&amp;</span>[u8],
) -&gt; Poll&lt;io::Result&lt;usize&gt;&gt; {
Poll::Ready(<span class="self">self</span>.get_mut().write(buf))
}
<span class="kw">fn </span>poll_flush(<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, <span class="kw">_</span>: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;io::Result&lt;()&gt;&gt; {
Poll::Ready(<span class="prelude-val">Ok</span>(()))
}
<span class="kw">fn </span>poll_shutdown(<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, <span class="kw">_</span>: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;io::Result&lt;()&gt;&gt; {
Poll::Ready(<span class="prelude-val">Ok</span>(()))
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,605 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/ws/codec.rs`."><title>codec.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>bitflags::bitflags;
<span class="kw">use </span>bytes::{Bytes, BytesMut};
<span class="kw">use </span>bytestring::ByteString;
<span class="kw">use </span>tokio_util::codec::{Decoder, Encoder};
<span class="kw">use </span>tracing::error;
<span class="kw">use super</span>::{
frame::Parser,
proto::{CloseReason, OpCode},
ProtocolError,
};
<span class="doccomment">/// A WebSocket message.
</span><span class="attr">#[derive(Debug, PartialEq, Eq)]
</span><span class="kw">pub enum </span>Message {
<span class="doccomment">/// Text message.
</span>Text(ByteString),
<span class="doccomment">/// Binary message.
</span>Binary(Bytes),
<span class="doccomment">/// Continuation.
</span>Continuation(Item),
<span class="doccomment">/// Ping message.
</span>Ping(Bytes),
<span class="doccomment">/// Pong message.
</span>Pong(Bytes),
<span class="doccomment">/// Close message with optional reason.
</span>Close(<span class="prelude-ty">Option</span>&lt;CloseReason&gt;),
<span class="doccomment">/// No-op. Useful for low-level services.
</span>Nop,
}
<span class="doccomment">/// A WebSocket frame.
</span><span class="attr">#[derive(Debug, PartialEq, Eq)]
</span><span class="kw">pub enum </span>Frame {
<span class="doccomment">/// Text frame. Note that the codec does not validate UTF-8 encoding.
</span>Text(Bytes),
<span class="doccomment">/// Binary frame.
</span>Binary(Bytes),
<span class="doccomment">/// Continuation.
</span>Continuation(Item),
<span class="doccomment">/// Ping message.
</span>Ping(Bytes),
<span class="doccomment">/// Pong message.
</span>Pong(Bytes),
<span class="doccomment">/// Close message with optional reason.
</span>Close(<span class="prelude-ty">Option</span>&lt;CloseReason&gt;),
}
<span class="doccomment">/// A WebSocket continuation item.
</span><span class="attr">#[derive(Debug, PartialEq, Eq)]
</span><span class="kw">pub enum </span>Item {
FirstText(Bytes),
FirstBinary(Bytes),
Continue(Bytes),
Last(Bytes),
}
<span class="doccomment">/// WebSocket protocol codec.
</span><span class="attr">#[derive(Debug, Clone)]
</span><span class="kw">pub struct </span>Codec {
flags: Flags,
max_size: usize,
}
<span class="macro">bitflags!</span> {
<span class="attr">#[derive(Debug, Clone, Copy)]
</span><span class="kw">struct </span>Flags: u8 {
<span class="kw">const </span>SERVER = <span class="number">0b0000_0001</span>;
<span class="kw">const </span>CONTINUATION = <span class="number">0b0000_0010</span>;
<span class="kw">const </span>W_CONTINUATION = <span class="number">0b0000_0100</span>;
}
}
<span class="kw">impl </span>Codec {
<span class="doccomment">/// Create new WebSocket frames decoder.
</span><span class="kw">pub const fn </span>new() -&gt; Codec {
Codec {
max_size: <span class="number">65_536</span>,
flags: Flags::SERVER,
}
}
<span class="doccomment">/// Set max frame size.
///
/// By default max size is set to 64KiB.
</span><span class="attr">#[must_use = <span class="string">"This returns the a new Codec, without modifying the original."</span>]
</span><span class="kw">pub fn </span>max_size(<span class="kw-2">mut </span><span class="self">self</span>, size: usize) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.max_size = size;
<span class="self">self
</span>}
<span class="doccomment">/// Set decoder to client mode.
///
/// By default decoder works in server mode.
</span><span class="attr">#[must_use = <span class="string">"This returns the a new Codec, without modifying the original."</span>]
</span><span class="kw">pub fn </span>client_mode(<span class="kw-2">mut </span><span class="self">self</span>) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.flags.remove(Flags::SERVER);
<span class="self">self
</span>}
}
<span class="kw">impl </span>Default <span class="kw">for </span>Codec {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::new()
}
}
<span class="kw">impl </span>Encoder&lt;Message&gt; <span class="kw">for </span>Codec {
<span class="kw">type </span>Error = ProtocolError;
<span class="kw">fn </span>encode(<span class="kw-2">&amp;mut </span><span class="self">self</span>, item: Message, dst: <span class="kw-2">&amp;mut </span>BytesMut) -&gt; <span class="prelude-ty">Result</span>&lt;(), <span class="self">Self</span>::Error&gt; {
<span class="kw">match </span>item {
Message::Text(txt) =&gt; Parser::write_message(
dst,
txt,
OpCode::Text,
<span class="bool-val">true</span>,
!<span class="self">self</span>.flags.contains(Flags::SERVER),
),
Message::Binary(bin) =&gt; Parser::write_message(
dst,
bin,
OpCode::Binary,
<span class="bool-val">true</span>,
!<span class="self">self</span>.flags.contains(Flags::SERVER),
),
Message::Ping(txt) =&gt; Parser::write_message(
dst,
txt,
OpCode::Ping,
<span class="bool-val">true</span>,
!<span class="self">self</span>.flags.contains(Flags::SERVER),
),
Message::Pong(txt) =&gt; Parser::write_message(
dst,
txt,
OpCode::Pong,
<span class="bool-val">true</span>,
!<span class="self">self</span>.flags.contains(Flags::SERVER),
),
Message::Close(reason) =&gt; {
Parser::write_close(dst, reason, !<span class="self">self</span>.flags.contains(Flags::SERVER))
}
Message::Continuation(cont) =&gt; <span class="kw">match </span>cont {
Item::FirstText(data) =&gt; {
<span class="kw">if </span><span class="self">self</span>.flags.contains(Flags::W_CONTINUATION) {
<span class="kw">return </span><span class="prelude-val">Err</span>(ProtocolError::ContinuationStarted);
} <span class="kw">else </span>{
<span class="self">self</span>.flags.insert(Flags::W_CONTINUATION);
Parser::write_message(
dst,
<span class="kw-2">&amp;</span>data[..],
OpCode::Text,
<span class="bool-val">false</span>,
!<span class="self">self</span>.flags.contains(Flags::SERVER),
)
}
}
Item::FirstBinary(data) =&gt; {
<span class="kw">if </span><span class="self">self</span>.flags.contains(Flags::W_CONTINUATION) {
<span class="kw">return </span><span class="prelude-val">Err</span>(ProtocolError::ContinuationStarted);
} <span class="kw">else </span>{
<span class="self">self</span>.flags.insert(Flags::W_CONTINUATION);
Parser::write_message(
dst,
<span class="kw-2">&amp;</span>data[..],
OpCode::Binary,
<span class="bool-val">false</span>,
!<span class="self">self</span>.flags.contains(Flags::SERVER),
)
}
}
Item::Continue(data) =&gt; {
<span class="kw">if </span><span class="self">self</span>.flags.contains(Flags::W_CONTINUATION) {
Parser::write_message(
dst,
<span class="kw-2">&amp;</span>data[..],
OpCode::Continue,
<span class="bool-val">false</span>,
!<span class="self">self</span>.flags.contains(Flags::SERVER),
)
} <span class="kw">else </span>{
<span class="kw">return </span><span class="prelude-val">Err</span>(ProtocolError::ContinuationNotStarted);
}
}
Item::Last(data) =&gt; {
<span class="kw">if </span><span class="self">self</span>.flags.contains(Flags::W_CONTINUATION) {
<span class="self">self</span>.flags.remove(Flags::W_CONTINUATION);
Parser::write_message(
dst,
<span class="kw-2">&amp;</span>data[..],
OpCode::Continue,
<span class="bool-val">true</span>,
!<span class="self">self</span>.flags.contains(Flags::SERVER),
)
} <span class="kw">else </span>{
<span class="kw">return </span><span class="prelude-val">Err</span>(ProtocolError::ContinuationNotStarted);
}
}
},
Message::Nop =&gt; {}
}
<span class="prelude-val">Ok</span>(())
}
}
<span class="kw">impl </span>Decoder <span class="kw">for </span>Codec {
<span class="kw">type </span>Item = Frame;
<span class="kw">type </span>Error = ProtocolError;
<span class="kw">fn </span>decode(<span class="kw-2">&amp;mut </span><span class="self">self</span>, src: <span class="kw-2">&amp;mut </span>BytesMut) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>::Item&gt;, <span class="self">Self</span>::Error&gt; {
<span class="kw">match </span>Parser::parse(src, <span class="self">self</span>.flags.contains(Flags::SERVER), <span class="self">self</span>.max_size) {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>((finished, opcode, payload))) =&gt; {
<span class="comment">// continuation is not supported
</span><span class="kw">if </span>!finished {
<span class="kw">return match </span>opcode {
OpCode::Continue =&gt; {
<span class="kw">if </span><span class="self">self</span>.flags.contains(Flags::CONTINUATION) {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Frame::Continuation(Item::Continue(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))))
} <span class="kw">else </span>{
<span class="prelude-val">Err</span>(ProtocolError::ContinuationNotStarted)
}
}
OpCode::Binary =&gt; {
<span class="kw">if </span>!<span class="self">self</span>.flags.contains(Flags::CONTINUATION) {
<span class="self">self</span>.flags.insert(Flags::CONTINUATION);
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Frame::Continuation(Item::FirstBinary(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))))
} <span class="kw">else </span>{
<span class="prelude-val">Err</span>(ProtocolError::ContinuationStarted)
}
}
OpCode::Text =&gt; {
<span class="kw">if </span>!<span class="self">self</span>.flags.contains(Flags::CONTINUATION) {
<span class="self">self</span>.flags.insert(Flags::CONTINUATION);
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Frame::Continuation(Item::FirstText(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))))
} <span class="kw">else </span>{
<span class="prelude-val">Err</span>(ProtocolError::ContinuationStarted)
}
}
<span class="kw">_ </span>=&gt; {
<span class="macro">error!</span>(<span class="string">"Unfinished fragment {:?}"</span>, opcode);
<span class="prelude-val">Err</span>(ProtocolError::ContinuationFragment(opcode))
}
};
}
<span class="kw">match </span>opcode {
OpCode::Continue =&gt; {
<span class="kw">if </span><span class="self">self</span>.flags.contains(Flags::CONTINUATION) {
<span class="self">self</span>.flags.remove(Flags::CONTINUATION);
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Frame::Continuation(Item::Last(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))))
} <span class="kw">else </span>{
<span class="prelude-val">Err</span>(ProtocolError::ContinuationNotStarted)
}
}
OpCode::Bad =&gt; <span class="prelude-val">Err</span>(ProtocolError::BadOpCode),
OpCode::Close =&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>pl) = payload {
<span class="kw">let </span>close_reason = Parser::parse_close_payload(pl);
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Frame::Close(close_reason)))
} <span class="kw">else </span>{
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Frame::Close(<span class="prelude-val">None</span>)))
}
}
OpCode::Ping =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Frame::Ping(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))),
OpCode::Pong =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Frame::Pong(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))),
OpCode::Binary =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Frame::Binary(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))),
OpCode::Text =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Frame::Text(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))),
}
}
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>),
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
}
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,879 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/ws/dispatcher.rs`."><title>dispatcher.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
<a href="#339" id="339">339</a>
<a href="#340" id="340">340</a>
<a href="#341" id="341">341</a>
<a href="#342" id="342">342</a>
<a href="#343" id="343">343</a>
<a href="#344" id="344">344</a>
<a href="#345" id="345">345</a>
<a href="#346" id="346">346</a>
<a href="#347" id="347">347</a>
<a href="#348" id="348">348</a>
<a href="#349" id="349">349</a>
<a href="#350" id="350">350</a>
<a href="#351" id="351">351</a>
<a href="#352" id="352">352</a>
<a href="#353" id="353">353</a>
<a href="#354" id="354">354</a>
<a href="#355" id="355">355</a>
<a href="#356" id="356">356</a>
<a href="#357" id="357">357</a>
<a href="#358" id="358">358</a>
<a href="#359" id="359">359</a>
<a href="#360" id="360">360</a>
<a href="#361" id="361">361</a>
<a href="#362" id="362">362</a>
<a href="#363" id="363">363</a>
<a href="#364" id="364">364</a>
<a href="#365" id="365">365</a>
<a href="#366" id="366">366</a>
<a href="#367" id="367">367</a>
<a href="#368" id="368">368</a>
<a href="#369" id="369">369</a>
<a href="#370" id="370">370</a>
<a href="#371" id="371">371</a>
<a href="#372" id="372">372</a>
<a href="#373" id="373">373</a>
<a href="#374" id="374">374</a>
<a href="#375" id="375">375</a>
<a href="#376" id="376">376</a>
<a href="#377" id="377">377</a>
<a href="#378" id="378">378</a>
<a href="#379" id="379">379</a>
<a href="#380" id="380">380</a>
<a href="#381" id="381">381</a>
<a href="#382" id="382">382</a>
<a href="#383" id="383">383</a>
<a href="#384" id="384">384</a>
<a href="#385" id="385">385</a>
<a href="#386" id="386">386</a>
<a href="#387" id="387">387</a>
<a href="#388" id="388">388</a>
<a href="#389" id="389">389</a>
<a href="#390" id="390">390</a>
<a href="#391" id="391">391</a>
<a href="#392" id="392">392</a>
<a href="#393" id="393">393</a>
<a href="#394" id="394">394</a>
<a href="#395" id="395">395</a>
<a href="#396" id="396">396</a>
<a href="#397" id="397">397</a>
<a href="#398" id="398">398</a>
<a href="#399" id="399">399</a>
<a href="#400" id="400">400</a>
<a href="#401" id="401">401</a>
<a href="#402" id="402">402</a>
<a href="#403" id="403">403</a>
<a href="#404" id="404">404</a>
<a href="#405" id="405">405</a>
<a href="#406" id="406">406</a>
<a href="#407" id="407">407</a>
<a href="#408" id="408">408</a>
<a href="#409" id="409">409</a>
<a href="#410" id="410">410</a>
<a href="#411" id="411">411</a>
<a href="#412" id="412">412</a>
<a href="#413" id="413">413</a>
<a href="#414" id="414">414</a>
<a href="#415" id="415">415</a>
<a href="#416" id="416">416</a>
<a href="#417" id="417">417</a>
<a href="#418" id="418">418</a>
<a href="#419" id="419">419</a>
<a href="#420" id="420">420</a>
<a href="#421" id="421">421</a>
<a href="#422" id="422">422</a>
<a href="#423" id="423">423</a>
<a href="#424" id="424">424</a>
<a href="#425" id="425">425</a>
<a href="#426" id="426">426</a>
<a href="#427" id="427">427</a>
<a href="#428" id="428">428</a>
<a href="#429" id="429">429</a>
<a href="#430" id="430">430</a>
<a href="#431" id="431">431</a>
<a href="#432" id="432">432</a>
<a href="#433" id="433">433</a>
<a href="#434" id="434">434</a>
<a href="#435" id="435">435</a>
<a href="#436" id="436">436</a>
<a href="#437" id="437">437</a>
<a href="#438" id="438">438</a>
<a href="#439" id="439">439</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>actix_codec::{AsyncRead, AsyncWrite, Framed};
<span class="kw">use </span>actix_service::{IntoService, Service};
<span class="kw">use </span>pin_project_lite::pin_project;
<span class="kw">use super</span>::{Codec, Frame, Message};
<span class="macro">pin_project!</span> {
<span class="kw">pub struct </span>Dispatcher&lt;S, T&gt;
<span class="kw">where
</span>S: Service&lt;Frame, Response = Message&gt;,
S: <span class="lifetime">'static</span>,
T: AsyncRead,
T: AsyncWrite,
{
<span class="attr">#[pin]
</span>inner: inner::Dispatcher&lt;S, T, Codec, Message&gt;,
}
}
<span class="kw">impl</span>&lt;S, T&gt; Dispatcher&lt;S, T&gt;
<span class="kw">where
</span>T: AsyncRead + AsyncWrite,
S: Service&lt;Frame, Response = Message&gt;,
S::Future: <span class="lifetime">'static</span>,
S::Error: <span class="lifetime">'static</span>,
{
<span class="kw">pub fn </span>new&lt;F: IntoService&lt;S, Frame&gt;&gt;(io: T, service: F) -&gt; <span class="self">Self </span>{
Dispatcher {
inner: inner::Dispatcher::new(Framed::new(io, Codec::new()), service),
}
}
<span class="kw">pub fn </span>with&lt;F: IntoService&lt;S, Frame&gt;&gt;(framed: Framed&lt;T, Codec&gt;, service: F) -&gt; <span class="self">Self </span>{
Dispatcher {
inner: inner::Dispatcher::new(framed, service),
}
}
}
<span class="kw">impl</span>&lt;S, T&gt; Future <span class="kw">for </span>Dispatcher&lt;S, T&gt;
<span class="kw">where
</span>T: AsyncRead + AsyncWrite,
S: Service&lt;Frame, Response = Message&gt;,
S::Future: <span class="lifetime">'static</span>,
S::Error: <span class="lifetime">'static</span>,
{
<span class="kw">type </span>Output = <span class="prelude-ty">Result</span>&lt;(), inner::DispatcherError&lt;S::Error, Codec, Message&gt;&gt;;
<span class="kw">fn </span>poll(<span class="self">self</span>: Pin&lt;<span class="kw-2">&amp;mut </span><span class="self">Self</span>&gt;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;<span class="self">Self</span>::Output&gt; {
<span class="self">self</span>.project().inner.poll(cx)
}
}
<span class="doccomment">/// Framed dispatcher service and related utilities.
</span><span class="kw">mod </span>inner {
<span class="comment">// allow dead code since this mod was ripped from actix-utils
</span><span class="attr">#![allow(dead_code)]
</span><span class="kw">use </span>core::{
fmt,
future::Future,
mem,
pin::Pin,
task::{Context, Poll},
};
<span class="kw">use </span>actix_codec::Framed;
<span class="kw">use </span>actix_service::{IntoService, Service};
<span class="kw">use </span>futures_core::stream::Stream;
<span class="kw">use </span>local_channel::mpsc;
<span class="kw">use </span>pin_project_lite::pin_project;
<span class="kw">use </span>tokio::io::{AsyncRead, AsyncWrite};
<span class="kw">use </span>tokio_util::codec::{Decoder, Encoder};
<span class="kw">use </span>tracing::debug;
<span class="kw">use crate</span>::{body::BoxBody, Response};
<span class="doccomment">/// Framed transport errors
</span><span class="kw">pub enum </span>DispatcherError&lt;E, U, I&gt;
<span class="kw">where
</span>U: Encoder&lt;I&gt; + Decoder,
{
<span class="doccomment">/// Inner service error.
</span>Service(E),
<span class="doccomment">/// Frame encoding error.
</span>Encoder(&lt;U <span class="kw">as </span>Encoder&lt;I&gt;&gt;::Error),
<span class="doccomment">/// Frame decoding error.
</span>Decoder(&lt;U <span class="kw">as </span>Decoder&gt;::Error),
}
<span class="kw">impl</span>&lt;E, U, I&gt; From&lt;E&gt; <span class="kw">for </span>DispatcherError&lt;E, U, I&gt;
<span class="kw">where
</span>U: Encoder&lt;I&gt; + Decoder,
{
<span class="kw">fn </span>from(err: E) -&gt; <span class="self">Self </span>{
DispatcherError::Service(err)
}
}
<span class="kw">impl</span>&lt;E, U, I&gt; fmt::Debug <span class="kw">for </span>DispatcherError&lt;E, U, I&gt;
<span class="kw">where
</span>E: fmt::Debug,
U: Encoder&lt;I&gt; + Decoder,
&lt;U <span class="kw">as </span>Encoder&lt;I&gt;&gt;::Error: fmt::Debug,
&lt;U <span class="kw">as </span>Decoder&gt;::Error: fmt::Debug,
{
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, fmt: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; fmt::Result {
<span class="kw">match </span><span class="kw-2">*</span><span class="self">self </span>{
DispatcherError::Service(<span class="kw-2">ref </span>e) =&gt; {
<span class="macro">write!</span>(fmt, <span class="string">"DispatcherError::Service({:?})"</span>, e)
}
DispatcherError::Encoder(<span class="kw-2">ref </span>e) =&gt; {
<span class="macro">write!</span>(fmt, <span class="string">"DispatcherError::Encoder({:?})"</span>, e)
}
DispatcherError::Decoder(<span class="kw-2">ref </span>e) =&gt; {
<span class="macro">write!</span>(fmt, <span class="string">"DispatcherError::Decoder({:?})"</span>, e)
}
}
}
}
<span class="kw">impl</span>&lt;E, U, I&gt; fmt::Display <span class="kw">for </span>DispatcherError&lt;E, U, I&gt;
<span class="kw">where
</span>E: fmt::Display,
U: Encoder&lt;I&gt; + Decoder,
&lt;U <span class="kw">as </span>Encoder&lt;I&gt;&gt;::Error: fmt::Debug,
&lt;U <span class="kw">as </span>Decoder&gt;::Error: fmt::Debug,
{
<span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, fmt: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; fmt::Result {
<span class="kw">match </span><span class="kw-2">*</span><span class="self">self </span>{
DispatcherError::Service(<span class="kw-2">ref </span>e) =&gt; <span class="macro">write!</span>(fmt, <span class="string">"{}"</span>, e),
DispatcherError::Encoder(<span class="kw-2">ref </span>e) =&gt; <span class="macro">write!</span>(fmt, <span class="string">"{:?}"</span>, e),
DispatcherError::Decoder(<span class="kw-2">ref </span>e) =&gt; <span class="macro">write!</span>(fmt, <span class="string">"{:?}"</span>, e),
}
}
}
<span class="kw">impl</span>&lt;E, U, I&gt; From&lt;DispatcherError&lt;E, U, I&gt;&gt; <span class="kw">for </span>Response&lt;BoxBody&gt;
<span class="kw">where
</span>E: fmt::Debug + fmt::Display,
U: Encoder&lt;I&gt; + Decoder,
&lt;U <span class="kw">as </span>Encoder&lt;I&gt;&gt;::Error: fmt::Debug,
&lt;U <span class="kw">as </span>Decoder&gt;::Error: fmt::Debug,
{
<span class="kw">fn </span>from(err: DispatcherError&lt;E, U, I&gt;) -&gt; <span class="self">Self </span>{
Response::internal_server_error().set_body(BoxBody::new(err.to_string()))
}
}
<span class="doccomment">/// Message type wrapper for signalling end of message stream.
</span><span class="kw">pub enum </span>Message&lt;T&gt; {
<span class="doccomment">/// Message item.
</span>Item(T),
<span class="doccomment">/// Signal from service to flush all messages and stop processing.
</span>Close,
}
<span class="macro">pin_project!</span> {
<span class="doccomment">/// A future that reads frames from a [`Framed`] object and passes them to a [`Service`].
</span><span class="kw">pub struct </span>Dispatcher&lt;S, T, U, I&gt;
<span class="kw">where
</span>S: Service&lt;&lt;U <span class="kw">as </span>Decoder&gt;::Item, Response = I&gt;,
S::Error: <span class="lifetime">'static</span>,
S::Future: <span class="lifetime">'static</span>,
T: AsyncRead,
T: AsyncWrite,
U: Encoder&lt;I&gt;,
U: Decoder,
I: <span class="lifetime">'static</span>,
&lt;U <span class="kw">as </span>Encoder&lt;I&gt;&gt;::Error: fmt::Debug,
{
service: S,
state: State&lt;S, U, I&gt;,
<span class="attr">#[pin]
</span>framed: Framed&lt;T, U&gt;,
rx: mpsc::Receiver&lt;<span class="prelude-ty">Result</span>&lt;Message&lt;I&gt;, S::Error&gt;&gt;,
tx: mpsc::Sender&lt;<span class="prelude-ty">Result</span>&lt;Message&lt;I&gt;, S::Error&gt;&gt;,
}
}
<span class="kw">enum </span>State&lt;S, U, I&gt;
<span class="kw">where
</span>S: Service&lt;&lt;U <span class="kw">as </span>Decoder&gt;::Item&gt;,
U: Encoder&lt;I&gt; + Decoder,
{
Processing,
Error(DispatcherError&lt;S::Error, U, I&gt;),
FramedError(DispatcherError&lt;S::Error, U, I&gt;),
FlushAndStop,
Stopping,
}
<span class="kw">impl</span>&lt;S, U, I&gt; State&lt;S, U, I&gt;
<span class="kw">where
</span>S: Service&lt;&lt;U <span class="kw">as </span>Decoder&gt;::Item&gt;,
U: Encoder&lt;I&gt; + Decoder,
{
<span class="kw">fn </span>take_error(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; DispatcherError&lt;S::Error, U, I&gt; {
<span class="kw">match </span>mem::replace(<span class="self">self</span>, State::Processing) {
State::Error(err) =&gt; err,
<span class="kw">_ </span>=&gt; <span class="macro">panic!</span>(),
}
}
<span class="kw">fn </span>take_framed_error(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; DispatcherError&lt;S::Error, U, I&gt; {
<span class="kw">match </span>mem::replace(<span class="self">self</span>, State::Processing) {
State::FramedError(err) =&gt; err,
<span class="kw">_ </span>=&gt; <span class="macro">panic!</span>(),
}
}
}
<span class="kw">impl</span>&lt;S, T, U, I&gt; Dispatcher&lt;S, T, U, I&gt;
<span class="kw">where
</span>S: Service&lt;&lt;U <span class="kw">as </span>Decoder&gt;::Item, Response = I&gt;,
S::Error: <span class="lifetime">'static</span>,
S::Future: <span class="lifetime">'static</span>,
T: AsyncRead + AsyncWrite,
U: Decoder + Encoder&lt;I&gt;,
I: <span class="lifetime">'static</span>,
&lt;U <span class="kw">as </span>Decoder&gt;::Error: fmt::Debug,
&lt;U <span class="kw">as </span>Encoder&lt;I&gt;&gt;::Error: fmt::Debug,
{
<span class="doccomment">/// Create new `Dispatcher`.
</span><span class="kw">pub fn </span>new&lt;F&gt;(framed: Framed&lt;T, U&gt;, service: F) -&gt; <span class="self">Self
</span><span class="kw">where
</span>F: IntoService&lt;S, &lt;U <span class="kw">as </span>Decoder&gt;::Item&gt;,
{
<span class="kw">let </span>(tx, rx) = mpsc::channel();
Dispatcher {
framed,
rx,
tx,
service: service.into_service(),
state: State::Processing,
}
}
<span class="doccomment">/// Construct new `Dispatcher` instance with customer `mpsc::Receiver`
</span><span class="kw">pub fn </span>with_rx&lt;F&gt;(
framed: Framed&lt;T, U&gt;,
service: F,
rx: mpsc::Receiver&lt;<span class="prelude-ty">Result</span>&lt;Message&lt;I&gt;, S::Error&gt;&gt;,
) -&gt; <span class="self">Self
</span><span class="kw">where
</span>F: IntoService&lt;S, &lt;U <span class="kw">as </span>Decoder&gt;::Item&gt;,
{
<span class="kw">let </span>tx = rx.sender();
Dispatcher {
framed,
rx,
tx,
service: service.into_service(),
state: State::Processing,
}
}
<span class="doccomment">/// Get sender handle.
</span><span class="kw">pub fn </span>tx(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; mpsc::Sender&lt;<span class="prelude-ty">Result</span>&lt;Message&lt;I&gt;, S::Error&gt;&gt; {
<span class="self">self</span>.tx.clone()
}
<span class="doccomment">/// Get reference to a service wrapped by `Dispatcher` instance.
</span><span class="kw">pub fn </span>service(<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>.service
}
<span class="doccomment">/// Get mutable reference to a service wrapped by `Dispatcher` instance.
</span><span class="kw">pub fn </span>service_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>.service
}
<span class="doccomment">/// Get reference to a framed instance wrapped by `Dispatcher` instance.
</span><span class="kw">pub fn </span>framed(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>Framed&lt;T, U&gt; {
<span class="kw-2">&amp;</span><span class="self">self</span>.framed
}
<span class="doccomment">/// Get mutable reference to a framed instance wrapped by `Dispatcher` instance.
</span><span class="kw">pub fn </span>framed_mut(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>Framed&lt;T, U&gt; {
<span class="kw-2">&amp;mut </span><span class="self">self</span>.framed
}
<span class="doccomment">/// Read from framed object.
</span><span class="kw">fn </span>poll_read(<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;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; bool
<span class="kw">where
</span>S: Service&lt;&lt;U <span class="kw">as </span>Decoder&gt;::Item, Response = I&gt;,
S::Error: <span class="lifetime">'static</span>,
S::Future: <span class="lifetime">'static</span>,
T: AsyncRead + AsyncWrite,
U: Decoder + Encoder&lt;I&gt;,
I: <span class="lifetime">'static</span>,
&lt;U <span class="kw">as </span>Encoder&lt;I&gt;&gt;::Error: fmt::Debug,
{
<span class="kw">loop </span>{
<span class="kw">let </span>this = <span class="self">self</span>.as_mut().project();
<span class="kw">match </span>this.service.poll_ready(cx) {
Poll::Ready(<span class="prelude-val">Ok</span>(<span class="kw">_</span>)) =&gt; {
<span class="kw">let </span>item = <span class="kw">match </span>this.framed.next_item(cx) {
Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(el))) =&gt; el,
Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err))) =&gt; {
<span class="kw-2">*</span>this.state = State::FramedError(DispatcherError::Decoder(err));
<span class="kw">return </span><span class="bool-val">true</span>;
}
Poll::Pending =&gt; <span class="kw">return </span><span class="bool-val">false</span>,
Poll::Ready(<span class="prelude-val">None</span>) =&gt; {
<span class="kw-2">*</span>this.state = State::Stopping;
<span class="kw">return </span><span class="bool-val">true</span>;
}
};
<span class="kw">let </span>tx = this.tx.clone();
<span class="kw">let </span>fut = this.service.call(item);
actix_rt::spawn(<span class="kw">async move </span>{
<span class="kw">let </span>item = fut.<span class="kw">await</span>;
<span class="kw">let _ </span>= tx.send(item.map(Message::Item));
});
}
Poll::Pending =&gt; <span class="kw">return </span><span class="bool-val">false</span>,
Poll::Ready(<span class="prelude-val">Err</span>(err)) =&gt; {
<span class="kw-2">*</span>this.state = State::Error(DispatcherError::Service(err));
<span class="kw">return </span><span class="bool-val">true</span>;
}
}
}
}
<span class="doccomment">/// Write to framed object.
</span><span class="kw">fn </span>poll_write(<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;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; bool
<span class="kw">where
</span>S: Service&lt;&lt;U <span class="kw">as </span>Decoder&gt;::Item, Response = I&gt;,
S::Error: <span class="lifetime">'static</span>,
S::Future: <span class="lifetime">'static</span>,
T: AsyncRead + AsyncWrite,
U: Decoder + Encoder&lt;I&gt;,
I: <span class="lifetime">'static</span>,
&lt;U <span class="kw">as </span>Encoder&lt;I&gt;&gt;::Error: fmt::Debug,
{
<span class="kw">loop </span>{
<span class="kw">let </span><span class="kw-2">mut </span>this = <span class="self">self</span>.as_mut().project();
<span class="kw">while </span>!this.framed.is_write_buf_full() {
<span class="kw">match </span>Pin::new(<span class="kw-2">&amp;mut </span>this.rx).poll_next(cx) {
Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(Message::Item(msg)))) =&gt; {
<span class="kw">if let </span><span class="prelude-val">Err</span>(err) = this.framed.as_mut().write(msg) {
<span class="kw-2">*</span>this.state = State::FramedError(DispatcherError::Encoder(err));
<span class="kw">return </span><span class="bool-val">true</span>;
}
}
Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Ok</span>(Message::Close))) =&gt; {
<span class="kw-2">*</span>this.state = State::FlushAndStop;
<span class="kw">return </span><span class="bool-val">true</span>;
}
Poll::Ready(<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err))) =&gt; {
<span class="kw-2">*</span>this.state = State::Error(DispatcherError::Service(err));
<span class="kw">return </span><span class="bool-val">true</span>;
}
Poll::Ready(<span class="prelude-val">None</span>) | Poll::Pending =&gt; <span class="kw">break</span>,
}
}
<span class="kw">if </span>!this.framed.is_write_buf_empty() {
<span class="kw">match </span>this.framed.flush(cx) {
Poll::Pending =&gt; <span class="kw">break</span>,
Poll::Ready(<span class="prelude-val">Ok</span>(<span class="kw">_</span>)) =&gt; {}
Poll::Ready(<span class="prelude-val">Err</span>(err)) =&gt; {
<span class="macro">debug!</span>(<span class="string">"Error sending data: {:?}"</span>, err);
<span class="kw-2">*</span>this.state = State::FramedError(DispatcherError::Encoder(err));
<span class="kw">return </span><span class="bool-val">true</span>;
}
}
} <span class="kw">else </span>{
<span class="kw">break</span>;
}
}
<span class="bool-val">false
</span>}
}
<span class="kw">impl</span>&lt;S, T, U, I&gt; Future <span class="kw">for </span>Dispatcher&lt;S, T, U, I&gt;
<span class="kw">where
</span>S: Service&lt;&lt;U <span class="kw">as </span>Decoder&gt;::Item, Response = I&gt;,
S::Error: <span class="lifetime">'static</span>,
S::Future: <span class="lifetime">'static</span>,
T: AsyncRead + AsyncWrite,
U: Decoder + Encoder&lt;I&gt;,
I: <span class="lifetime">'static</span>,
&lt;U <span class="kw">as </span>Encoder&lt;I&gt;&gt;::Error: fmt::Debug,
&lt;U <span class="kw">as </span>Decoder&gt;::Error: fmt::Debug,
{
<span class="kw">type </span>Output = <span class="prelude-ty">Result</span>&lt;(), DispatcherError&lt;S::Error, U, I&gt;&gt;;
<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;, cx: <span class="kw-2">&amp;mut </span>Context&lt;<span class="lifetime">'_</span>&gt;) -&gt; Poll&lt;<span class="self">Self</span>::Output&gt; {
<span class="kw">loop </span>{
<span class="kw">let </span>this = <span class="self">self</span>.as_mut().project();
<span class="kw">return match </span>this.state {
State::Processing =&gt; {
<span class="kw">if </span><span class="self">self</span>.as_mut().poll_read(cx) || <span class="self">self</span>.as_mut().poll_write(cx) {
<span class="kw">continue</span>;
} <span class="kw">else </span>{
Poll::Pending
}
}
State::Error(<span class="kw">_</span>) =&gt; {
<span class="comment">// flush write buffer
</span><span class="kw">if </span>!this.framed.is_write_buf_empty() &amp;&amp; this.framed.flush(cx).is_pending() {
<span class="kw">return </span>Poll::Pending;
}
Poll::Ready(<span class="prelude-val">Err</span>(this.state.take_error()))
}
State::FlushAndStop =&gt; {
<span class="kw">if </span>!this.framed.is_write_buf_empty() {
this.framed.flush(cx).map(|res| {
<span class="kw">if let </span><span class="prelude-val">Err</span>(err) = res {
<span class="macro">debug!</span>(<span class="string">"Error sending data: {:?}"</span>, err);
}
<span class="prelude-val">Ok</span>(())
})
} <span class="kw">else </span>{
Poll::Ready(<span class="prelude-val">Ok</span>(()))
}
}
State::FramedError(<span class="kw">_</span>) =&gt; Poll::Ready(<span class="prelude-val">Err</span>(this.state.take_framed_error())),
State::Stopping =&gt; Poll::Ready(<span class="prelude-val">Ok</span>(())),
};
}
}
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,811 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/ws/frame.rs`."><title>frame.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
<a href="#339" id="339">339</a>
<a href="#340" id="340">340</a>
<a href="#341" id="341">341</a>
<a href="#342" id="342">342</a>
<a href="#343" id="343">343</a>
<a href="#344" id="344">344</a>
<a href="#345" id="345">345</a>
<a href="#346" id="346">346</a>
<a href="#347" id="347">347</a>
<a href="#348" id="348">348</a>
<a href="#349" id="349">349</a>
<a href="#350" id="350">350</a>
<a href="#351" id="351">351</a>
<a href="#352" id="352">352</a>
<a href="#353" id="353">353</a>
<a href="#354" id="354">354</a>
<a href="#355" id="355">355</a>
<a href="#356" id="356">356</a>
<a href="#357" id="357">357</a>
<a href="#358" id="358">358</a>
<a href="#359" id="359">359</a>
<a href="#360" id="360">360</a>
<a href="#361" id="361">361</a>
<a href="#362" id="362">362</a>
<a href="#363" id="363">363</a>
<a href="#364" id="364">364</a>
<a href="#365" id="365">365</a>
<a href="#366" id="366">366</a>
<a href="#367" id="367">367</a>
<a href="#368" id="368">368</a>
<a href="#369" id="369">369</a>
<a href="#370" id="370">370</a>
<a href="#371" id="371">371</a>
<a href="#372" id="372">372</a>
<a href="#373" id="373">373</a>
<a href="#374" id="374">374</a>
<a href="#375" id="375">375</a>
<a href="#376" id="376">376</a>
<a href="#377" id="377">377</a>
<a href="#378" id="378">378</a>
<a href="#379" id="379">379</a>
<a href="#380" id="380">380</a>
<a href="#381" id="381">381</a>
<a href="#382" id="382">382</a>
<a href="#383" id="383">383</a>
<a href="#384" id="384">384</a>
<a href="#385" id="385">385</a>
<a href="#386" id="386">386</a>
<a href="#387" id="387">387</a>
<a href="#388" id="388">388</a>
<a href="#389" id="389">389</a>
<a href="#390" id="390">390</a>
<a href="#391" id="391">391</a>
<a href="#392" id="392">392</a>
<a href="#393" id="393">393</a>
<a href="#394" id="394">394</a>
<a href="#395" id="395">395</a>
<a href="#396" id="396">396</a>
<a href="#397" id="397">397</a>
<a href="#398" id="398">398</a>
<a href="#399" id="399">399</a>
<a href="#400" id="400">400</a>
<a href="#401" id="401">401</a>
<a href="#402" id="402">402</a>
<a href="#403" id="403">403</a>
<a href="#404" id="404">404</a>
<a href="#405" id="405">405</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::cmp::min;
<span class="kw">use </span>bytes::{Buf, BufMut, BytesMut};
<span class="kw">use </span>tracing::debug;
<span class="kw">use super</span>::{
mask::apply_mask,
proto::{CloseCode, CloseReason, OpCode},
ProtocolError,
};
<span class="doccomment">/// A struct representing a WebSocket frame.
</span><span class="attr">#[derive(Debug)]
</span><span class="kw">pub struct </span>Parser;
<span class="kw">impl </span>Parser {
<span class="kw">fn </span>parse_metadata(
src: <span class="kw-2">&amp;</span>[u8],
server: bool,
) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;(usize, bool, OpCode, usize, <span class="prelude-ty">Option</span>&lt;[u8; <span class="number">4</span>]&gt;)&gt;, ProtocolError&gt; {
<span class="kw">let </span>chunk_len = src.len();
<span class="kw">let </span><span class="kw-2">mut </span>idx = <span class="number">2</span>;
<span class="kw">if </span>chunk_len &lt; <span class="number">2 </span>{
<span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>);
}
<span class="kw">let </span>first = src[<span class="number">0</span>];
<span class="kw">let </span>second = src[<span class="number">1</span>];
<span class="kw">let </span>finished = first &amp; <span class="number">0x80 </span>!= <span class="number">0</span>;
<span class="comment">// check masking
</span><span class="kw">let </span>masked = second &amp; <span class="number">0x80 </span>!= <span class="number">0</span>;
<span class="kw">if </span>!masked &amp;&amp; server {
<span class="kw">return </span><span class="prelude-val">Err</span>(ProtocolError::UnmaskedFrame);
} <span class="kw">else if </span>masked &amp;&amp; !server {
<span class="kw">return </span><span class="prelude-val">Err</span>(ProtocolError::MaskedFrame);
}
<span class="comment">// Op code
</span><span class="kw">let </span>opcode = OpCode::from(first &amp; <span class="number">0x0F</span>);
<span class="kw">if let </span>OpCode::Bad = opcode {
<span class="kw">return </span><span class="prelude-val">Err</span>(ProtocolError::InvalidOpcode(first &amp; <span class="number">0x0F</span>));
}
<span class="kw">let </span>len = second &amp; <span class="number">0x7F</span>;
<span class="kw">let </span>length = <span class="kw">if </span>len == <span class="number">126 </span>{
<span class="kw">if </span>chunk_len &lt; <span class="number">4 </span>{
<span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>);
}
<span class="kw">let </span>len = usize::from(u16::from_be_bytes(
TryFrom::try_from(<span class="kw-2">&amp;</span>src[idx..idx + <span class="number">2</span>]).unwrap(),
));
idx += <span class="number">2</span>;
len
} <span class="kw">else if </span>len == <span class="number">127 </span>{
<span class="kw">if </span>chunk_len &lt; <span class="number">10 </span>{
<span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>);
}
<span class="kw">let </span>len = u64::from_be_bytes(TryFrom::try_from(<span class="kw-2">&amp;</span>src[idx..idx + <span class="number">8</span>]).unwrap());
idx += <span class="number">8</span>;
len <span class="kw">as </span>usize
} <span class="kw">else </span>{
len <span class="kw">as </span>usize
};
<span class="kw">let </span>mask = <span class="kw">if </span>server {
<span class="kw">if </span>chunk_len &lt; idx + <span class="number">4 </span>{
<span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>);
}
<span class="kw">let </span>mask = TryFrom::try_from(<span class="kw-2">&amp;</span>src[idx..idx + <span class="number">4</span>]).unwrap();
idx += <span class="number">4</span>;
<span class="prelude-val">Some</span>(mask)
} <span class="kw">else </span>{
<span class="prelude-val">None
</span>};
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>((idx, finished, opcode, length, mask)))
}
<span class="doccomment">/// Parse the input stream into a frame.
</span><span class="kw">pub fn </span>parse(
src: <span class="kw-2">&amp;mut </span>BytesMut,
server: bool,
max_size: usize,
) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;(bool, OpCode, <span class="prelude-ty">Option</span>&lt;BytesMut&gt;)&gt;, ProtocolError&gt; {
<span class="comment">// try to parse ws frame metadata
</span><span class="kw">let </span>(idx, finished, opcode, length, mask) = <span class="kw">match </span>Parser::parse_metadata(src, server)<span class="question-mark">? </span>{
<span class="prelude-val">None </span>=&gt; <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>),
<span class="prelude-val">Some</span>(res) =&gt; res,
};
<span class="comment">// not enough data
</span><span class="kw">if </span>src.len() &lt; idx + length {
<span class="kw">let </span>min_length = min(length, max_size);
<span class="kw">if </span>src.capacity() &lt; idx + min_length {
src.reserve(idx + min_length - src.capacity());
}
<span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>);
}
<span class="comment">// remove prefix
</span>src.advance(idx);
<span class="comment">// check for max allowed size
</span><span class="kw">if </span>length &gt; max_size {
<span class="comment">// drop the payload
</span>src.advance(length);
<span class="kw">return </span><span class="prelude-val">Err</span>(ProtocolError::Overflow);
}
<span class="comment">// no need for body
</span><span class="kw">if </span>length == <span class="number">0 </span>{
<span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>((finished, opcode, <span class="prelude-val">None</span>)));
}
<span class="kw">let </span><span class="kw-2">mut </span>data = src.split_to(length);
<span class="comment">// control frames must have length &lt;= 125
</span><span class="kw">match </span>opcode {
OpCode::Ping | OpCode::Pong <span class="kw">if </span>length &gt; <span class="number">125 </span>=&gt; {
<span class="kw">return </span><span class="prelude-val">Err</span>(ProtocolError::InvalidLength(length));
}
OpCode::Close <span class="kw">if </span>length &gt; <span class="number">125 </span>=&gt; {
<span class="macro">debug!</span>(<span class="string">"Received close frame with payload length exceeding 125. Morphing to protocol close frame."</span>);
<span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>((<span class="bool-val">true</span>, OpCode::Close, <span class="prelude-val">None</span>)));
}
<span class="kw">_ </span>=&gt; {}
}
<span class="comment">// unmask
</span><span class="kw">if let </span><span class="prelude-val">Some</span>(mask) = mask {
apply_mask(<span class="kw-2">&amp;mut </span>data, mask);
}
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>((finished, opcode, <span class="prelude-val">Some</span>(data))))
}
<span class="doccomment">/// Parse the payload of a close frame.
</span><span class="kw">pub fn </span>parse_close_payload(payload: <span class="kw-2">&amp;</span>[u8]) -&gt; <span class="prelude-ty">Option</span>&lt;CloseReason&gt; {
<span class="kw">if </span>payload.len() &gt;= <span class="number">2 </span>{
<span class="kw">let </span>raw_code = u16::from_be_bytes(TryFrom::try_from(<span class="kw-2">&amp;</span>payload[..<span class="number">2</span>]).unwrap());
<span class="kw">let </span>code = CloseCode::from(raw_code);
<span class="kw">let </span>description = <span class="kw">if </span>payload.len() &gt; <span class="number">2 </span>{
<span class="prelude-val">Some</span>(String::from_utf8_lossy(<span class="kw-2">&amp;</span>payload[<span class="number">2</span>..]).into())
} <span class="kw">else </span>{
<span class="prelude-val">None
</span>};
<span class="prelude-val">Some</span>(CloseReason { code, description })
} <span class="kw">else </span>{
<span class="prelude-val">None
</span>}
}
<span class="doccomment">/// Generate binary representation
</span><span class="kw">pub fn </span>write_message&lt;B: AsRef&lt;[u8]&gt;&gt;(
dst: <span class="kw-2">&amp;mut </span>BytesMut,
pl: B,
op: OpCode,
fin: bool,
mask: bool,
) {
<span class="kw">let </span>payload = pl.as_ref();
<span class="kw">let </span>one: u8 = <span class="kw">if </span>fin {
<span class="number">0x80 </span>| Into::&lt;u8&gt;::into(op)
} <span class="kw">else </span>{
op.into()
};
<span class="kw">let </span>payload_len = payload.len();
<span class="kw">let </span>(two, p_len) = <span class="kw">if </span>mask {
(<span class="number">0x80</span>, payload_len + <span class="number">4</span>)
} <span class="kw">else </span>{
(<span class="number">0</span>, payload_len)
};
<span class="kw">if </span>payload_len &lt; <span class="number">126 </span>{
dst.reserve(p_len + <span class="number">2 </span>+ <span class="kw">if </span>mask { <span class="number">4 </span>} <span class="kw">else </span>{ <span class="number">0 </span>});
dst.put_slice(<span class="kw-2">&amp;</span>[one, two | payload_len <span class="kw">as </span>u8]);
} <span class="kw">else if </span>payload_len &lt;= <span class="number">65_535 </span>{
dst.reserve(p_len + <span class="number">4 </span>+ <span class="kw">if </span>mask { <span class="number">4 </span>} <span class="kw">else </span>{ <span class="number">0 </span>});
dst.put_slice(<span class="kw-2">&amp;</span>[one, two | <span class="number">126</span>]);
dst.put_u16(payload_len <span class="kw">as </span>u16);
} <span class="kw">else </span>{
dst.reserve(p_len + <span class="number">10 </span>+ <span class="kw">if </span>mask { <span class="number">4 </span>} <span class="kw">else </span>{ <span class="number">0 </span>});
dst.put_slice(<span class="kw-2">&amp;</span>[one, two | <span class="number">127</span>]);
dst.put_u64(payload_len <span class="kw">as </span>u64);
};
<span class="kw">if </span>mask {
<span class="kw">let </span>mask = rand::random::&lt;[u8; <span class="number">4</span>]&gt;();
dst.put_slice(mask.as_ref());
dst.put_slice(payload.as_ref());
<span class="kw">let </span>pos = dst.len() - payload_len;
apply_mask(<span class="kw-2">&amp;mut </span>dst[pos..], mask);
} <span class="kw">else </span>{
dst.put_slice(payload.as_ref());
}
}
<span class="doccomment">/// Create a new Close control frame.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>write_close(dst: <span class="kw-2">&amp;mut </span>BytesMut, reason: <span class="prelude-ty">Option</span>&lt;CloseReason&gt;, mask: bool) {
<span class="kw">let </span>payload = <span class="kw">match </span>reason {
<span class="prelude-val">None </span>=&gt; Vec::new(),
<span class="prelude-val">Some</span>(reason) =&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>payload = Into::&lt;u16&gt;::into(reason.code).to_be_bytes().to_vec();
<span class="kw">if let </span><span class="prelude-val">Some</span>(description) = reason.description {
payload.extend(description.as_bytes());
}
payload
}
};
Parser::write_message(dst, payload, OpCode::Close, <span class="bool-val">true</span>, mask)
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">struct </span>F {
finished: bool,
opcode: OpCode,
payload: Bytes,
}
<span class="kw">fn </span>is_none(frm: <span class="kw-2">&amp;</span><span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;(bool, OpCode, <span class="prelude-ty">Option</span>&lt;BytesMut&gt;)&gt;, ProtocolError&gt;) -&gt; bool {
<span class="macro">matches!</span>(<span class="kw-2">*</span>frm, <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>))
}
<span class="kw">fn </span>extract(frm: <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;(bool, OpCode, <span class="prelude-ty">Option</span>&lt;BytesMut&gt;)&gt;, ProtocolError&gt;) -&gt; F {
<span class="kw">match </span>frm {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>((finished, opcode, payload))) =&gt; F {
finished,
opcode,
payload: payload
.map(|b| b.freeze())
.unwrap_or_else(|| Bytes::from(<span class="string">""</span>)),
},
<span class="kw">_ </span>=&gt; <span class="macro">unreachable!</span>(<span class="string">"error"</span>),
}
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(<span class="kw-2">&amp;</span>[<span class="number">0b0000_0001u8</span>, <span class="number">0b0000_0001u8</span>][..]);
<span class="macro">assert!</span>(is_none(<span class="kw-2">&amp;</span>Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>, <span class="number">1024</span>)));
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(<span class="kw-2">&amp;</span>[<span class="number">0b0000_0001u8</span>, <span class="number">0b0000_0001u8</span>][..]);
buf.extend(<span class="string">b"1"</span>);
<span class="kw">let </span>frame = extract(Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>, <span class="number">1024</span>));
<span class="macro">assert!</span>(!frame.finished);
<span class="macro">assert_eq!</span>(frame.opcode, OpCode::Text);
<span class="macro">assert_eq!</span>(frame.payload.as_ref(), <span class="kw-2">&amp;</span><span class="string">b"1"</span>[..]);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_length0() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(<span class="kw-2">&amp;</span>[<span class="number">0b0000_0001u8</span>, <span class="number">0b0000_0000u8</span>][..]);
<span class="kw">let </span>frame = extract(Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>, <span class="number">1024</span>));
<span class="macro">assert!</span>(!frame.finished);
<span class="macro">assert_eq!</span>(frame.opcode, OpCode::Text);
<span class="macro">assert!</span>(frame.payload.is_empty());
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_length2() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(<span class="kw-2">&amp;</span>[<span class="number">0b0000_0001u8</span>, <span class="number">126u8</span>][..]);
<span class="macro">assert!</span>(is_none(<span class="kw-2">&amp;</span>Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>, <span class="number">1024</span>)));
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(<span class="kw-2">&amp;</span>[<span class="number">0b0000_0001u8</span>, <span class="number">126u8</span>][..]);
buf.extend(<span class="kw-2">&amp;</span>[<span class="number">0u8</span>, <span class="number">4u8</span>][..]);
buf.extend(<span class="string">b"1234"</span>);
<span class="kw">let </span>frame = extract(Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>, <span class="number">1024</span>));
<span class="macro">assert!</span>(!frame.finished);
<span class="macro">assert_eq!</span>(frame.opcode, OpCode::Text);
<span class="macro">assert_eq!</span>(frame.payload.as_ref(), <span class="kw-2">&amp;</span><span class="string">b"1234"</span>[..]);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_length4() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(<span class="kw-2">&amp;</span>[<span class="number">0b0000_0001u8</span>, <span class="number">127u8</span>][..]);
<span class="macro">assert!</span>(is_none(<span class="kw-2">&amp;</span>Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>, <span class="number">1024</span>)));
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(<span class="kw-2">&amp;</span>[<span class="number">0b0000_0001u8</span>, <span class="number">127u8</span>][..]);
buf.extend(<span class="kw-2">&amp;</span>[<span class="number">0u8</span>, <span class="number">0u8</span>, <span class="number">0u8</span>, <span class="number">0u8</span>, <span class="number">0u8</span>, <span class="number">0u8</span>, <span class="number">0u8</span>, <span class="number">4u8</span>][..]);
buf.extend(<span class="string">b"1234"</span>);
<span class="kw">let </span>frame = extract(Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>, <span class="number">1024</span>));
<span class="macro">assert!</span>(!frame.finished);
<span class="macro">assert_eq!</span>(frame.opcode, OpCode::Text);
<span class="macro">assert_eq!</span>(frame.payload.as_ref(), <span class="kw-2">&amp;</span><span class="string">b"1234"</span>[..]);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_frame_mask() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(<span class="kw-2">&amp;</span>[<span class="number">0b0000_0001u8</span>, <span class="number">0b1000_0001u8</span>][..]);
buf.extend(<span class="string">b"0001"</span>);
buf.extend(<span class="string">b"1"</span>);
<span class="macro">assert!</span>(Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>, <span class="number">1024</span>).is_err());
<span class="kw">let </span>frame = extract(Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">true</span>, <span class="number">1024</span>));
<span class="macro">assert!</span>(!frame.finished);
<span class="macro">assert_eq!</span>(frame.opcode, OpCode::Text);
<span class="macro">assert_eq!</span>(frame.payload, Bytes::from(<span class="macro">vec!</span>[<span class="number">1u8</span>]));
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_frame_no_mask() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(<span class="kw-2">&amp;</span>[<span class="number">0b0000_0001u8</span>, <span class="number">0b0000_0001u8</span>][..]);
buf.extend([<span class="number">1u8</span>]);
<span class="macro">assert!</span>(Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">true</span>, <span class="number">1024</span>).is_err());
<span class="kw">let </span>frame = extract(Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>, <span class="number">1024</span>));
<span class="macro">assert!</span>(!frame.finished);
<span class="macro">assert_eq!</span>(frame.opcode, OpCode::Text);
<span class="macro">assert_eq!</span>(frame.payload, Bytes::from(<span class="macro">vec!</span>[<span class="number">1u8</span>]));
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_frame_max_size() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::from(<span class="kw-2">&amp;</span>[<span class="number">0b0000_0001u8</span>, <span class="number">0b0000_0010u8</span>][..]);
buf.extend([<span class="number">1u8</span>, <span class="number">1u8</span>]);
<span class="macro">assert!</span>(Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">true</span>, <span class="number">1</span>).is_err());
<span class="kw">if let </span><span class="prelude-val">Err</span>(ProtocolError::Overflow) = Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>, <span class="number">0</span>) {
} <span class="kw">else </span>{
<span class="macro">unreachable!</span>(<span class="string">"error"</span>);
}
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_parse_frame_max_size_recoverability() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::new();
<span class="comment">// The first text frame with length == 2, payload doesn't matter.
</span>buf.extend([<span class="number">0b0000_0001u8</span>, <span class="number">0b0000_0010u8</span>, <span class="number">0b0000_0000u8</span>, <span class="number">0b0000_0000u8</span>]);
<span class="comment">// Next binary frame with length == 2 and payload == `[0x1111_1111u8, 0x1111_1111u8]`.
</span>buf.extend([<span class="number">0b0000_0010u8</span>, <span class="number">0b0000_0010u8</span>, <span class="number">0b1111_1111u8</span>, <span class="number">0b1111_1111u8</span>]);
<span class="macro">assert_eq!</span>(buf.len(), <span class="number">8</span>);
<span class="macro">assert!</span>(<span class="macro">matches!</span>(
Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>, <span class="number">1</span>),
<span class="prelude-val">Err</span>(ProtocolError::Overflow)
));
<span class="macro">assert_eq!</span>(buf.len(), <span class="number">4</span>);
<span class="kw">let </span>frame = extract(Parser::parse(<span class="kw-2">&amp;mut </span>buf, <span class="bool-val">false</span>, <span class="number">2</span>));
<span class="macro">assert!</span>(!frame.finished);
<span class="macro">assert_eq!</span>(frame.opcode, OpCode::Binary);
<span class="macro">assert_eq!</span>(
frame.payload,
Bytes::from(<span class="macro">vec!</span>[<span class="number">0b1111_1111u8</span>, <span class="number">0b1111_1111u8</span>])
);
<span class="macro">assert_eq!</span>(buf.len(), <span class="number">0</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_ping_frame() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::new();
Parser::write_message(<span class="kw-2">&amp;mut </span>buf, Vec::from(<span class="string">"data"</span>), OpCode::Ping, <span class="bool-val">true</span>, <span class="bool-val">false</span>);
<span class="kw">let </span><span class="kw-2">mut </span>v = <span class="macro">vec!</span>[<span class="number">137u8</span>, <span class="number">4u8</span>];
v.extend(<span class="string">b"data"</span>);
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>buf[..], <span class="kw-2">&amp;</span>v[..]);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_pong_frame() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::new();
Parser::write_message(<span class="kw-2">&amp;mut </span>buf, Vec::from(<span class="string">"data"</span>), OpCode::Pong, <span class="bool-val">true</span>, <span class="bool-val">false</span>);
<span class="kw">let </span><span class="kw-2">mut </span>v = <span class="macro">vec!</span>[<span class="number">138u8</span>, <span class="number">4u8</span>];
v.extend(<span class="string">b"data"</span>);
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>buf[..], <span class="kw-2">&amp;</span>v[..]);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_close_frame() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::new();
<span class="kw">let </span>reason = (CloseCode::Normal, <span class="string">"data"</span>);
Parser::write_close(<span class="kw-2">&amp;mut </span>buf, <span class="prelude-val">Some</span>(reason.into()), <span class="bool-val">false</span>);
<span class="kw">let </span><span class="kw-2">mut </span>v = <span class="macro">vec!</span>[<span class="number">136u8</span>, <span class="number">6u8</span>, <span class="number">3u8</span>, <span class="number">232u8</span>];
v.extend(<span class="string">b"data"</span>);
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>buf[..], <span class="kw-2">&amp;</span>v[..]);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_empty_close_frame() {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::new();
Parser::write_close(<span class="kw-2">&amp;mut </span>buf, <span class="prelude-val">None</span>, <span class="bool-val">false</span>);
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>buf[..], <span class="kw-2">&amp;</span><span class="macro">vec!</span>[<span class="number">0x88</span>, <span class="number">0x00</span>][..]);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,151 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/ws/mask.rs`."><title>mask.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! This is code from [Tungstenite project](https://github.com/snapview/tungstenite-rs)
/// Mask/unmask a frame.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>apply_mask(buf: <span class="kw-2">&amp;mut </span>[u8], mask: [u8; <span class="number">4</span>]) {
apply_mask_fast32(buf, mask)
}
<span class="doccomment">/// A safe unoptimized mask application.
</span><span class="attr">#[inline]
</span><span class="kw">fn </span>apply_mask_fallback(buf: <span class="kw-2">&amp;mut </span>[u8], mask: [u8; <span class="number">4</span>]) {
<span class="kw">for </span>(i, byte) <span class="kw">in </span>buf.iter_mut().enumerate() {
<span class="kw-2">*</span>byte ^= mask[i &amp; <span class="number">3</span>];
}
}
<span class="doccomment">/// Faster version of `apply_mask()` which operates on 4-byte blocks.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>apply_mask_fast32(buf: <span class="kw-2">&amp;mut </span>[u8], mask: [u8; <span class="number">4</span>]) {
<span class="kw">let </span>mask_u32 = u32::from_ne_bytes(mask);
<span class="comment">// SAFETY:
//
// buf is a valid slice borrowed mutably from bytes::BytesMut.
//
// un aligned prefix and suffix would be mask/unmask per byte.
// proper aligned middle slice goes into fast path and operates on 4-byte blocks.
</span><span class="kw">let </span>(prefix, words, suffix) = <span class="kw">unsafe </span>{ buf.align_to_mut::&lt;u32&gt;() };
apply_mask_fallback(prefix, mask);
<span class="kw">let </span>head = prefix.len() &amp; <span class="number">3</span>;
<span class="kw">let </span>mask_u32 = <span class="kw">if </span>head &gt; <span class="number">0 </span>{
<span class="kw">if </span><span class="macro">cfg!</span>(target_endian = <span class="string">"big"</span>) {
mask_u32.rotate_left(<span class="number">8 </span>* head <span class="kw">as </span>u32)
} <span class="kw">else </span>{
mask_u32.rotate_right(<span class="number">8 </span>* head <span class="kw">as </span>u32)
}
} <span class="kw">else </span>{
mask_u32
};
<span class="kw">for </span>word <span class="kw">in </span>words.iter_mut() {
<span class="kw-2">*</span>word ^= mask_u32;
}
apply_mask_fallback(suffix, mask_u32.to_ne_bytes());
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>test_apply_mask() {
<span class="kw">let </span>mask = [<span class="number">0x6d</span>, <span class="number">0xb6</span>, <span class="number">0xb2</span>, <span class="number">0x80</span>];
<span class="kw">let </span>unmasked = [
<span class="number">0xf3</span>, <span class="number">0x00</span>, <span class="number">0x01</span>, <span class="number">0x02</span>, <span class="number">0x03</span>, <span class="number">0x80</span>, <span class="number">0x81</span>, <span class="number">0x82</span>, <span class="number">0xff</span>, <span class="number">0xfe</span>, <span class="number">0x00</span>, <span class="number">0x17</span>, <span class="number">0x74</span>, <span class="number">0xf9</span>,
<span class="number">0x12</span>, <span class="number">0x03</span>,
];
<span class="kw">for </span>data_len <span class="kw">in </span><span class="number">0</span>..=unmasked.len() {
<span class="kw">let </span>unmasked = <span class="kw-2">&amp;</span>unmasked[<span class="number">0</span>..data_len];
<span class="comment">// Check masking with different alignment.
</span><span class="kw">for </span>off <span class="kw">in </span><span class="number">0</span>..=<span class="number">3 </span>{
<span class="kw">if </span>unmasked.len() &lt; off {
<span class="kw">continue</span>;
}
<span class="kw">let </span><span class="kw-2">mut </span>masked = unmasked.to_vec();
apply_mask_fallback(<span class="kw-2">&amp;mut </span>masked[off..], mask);
<span class="kw">let </span><span class="kw-2">mut </span>masked_fast = unmasked.to_vec();
apply_mask_fast32(<span class="kw-2">&amp;mut </span>masked_fast[off..], mask);
<span class="macro">assert_eq!</span>(masked, masked_fast);
}
}
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,703 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/ws/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
<a href="#339" id="339">339</a>
<a href="#340" id="340">340</a>
<a href="#341" id="341">341</a>
<a href="#342" id="342">342</a>
<a href="#343" id="343">343</a>
<a href="#344" id="344">344</a>
<a href="#345" id="345">345</a>
<a href="#346" id="346">346</a>
<a href="#347" id="347">347</a>
<a href="#348" id="348">348</a>
<a href="#349" id="349">349</a>
<a href="#350" id="350">350</a>
<a href="#351" id="351">351</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! WebSocket protocol implementation.
//!
//! To setup a WebSocket, first perform the WebSocket handshake then on success convert `Payload` into a
//! `WsStream` stream and then use `WsWriter` to communicate with the peer.
</span><span class="kw">use </span>std::io;
<span class="kw">use </span>derive_more::{Display, Error, From};
<span class="kw">use </span>http::{header, Method, StatusCode};
<span class="kw">use crate</span>::{body::BoxBody, header::HeaderValue, RequestHead, Response, ResponseBuilder};
<span class="kw">mod </span>codec;
<span class="kw">mod </span>dispatcher;
<span class="kw">mod </span>frame;
<span class="kw">mod </span>mask;
<span class="kw">mod </span>proto;
<span class="kw">pub use </span><span class="self">self</span>::{
codec::{Codec, Frame, Item, Message},
dispatcher::Dispatcher,
frame::Parser,
proto::{hash_key, CloseCode, CloseReason, OpCode},
};
<span class="doccomment">/// WebSocket protocol errors.
</span><span class="attr">#[derive(Debug, Display, Error, From)]
</span><span class="kw">pub enum </span>ProtocolError {
<span class="doccomment">/// Received an unmasked frame from client.
</span><span class="attr">#[display(fmt = <span class="string">"received an unmasked frame from client"</span>)]
</span>UnmaskedFrame,
<span class="doccomment">/// Received a masked frame from server.
</span><span class="attr">#[display(fmt = <span class="string">"received a masked frame from server"</span>)]
</span>MaskedFrame,
<span class="doccomment">/// Encountered invalid opcode.
</span><span class="attr">#[display(fmt = <span class="string">"invalid opcode ({})"</span>, _0)]
</span>InvalidOpcode(<span class="attr">#[error(not(source))] </span>u8),
<span class="doccomment">/// Invalid control frame length
</span><span class="attr">#[display(fmt = <span class="string">"invalid control frame length ({})"</span>, _0)]
</span>InvalidLength(<span class="attr">#[error(not(source))] </span>usize),
<span class="doccomment">/// Bad opcode.
</span><span class="attr">#[display(fmt = <span class="string">"bad opcode"</span>)]
</span>BadOpCode,
<span class="doccomment">/// A payload reached size limit.
</span><span class="attr">#[display(fmt = <span class="string">"payload reached size limit"</span>)]
</span>Overflow,
<span class="doccomment">/// Continuation has not started.
</span><span class="attr">#[display(fmt = <span class="string">"continuation has not started"</span>)]
</span>ContinuationNotStarted,
<span class="doccomment">/// Received new continuation but it is already started.
</span><span class="attr">#[display(fmt = <span class="string">"received new continuation but it has already started"</span>)]
</span>ContinuationStarted,
<span class="doccomment">/// Unknown continuation fragment.
</span><span class="attr">#[display(fmt = <span class="string">"unknown continuation fragment: {}"</span>, _0)]
</span>ContinuationFragment(<span class="attr">#[error(not(source))] </span>OpCode),
<span class="doccomment">/// I/O error.
</span><span class="attr">#[display(fmt = <span class="string">"I/O error: {}"</span>, _0)]
</span>Io(io::Error),
}
<span class="doccomment">/// WebSocket handshake errors
</span><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, Error)]
</span><span class="kw">pub enum </span>HandshakeError {
<span class="doccomment">/// Only get method is allowed.
</span><span class="attr">#[display(fmt = <span class="string">"method not allowed"</span>)]
</span>GetMethodRequired,
<span class="doccomment">/// Upgrade header if not set to WebSocket.
</span><span class="attr">#[display(fmt = <span class="string">"WebSocket upgrade is expected"</span>)]
</span>NoWebsocketUpgrade,
<span class="doccomment">/// Connection header is not set to upgrade.
</span><span class="attr">#[display(fmt = <span class="string">"connection upgrade is expected"</span>)]
</span>NoConnectionUpgrade,
<span class="doccomment">/// WebSocket version header is not set.
</span><span class="attr">#[display(fmt = <span class="string">"WebSocket version header is required"</span>)]
</span>NoVersionHeader,
<span class="doccomment">/// Unsupported WebSocket version.
</span><span class="attr">#[display(fmt = <span class="string">"unsupported WebSocket version"</span>)]
</span>UnsupportedVersion,
<span class="doccomment">/// WebSocket key is not set or wrong.
</span><span class="attr">#[display(fmt = <span class="string">"unknown WebSocket key"</span>)]
</span>BadWebsocketKey,
}
<span class="kw">impl </span>From&lt;HandshakeError&gt; <span class="kw">for </span>Response&lt;BoxBody&gt; {
<span class="kw">fn </span>from(err: HandshakeError) -&gt; <span class="self">Self </span>{
<span class="kw">match </span>err {
HandshakeError::GetMethodRequired =&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::new(StatusCode::METHOD_NOT_ALLOWED);
<span class="attr">#[allow(clippy::declare_interior_mutable_const)]
</span><span class="kw">const </span>HV_GET: HeaderValue = HeaderValue::from_static(<span class="string">"GET"</span>);
res.headers_mut().insert(header::ALLOW, HV_GET);
res
}
HandshakeError::NoWebsocketUpgrade =&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::bad_request();
res.head_mut().reason = <span class="prelude-val">Some</span>(<span class="string">"No WebSocket Upgrade header found"</span>);
res
}
HandshakeError::NoConnectionUpgrade =&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::bad_request();
res.head_mut().reason = <span class="prelude-val">Some</span>(<span class="string">"No Connection upgrade"</span>);
res
}
HandshakeError::NoVersionHeader =&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::bad_request();
res.head_mut().reason = <span class="prelude-val">Some</span>(<span class="string">"WebSocket version header is required"</span>);
res
}
HandshakeError::UnsupportedVersion =&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::bad_request();
res.head_mut().reason = <span class="prelude-val">Some</span>(<span class="string">"Unsupported WebSocket version"</span>);
res
}
HandshakeError::BadWebsocketKey =&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>res = Response::bad_request();
res.head_mut().reason = <span class="prelude-val">Some</span>(<span class="string">"Handshake error"</span>);
res
}
}
}
}
<span class="kw">impl </span>From&lt;<span class="kw-2">&amp;</span>HandshakeError&gt; <span class="kw">for </span>Response&lt;BoxBody&gt; {
<span class="kw">fn </span>from(err: <span class="kw-2">&amp;</span>HandshakeError) -&gt; <span class="self">Self </span>{
(<span class="kw-2">*</span>err).into()
}
}
<span class="doccomment">/// Verify WebSocket handshake request and create handshake response.
</span><span class="kw">pub fn </span>handshake(req: <span class="kw-2">&amp;</span>RequestHead) -&gt; <span class="prelude-ty">Result</span>&lt;ResponseBuilder, HandshakeError&gt; {
verify_handshake(req)<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(handshake_response(req))
}
<span class="doccomment">/// Verify WebSocket handshake request.
</span><span class="kw">pub fn </span>verify_handshake(req: <span class="kw-2">&amp;</span>RequestHead) -&gt; <span class="prelude-ty">Result</span>&lt;(), HandshakeError&gt; {
<span class="comment">// WebSocket accepts only GET
</span><span class="kw">if </span>req.method != Method::GET {
<span class="kw">return </span><span class="prelude-val">Err</span>(HandshakeError::GetMethodRequired);
}
<span class="comment">// Check for "UPGRADE" to WebSocket header
</span><span class="kw">let </span>has_hdr = <span class="kw">if let </span><span class="prelude-val">Some</span>(hdr) = req.headers().get(header::UPGRADE) {
<span class="kw">if let </span><span class="prelude-val">Ok</span>(s) = hdr.to_str() {
s.to_ascii_lowercase().contains(<span class="string">"websocket"</span>)
} <span class="kw">else </span>{
<span class="bool-val">false
</span>}
} <span class="kw">else </span>{
<span class="bool-val">false
</span>};
<span class="kw">if </span>!has_hdr {
<span class="kw">return </span><span class="prelude-val">Err</span>(HandshakeError::NoWebsocketUpgrade);
}
<span class="comment">// Upgrade connection
</span><span class="kw">if </span>!req.upgrade() {
<span class="kw">return </span><span class="prelude-val">Err</span>(HandshakeError::NoConnectionUpgrade);
}
<span class="comment">// check supported version
</span><span class="kw">if </span>!req.headers().contains_key(header::SEC_WEBSOCKET_VERSION) {
<span class="kw">return </span><span class="prelude-val">Err</span>(HandshakeError::NoVersionHeader);
}
<span class="kw">let </span>supported_ver = {
<span class="kw">if let </span><span class="prelude-val">Some</span>(hdr) = req.headers().get(header::SEC_WEBSOCKET_VERSION) {
hdr == <span class="string">"13" </span>|| hdr == <span class="string">"8" </span>|| hdr == <span class="string">"7"
</span>} <span class="kw">else </span>{
<span class="bool-val">false
</span>}
};
<span class="kw">if </span>!supported_ver {
<span class="kw">return </span><span class="prelude-val">Err</span>(HandshakeError::UnsupportedVersion);
}
<span class="comment">// check client handshake for validity
</span><span class="kw">if </span>!req.headers().contains_key(header::SEC_WEBSOCKET_KEY) {
<span class="kw">return </span><span class="prelude-val">Err</span>(HandshakeError::BadWebsocketKey);
}
<span class="prelude-val">Ok</span>(())
}
<span class="doccomment">/// Create WebSocket handshake response.
///
/// This function returns handshake `Response`, ready to send to peer.
</span><span class="kw">pub fn </span>handshake_response(req: <span class="kw-2">&amp;</span>RequestHead) -&gt; ResponseBuilder {
<span class="kw">let </span>key = {
<span class="kw">let </span>key = req.headers().get(header::SEC_WEBSOCKET_KEY).unwrap();
proto::hash_key(key.as_ref())
};
Response::build(StatusCode::SWITCHING_PROTOCOLS)
.upgrade(<span class="string">"websocket"</span>)
.insert_header((
header::SEC_WEBSOCKET_ACCEPT,
<span class="comment">// key is known to be header value safe ascii
</span>HeaderValue::from_bytes(<span class="kw-2">&amp;</span>key).unwrap(),
))
.take()
}
<span class="attr">#[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>::{header, test::TestRequest};
<span class="attr">#[test]
</span><span class="kw">fn </span>test_handshake() {
<span class="kw">let </span>req = TestRequest::default().method(Method::POST).finish();
<span class="macro">assert_eq!</span>(
HandshakeError::GetMethodRequired,
verify_handshake(req.head()).unwrap_err(),
);
<span class="kw">let </span>req = TestRequest::default().finish();
<span class="macro">assert_eq!</span>(
HandshakeError::NoWebsocketUpgrade,
verify_handshake(req.head()).unwrap_err(),
);
<span class="kw">let </span>req = TestRequest::default()
.insert_header((header::UPGRADE, header::HeaderValue::from_static(<span class="string">"test"</span>)))
.finish();
<span class="macro">assert_eq!</span>(
HandshakeError::NoWebsocketUpgrade,
verify_handshake(req.head()).unwrap_err(),
);
<span class="kw">let </span>req = TestRequest::default()
.insert_header((
header::UPGRADE,
header::HeaderValue::from_static(<span class="string">"websocket"</span>),
))
.finish();
<span class="macro">assert_eq!</span>(
HandshakeError::NoConnectionUpgrade,
verify_handshake(req.head()).unwrap_err(),
);
<span class="kw">let </span>req = TestRequest::default()
.insert_header((
header::UPGRADE,
header::HeaderValue::from_static(<span class="string">"websocket"</span>),
))
.insert_header((
header::CONNECTION,
header::HeaderValue::from_static(<span class="string">"upgrade"</span>),
))
.finish();
<span class="macro">assert_eq!</span>(
HandshakeError::NoVersionHeader,
verify_handshake(req.head()).unwrap_err(),
);
<span class="kw">let </span>req = TestRequest::default()
.insert_header((
header::UPGRADE,
header::HeaderValue::from_static(<span class="string">"websocket"</span>),
))
.insert_header((
header::CONNECTION,
header::HeaderValue::from_static(<span class="string">"upgrade"</span>),
))
.insert_header((
header::SEC_WEBSOCKET_VERSION,
header::HeaderValue::from_static(<span class="string">"5"</span>),
))
.finish();
<span class="macro">assert_eq!</span>(
HandshakeError::UnsupportedVersion,
verify_handshake(req.head()).unwrap_err(),
);
<span class="kw">let </span>req = TestRequest::default()
.insert_header((
header::UPGRADE,
header::HeaderValue::from_static(<span class="string">"websocket"</span>),
))
.insert_header((
header::CONNECTION,
header::HeaderValue::from_static(<span class="string">"upgrade"</span>),
))
.insert_header((
header::SEC_WEBSOCKET_VERSION,
header::HeaderValue::from_static(<span class="string">"13"</span>),
))
.finish();
<span class="macro">assert_eq!</span>(
HandshakeError::BadWebsocketKey,
verify_handshake(req.head()).unwrap_err(),
);
<span class="kw">let </span>req = TestRequest::default()
.insert_header((
header::UPGRADE,
header::HeaderValue::from_static(<span class="string">"websocket"</span>),
))
.insert_header((
header::CONNECTION,
header::HeaderValue::from_static(<span class="string">"upgrade"</span>),
))
.insert_header((
header::SEC_WEBSOCKET_VERSION,
header::HeaderValue::from_static(<span class="string">"13"</span>),
))
.insert_header((
header::SEC_WEBSOCKET_KEY,
header::HeaderValue::from_static(<span class="string">"13"</span>),
))
.finish();
<span class="macro">assert_eq!</span>(
StatusCode::SWITCHING_PROTOCOLS,
handshake_response(req.head()).finish().status()
);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_ws_error_http_response() {
<span class="kw">let </span>resp: Response&lt;BoxBody&gt; = HandshakeError::GetMethodRequired.into();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
<span class="kw">let </span>resp: Response&lt;BoxBody&gt; = HandshakeError::NoWebsocketUpgrade.into();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::BAD_REQUEST);
<span class="kw">let </span>resp: Response&lt;BoxBody&gt; = HandshakeError::NoConnectionUpgrade.into();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::BAD_REQUEST);
<span class="kw">let </span>resp: Response&lt;BoxBody&gt; = HandshakeError::NoVersionHeader.into();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::BAD_REQUEST);
<span class="kw">let </span>resp: Response&lt;BoxBody&gt; = HandshakeError::UnsupportedVersion.into();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::BAD_REQUEST);
<span class="kw">let </span>resp: Response&lt;BoxBody&gt; = HandshakeError::BadWebsocketKey.into();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::BAD_REQUEST);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,709 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http/src/ws/proto.rs`."><title>proto.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_http" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
<a href="#320" id="320">320</a>
<a href="#321" id="321">321</a>
<a href="#322" id="322">322</a>
<a href="#323" id="323">323</a>
<a href="#324" id="324">324</a>
<a href="#325" id="325">325</a>
<a href="#326" id="326">326</a>
<a href="#327" id="327">327</a>
<a href="#328" id="328">328</a>
<a href="#329" id="329">329</a>
<a href="#330" id="330">330</a>
<a href="#331" id="331">331</a>
<a href="#332" id="332">332</a>
<a href="#333" id="333">333</a>
<a href="#334" id="334">334</a>
<a href="#335" id="335">335</a>
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
<a href="#339" id="339">339</a>
<a href="#340" id="340">340</a>
<a href="#341" id="341">341</a>
<a href="#342" id="342">342</a>
<a href="#343" id="343">343</a>
<a href="#344" id="344">344</a>
<a href="#345" id="345">345</a>
<a href="#346" id="346">346</a>
<a href="#347" id="347">347</a>
<a href="#348" id="348">348</a>
<a href="#349" id="349">349</a>
<a href="#350" id="350">350</a>
<a href="#351" id="351">351</a>
<a href="#352" id="352">352</a>
<a href="#353" id="353">353</a>
<a href="#354" id="354">354</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::fmt;
<span class="kw">use </span>base64::prelude::<span class="kw-2">*</span>;
<span class="kw">use </span>tracing::error;
<span class="doccomment">/// Operation codes defined in [RFC 6455 §11.8].
///
/// [RFC 6455]: https://datatracker.ietf.org/doc/html/rfc6455#section-11.8
</span><span class="attr">#[derive(Debug, Eq, PartialEq, Clone, Copy)]
</span><span class="kw">pub enum </span>OpCode {
<span class="doccomment">/// Indicates a continuation frame of a fragmented message.
</span>Continue,
<span class="doccomment">/// Indicates a text data frame.
</span>Text,
<span class="doccomment">/// Indicates a binary data frame.
</span>Binary,
<span class="doccomment">/// Indicates a close control frame.
</span>Close,
<span class="doccomment">/// Indicates a ping control frame.
</span>Ping,
<span class="doccomment">/// Indicates a pong control frame.
</span>Pong,
<span class="doccomment">/// Indicates an invalid opcode was received.
</span>Bad,
}
<span class="kw">impl </span>fmt::Display <span class="kw">for </span>OpCode {
<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">'_</span>&gt;) -&gt; fmt::Result {
<span class="kw">use </span>OpCode::<span class="kw-2">*</span>;
<span class="kw">match </span><span class="self">self </span>{
Continue =&gt; <span class="macro">write!</span>(f, <span class="string">"CONTINUE"</span>),
Text =&gt; <span class="macro">write!</span>(f, <span class="string">"TEXT"</span>),
Binary =&gt; <span class="macro">write!</span>(f, <span class="string">"BINARY"</span>),
Close =&gt; <span class="macro">write!</span>(f, <span class="string">"CLOSE"</span>),
Ping =&gt; <span class="macro">write!</span>(f, <span class="string">"PING"</span>),
Pong =&gt; <span class="macro">write!</span>(f, <span class="string">"PONG"</span>),
Bad =&gt; <span class="macro">write!</span>(f, <span class="string">"BAD"</span>),
}
}
}
<span class="kw">impl </span>From&lt;OpCode&gt; <span class="kw">for </span>u8 {
<span class="kw">fn </span>from(op: OpCode) -&gt; u8 {
<span class="kw">use </span><span class="self">self</span>::OpCode::<span class="kw-2">*</span>;
<span class="kw">match </span>op {
Continue =&gt; <span class="number">0</span>,
Text =&gt; <span class="number">1</span>,
Binary =&gt; <span class="number">2</span>,
Close =&gt; <span class="number">8</span>,
Ping =&gt; <span class="number">9</span>,
Pong =&gt; <span class="number">10</span>,
Bad =&gt; {
<span class="macro">error!</span>(<span class="string">"Attempted to convert invalid opcode to u8. This is a bug."</span>);
<span class="number">8 </span><span class="comment">// if this somehow happens, a close frame will help us tear down quickly
</span>}
}
}
}
<span class="kw">impl </span>From&lt;u8&gt; <span class="kw">for </span>OpCode {
<span class="kw">fn </span>from(byte: u8) -&gt; OpCode {
<span class="kw">use </span><span class="self">self</span>::OpCode::<span class="kw-2">*</span>;
<span class="kw">match </span>byte {
<span class="number">0 </span>=&gt; Continue,
<span class="number">1 </span>=&gt; Text,
<span class="number">2 </span>=&gt; Binary,
<span class="number">8 </span>=&gt; Close,
<span class="number">9 </span>=&gt; Ping,
<span class="number">10 </span>=&gt; Pong,
<span class="kw">_ </span>=&gt; Bad,
}
}
}
<span class="doccomment">/// Status code used to indicate why an endpoint is closing the WebSocket connection.
</span><span class="attr">#[derive(Debug, Eq, PartialEq, Clone, Copy)]
</span><span class="kw">pub enum </span>CloseCode {
<span class="doccomment">/// Indicates a normal closure, meaning that the purpose for which the connection was
/// established has been fulfilled.
</span>Normal,
<span class="doccomment">/// Indicates that an endpoint is "going away", such as a server going down or a browser having
/// navigated away from a page.
</span>Away,
<span class="doccomment">/// Indicates that an endpoint is terminating the connection due to a protocol error.
</span>Protocol,
<span class="doccomment">/// Indicates that an endpoint is terminating the connection because it has received a type of
/// data it cannot accept (e.g., an endpoint that understands only text data MAY send this if it
/// receives a binary message).
</span>Unsupported,
<span class="doccomment">/// Indicates an abnormal closure. If the abnormal closure was due to an error, this close code
/// will not be used. Instead, the `on_error` method of the handler will be called with
/// the error. However, if the connection is simply dropped, without an error, this close code
/// will be sent to the handler.
</span>Abnormal,
<span class="doccomment">/// Indicates that an endpoint is terminating the connection because it has received data within
/// a message that was not consistent with the type of the message (e.g., non-UTF-8 \[RFC 3629\]
/// data within a text message).
</span>Invalid,
<span class="doccomment">/// Indicates that an endpoint is terminating the connection because it has received a message
/// that violates its policy. This is a generic status code that can be returned when there is
/// no other more suitable status code (e.g., Unsupported or Size) or if there is a need to hide
/// specific details about the policy.
</span>Policy,
<span class="doccomment">/// Indicates that an endpoint is terminating the connection because it has received a message
/// that is too big for it to process.
</span>Size,
<span class="doccomment">/// Indicates that an endpoint (client) is terminating the connection because it has expected
/// the server to negotiate one or more extension, but the server didn't return them in the
/// response message of the WebSocket handshake. The list of extensions that are needed should
/// be given as the reason for closing. Note that this status code is not used by the server,
/// because it can fail the WebSocket handshake instead.
</span>Extension,
<span class="doccomment">/// Indicates that a server is terminating the connection because it encountered an unexpected
/// condition that prevented it from fulfilling the request.
</span>Error,
<span class="doccomment">/// Indicates that the server is restarting. A client may choose to reconnect, and if it does,
/// it should use a randomized delay of 5-30 seconds between attempts.
</span>Restart,
<span class="doccomment">/// Indicates that the server is overloaded and the client should either connect to a different
/// IP (when multiple targets exist), or reconnect to the same IP when a user has performed
/// an action.
</span>Again,
<span class="attr">#[doc(hidden)]
</span>Tls,
<span class="attr">#[doc(hidden)]
</span>Other(u16),
}
<span class="kw">impl </span>From&lt;CloseCode&gt; <span class="kw">for </span>u16 {
<span class="kw">fn </span>from(code: CloseCode) -&gt; u16 {
<span class="kw">use </span><span class="self">self</span>::CloseCode::<span class="kw-2">*</span>;
<span class="kw">match </span>code {
Normal =&gt; <span class="number">1000</span>,
Away =&gt; <span class="number">1001</span>,
Protocol =&gt; <span class="number">1002</span>,
Unsupported =&gt; <span class="number">1003</span>,
Abnormal =&gt; <span class="number">1006</span>,
Invalid =&gt; <span class="number">1007</span>,
Policy =&gt; <span class="number">1008</span>,
Size =&gt; <span class="number">1009</span>,
Extension =&gt; <span class="number">1010</span>,
Error =&gt; <span class="number">1011</span>,
Restart =&gt; <span class="number">1012</span>,
Again =&gt; <span class="number">1013</span>,
Tls =&gt; <span class="number">1015</span>,
Other(code) =&gt; code,
}
}
}
<span class="kw">impl </span>From&lt;u16&gt; <span class="kw">for </span>CloseCode {
<span class="kw">fn </span>from(code: u16) -&gt; CloseCode {
<span class="kw">use </span><span class="self">self</span>::CloseCode::<span class="kw-2">*</span>;
<span class="kw">match </span>code {
<span class="number">1000 </span>=&gt; Normal,
<span class="number">1001 </span>=&gt; Away,
<span class="number">1002 </span>=&gt; Protocol,
<span class="number">1003 </span>=&gt; Unsupported,
<span class="number">1006 </span>=&gt; Abnormal,
<span class="number">1007 </span>=&gt; Invalid,
<span class="number">1008 </span>=&gt; Policy,
<span class="number">1009 </span>=&gt; Size,
<span class="number">1010 </span>=&gt; Extension,
<span class="number">1011 </span>=&gt; Error,
<span class="number">1012 </span>=&gt; Restart,
<span class="number">1013 </span>=&gt; Again,
<span class="number">1015 </span>=&gt; Tls,
<span class="kw">_ </span>=&gt; Other(code),
}
}
}
<span class="attr">#[derive(Debug, Eq, PartialEq, Clone)]
</span><span class="doccomment">/// Reason for closing the connection
</span><span class="kw">pub struct </span>CloseReason {
<span class="doccomment">/// Exit code
</span><span class="kw">pub </span>code: CloseCode,
<span class="doccomment">/// Optional description of the exit code
</span><span class="kw">pub </span>description: <span class="prelude-ty">Option</span>&lt;String&gt;,
}
<span class="kw">impl </span>From&lt;CloseCode&gt; <span class="kw">for </span>CloseReason {
<span class="kw">fn </span>from(code: CloseCode) -&gt; <span class="self">Self </span>{
CloseReason {
code,
description: <span class="prelude-val">None</span>,
}
}
}
<span class="kw">impl</span>&lt;T: Into&lt;String&gt;&gt; From&lt;(CloseCode, T)&gt; <span class="kw">for </span>CloseReason {
<span class="kw">fn </span>from(info: (CloseCode, T)) -&gt; <span class="self">Self </span>{
CloseReason {
code: info.<span class="number">0</span>,
description: <span class="prelude-val">Some</span>(info.<span class="number">1</span>.into()),
}
}
}
<span class="doccomment">/// The WebSocket GUID as stated in the spec.
/// See &lt;https://datatracker.ietf.org/doc/html/rfc6455#section-1.3&gt;.
</span><span class="kw">static </span>WS_GUID: <span class="kw-2">&amp;</span>[u8] = <span class="string">b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"</span>;
<span class="doccomment">/// Hashes the `Sec-WebSocket-Key` header according to the WebSocket spec.
///
/// Result is a Base64 encoded byte array. `base64(sha1(input))` is always 28 bytes.
</span><span class="kw">pub fn </span>hash_key(key: <span class="kw-2">&amp;</span>[u8]) -&gt; [u8; <span class="number">28</span>] {
<span class="kw">let </span>hash = {
<span class="kw">use </span>sha1::Digest <span class="kw">as _</span>;
<span class="kw">let </span><span class="kw-2">mut </span>hasher = sha1::Sha1::new();
hasher.update(key);
hasher.update(WS_GUID);
hasher.finalize()
};
<span class="kw">let </span><span class="kw-2">mut </span>hash_b64 = [<span class="number">0</span>; <span class="number">28</span>];
<span class="kw">let </span>n = BASE64_STANDARD.encode_slice(hash, <span class="kw-2">&amp;mut </span>hash_b64).unwrap();
<span class="macro">assert_eq!</span>(n, <span class="number">28</span>);
hash_b64
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>test {
<span class="attr">#![allow(unused_imports, unused_variables, dead_code)]
</span><span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="macro">macro_rules!</span> opcode_into {
(<span class="macro-nonterminal">$from</span>:expr =&gt; <span class="macro-nonterminal">$opcode</span>:pat) =&gt; {
<span class="kw">match </span>OpCode::from(<span class="macro-nonterminal">$from</span>) {
e @ <span class="macro-nonterminal">$opcode </span>=&gt; {}
e =&gt; <span class="macro">unreachable!</span>(<span class="string">"{:?}"</span>, e),
}
};
}
<span class="macro">macro_rules!</span> opcode_from {
(<span class="macro-nonterminal">$from</span>:expr =&gt; <span class="macro-nonterminal">$opcode</span>:pat) =&gt; {
<span class="kw">let </span>res: u8 = <span class="macro-nonterminal">$from</span>.into();
<span class="kw">match </span>res {
e @ <span class="macro-nonterminal">$opcode </span>=&gt; {}
e =&gt; <span class="macro">unreachable!</span>(<span class="string">"{:?}"</span>, e),
}
};
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_to_opcode() {
<span class="macro">opcode_into!</span>(<span class="number">0 </span>=&gt; OpCode::Continue);
<span class="macro">opcode_into!</span>(<span class="number">1 </span>=&gt; OpCode::Text);
<span class="macro">opcode_into!</span>(<span class="number">2 </span>=&gt; OpCode::Binary);
<span class="macro">opcode_into!</span>(<span class="number">8 </span>=&gt; OpCode::Close);
<span class="macro">opcode_into!</span>(<span class="number">9 </span>=&gt; OpCode::Ping);
<span class="macro">opcode_into!</span>(<span class="number">10 </span>=&gt; OpCode::Pong);
<span class="macro">opcode_into!</span>(<span class="number">99 </span>=&gt; OpCode::Bad);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_from_opcode() {
<span class="macro">opcode_from!</span>(OpCode::Continue =&gt; <span class="number">0</span>);
<span class="macro">opcode_from!</span>(OpCode::Text =&gt; <span class="number">1</span>);
<span class="macro">opcode_from!</span>(OpCode::Binary =&gt; <span class="number">2</span>);
<span class="macro">opcode_from!</span>(OpCode::Close =&gt; <span class="number">8</span>);
<span class="macro">opcode_from!</span>(OpCode::Ping =&gt; <span class="number">9</span>);
<span class="macro">opcode_from!</span>(OpCode::Pong =&gt; <span class="number">10</span>);
}
<span class="attr">#[test]
#[should_panic]
</span><span class="kw">fn </span>test_from_opcode_debug() {
<span class="macro">opcode_from!</span>(OpCode::Bad =&gt; <span class="number">99</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_from_opcode_display() {
<span class="macro">assert_eq!</span>(<span class="macro">format!</span>(<span class="string">"{}"</span>, OpCode::Continue), <span class="string">"CONTINUE"</span>);
<span class="macro">assert_eq!</span>(<span class="macro">format!</span>(<span class="string">"{}"</span>, OpCode::Text), <span class="string">"TEXT"</span>);
<span class="macro">assert_eq!</span>(<span class="macro">format!</span>(<span class="string">"{}"</span>, OpCode::Binary), <span class="string">"BINARY"</span>);
<span class="macro">assert_eq!</span>(<span class="macro">format!</span>(<span class="string">"{}"</span>, OpCode::Close), <span class="string">"CLOSE"</span>);
<span class="macro">assert_eq!</span>(<span class="macro">format!</span>(<span class="string">"{}"</span>, OpCode::Ping), <span class="string">"PING"</span>);
<span class="macro">assert_eq!</span>(<span class="macro">format!</span>(<span class="string">"{}"</span>, OpCode::Pong), <span class="string">"PONG"</span>);
<span class="macro">assert_eq!</span>(<span class="macro">format!</span>(<span class="string">"{}"</span>, OpCode::Bad), <span class="string">"BAD"</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_hash_key() {
<span class="kw">let </span>hash = hash_key(<span class="string">b"hello actix-web"</span>);
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>hash, <span class="string">b"cR1dlyUUJKp0s/Bel25u5TgvC3E="</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>close_code_from_u16() {
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1000u16</span>), CloseCode::Normal);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1001u16</span>), CloseCode::Away);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1002u16</span>), CloseCode::Protocol);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1003u16</span>), CloseCode::Unsupported);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1006u16</span>), CloseCode::Abnormal);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1007u16</span>), CloseCode::Invalid);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1008u16</span>), CloseCode::Policy);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1009u16</span>), CloseCode::Size);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1010u16</span>), CloseCode::Extension);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1011u16</span>), CloseCode::Error);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1012u16</span>), CloseCode::Restart);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1013u16</span>), CloseCode::Again);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">1015u16</span>), CloseCode::Tls);
<span class="macro">assert_eq!</span>(CloseCode::from(<span class="number">2000u16</span>), CloseCode::Other(<span class="number">2000</span>));
}
<span class="attr">#[test]
</span><span class="kw">fn </span>close_code_into_u16() {
<span class="macro">assert_eq!</span>(<span class="number">1000u16</span>, Into::&lt;u16&gt;::into(CloseCode::Normal));
<span class="macro">assert_eq!</span>(<span class="number">1001u16</span>, Into::&lt;u16&gt;::into(CloseCode::Away));
<span class="macro">assert_eq!</span>(<span class="number">1002u16</span>, Into::&lt;u16&gt;::into(CloseCode::Protocol));
<span class="macro">assert_eq!</span>(<span class="number">1003u16</span>, Into::&lt;u16&gt;::into(CloseCode::Unsupported));
<span class="macro">assert_eq!</span>(<span class="number">1006u16</span>, Into::&lt;u16&gt;::into(CloseCode::Abnormal));
<span class="macro">assert_eq!</span>(<span class="number">1007u16</span>, Into::&lt;u16&gt;::into(CloseCode::Invalid));
<span class="macro">assert_eq!</span>(<span class="number">1008u16</span>, Into::&lt;u16&gt;::into(CloseCode::Policy));
<span class="macro">assert_eq!</span>(<span class="number">1009u16</span>, Into::&lt;u16&gt;::into(CloseCode::Size));
<span class="macro">assert_eq!</span>(<span class="number">1010u16</span>, Into::&lt;u16&gt;::into(CloseCode::Extension));
<span class="macro">assert_eq!</span>(<span class="number">1011u16</span>, Into::&lt;u16&gt;::into(CloseCode::Error));
<span class="macro">assert_eq!</span>(<span class="number">1012u16</span>, Into::&lt;u16&gt;::into(CloseCode::Restart));
<span class="macro">assert_eq!</span>(<span class="number">1013u16</span>, Into::&lt;u16&gt;::into(CloseCode::Again));
<span class="macro">assert_eq!</span>(<span class="number">1015u16</span>, Into::&lt;u16&gt;::into(CloseCode::Tls));
<span class="macro">assert_eq!</span>(<span class="number">2000u16</span>, Into::&lt;u16&gt;::into(CloseCode::Other(<span class="number">2000</span>)));
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,639 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-http-test/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_http_test" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
<a href="#316" id="316">316</a>
<a href="#317" id="317">317</a>
<a href="#318" id="318">318</a>
<a href="#319" id="319">319</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Various helpers for Actix applications to use during testing.
</span><span class="attr">#![deny(rust_2018_idioms, nonstandard_style)]
#![warn(future_incompatible)]
#![doc(html_logo_url = <span class="string">"https://actix.rs/img/logo.png"</span>)]
#![doc(html_favicon_url = <span class="string">"https://actix.rs/favicon.ico"</span>)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#[cfg(feature = <span class="string">"openssl"</span>)]
</span><span class="kw">extern crate </span>tls_openssl <span class="kw">as </span>openssl;
<span class="kw">use </span>std::{net, thread, time::Duration};
<span class="kw">use </span>actix_codec::{AsyncRead, AsyncWrite, Framed};
<span class="kw">use </span>actix_rt::{net::TcpStream, System};
<span class="kw">use </span>actix_server::{Server, ServerServiceFactory};
<span class="kw">use </span>awc::{
error::PayloadError, http::header::HeaderMap, ws, Client, ClientRequest, ClientResponse,
Connector,
};
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use </span>futures_core::stream::Stream;
<span class="kw">use </span>http::Method;
<span class="kw">use </span>socket2::{Domain, Protocol, Socket, Type};
<span class="kw">use </span>tokio::sync::mpsc;
<span class="doccomment">/// Start test server.
///
/// `TestServer` is very simple test server that simplify process of writing integration tests cases
/// for HTTP applications.
///
/// # Examples
///
/// ```
/// use actix_http::{HttpService, Response, Error, StatusCode};
/// use actix_http_test::test_server;
/// use actix_service::{fn_service, map_config, ServiceFactoryExt as _};
///
/// #[actix_rt::test]
/// # async fn hidden_test() {}
/// async fn test_example() {
/// let srv = test_server(|| {
/// HttpService::build()
/// .h1(fn_service(|req| async move {
/// Ok::&lt;_, Error&gt;(Response::ok())
/// }))
/// .tcp()
/// .map_err(|_| ())
/// })
/// .await;
///
/// let req = srv.get("/");
/// let response = req.send().await.unwrap();
///
/// assert_eq!(response.status(), StatusCode::OK);
/// }
/// # actix_rt::System::new().block_on(test_example());
/// ```
</span><span class="kw">pub async fn </span>test_server&lt;F: ServerServiceFactory&lt;TcpStream&gt;&gt;(factory: F) -&gt; TestServer {
<span class="kw">let </span>tcp = net::TcpListener::bind(<span class="string">"127.0.0.1:0"</span>).unwrap();
test_server_with_addr(tcp, factory).<span class="kw">await
</span>}
<span class="doccomment">/// Start [`test server`](test_server()) on an existing address binding.
</span><span class="kw">pub async fn </span>test_server_with_addr&lt;F: ServerServiceFactory&lt;TcpStream&gt;&gt;(
tcp: net::TcpListener,
factory: F,
) -&gt; TestServer {
<span class="kw">let </span>(started_tx, started_rx) = std::sync::mpsc::channel();
<span class="kw">let </span>(thread_stop_tx, thread_stop_rx) = mpsc::channel(<span class="number">1</span>);
<span class="comment">// run server in separate thread
</span>thread::spawn(<span class="kw">move </span>|| {
System::new().block_on(<span class="kw">async move </span>{
<span class="kw">let </span>local_addr = tcp.local_addr().unwrap();
<span class="kw">let </span>srv = Server::build()
.workers(<span class="number">1</span>)
.disable_signals()
.system_exit()
.listen(<span class="string">"test"</span>, tcp, factory)
.expect(<span class="string">"test server could not be created"</span>);
<span class="kw">let </span>srv = srv.run();
started_tx
.send((System::current(), srv.handle(), local_addr))
.unwrap();
<span class="comment">// drive server loop
</span>srv.<span class="kw">await</span>.unwrap();
});
<span class="comment">// notify TestServer that server and system have shut down
// all thread managed resources should be dropped at this point
</span><span class="attr">#[allow(clippy::let_underscore_future)]
</span><span class="kw">let _ </span>= thread_stop_tx.send(());
});
<span class="kw">let </span>(system, server, addr) = started_rx.recv().unwrap();
<span class="kw">let </span>client = {
<span class="attr">#[cfg(feature = <span class="string">"openssl"</span>)]
</span><span class="kw">let </span>connector = {
<span class="kw">use </span>openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
<span class="kw">let </span><span class="kw-2">mut </span>builder = SslConnector::builder(SslMethod::tls()).unwrap();
builder.set_verify(SslVerifyMode::NONE);
<span class="kw">let _ </span>= builder
.set_alpn_protos(<span class="string">b"\x02h2\x08http/1.1"</span>)
.map_err(|e| <span class="macro">log::error!</span>(<span class="string">"Can not set alpn protocol: {:?}"</span>, e));
Connector::new()
.conn_lifetime(Duration::from_secs(<span class="number">0</span>))
.timeout(Duration::from_millis(<span class="number">30000</span>))
.openssl(builder.build())
};
<span class="attr">#[cfg(not(feature = <span class="string">"openssl"</span>))]
</span><span class="kw">let </span>connector = {
Connector::new()
.conn_lifetime(Duration::from_secs(<span class="number">0</span>))
.timeout(Duration::from_millis(<span class="number">30000</span>))
};
Client::builder().connector(connector).finish()
};
TestServer {
server,
client,
system,
addr,
thread_stop_rx,
}
}
<span class="doccomment">/// Test server controller
</span><span class="kw">pub struct </span>TestServer {
server: actix_server::ServerHandle,
client: awc::Client,
system: actix_rt::System,
addr: net::SocketAddr,
thread_stop_rx: mpsc::Receiver&lt;()&gt;,
}
<span class="kw">impl </span>TestServer {
<span class="doccomment">/// Construct test server url
</span><span class="kw">pub fn </span>addr(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; net::SocketAddr {
<span class="self">self</span>.addr
}
<span class="doccomment">/// Construct test server url
</span><span class="kw">pub fn </span>url(<span class="kw-2">&amp;</span><span class="self">self</span>, uri: <span class="kw-2">&amp;</span>str) -&gt; String {
<span class="kw">if </span>uri.starts_with(<span class="string">'/'</span>) {
<span class="macro">format!</span>(<span class="string">"http://localhost:{}{}"</span>, <span class="self">self</span>.addr.port(), uri)
} <span class="kw">else </span>{
<span class="macro">format!</span>(<span class="string">"http://localhost:{}/{}"</span>, <span class="self">self</span>.addr.port(), uri)
}
}
<span class="doccomment">/// Construct test HTTPS server URL.
</span><span class="kw">pub fn </span>surl(<span class="kw-2">&amp;</span><span class="self">self</span>, uri: <span class="kw-2">&amp;</span>str) -&gt; String {
<span class="kw">if </span>uri.starts_with(<span class="string">'/'</span>) {
<span class="macro">format!</span>(<span class="string">"https://localhost:{}{}"</span>, <span class="self">self</span>.addr.port(), uri)
} <span class="kw">else </span>{
<span class="macro">format!</span>(<span class="string">"https://localhost:{}/{}"</span>, <span class="self">self</span>.addr.port(), uri)
}
}
<span class="doccomment">/// Create `GET` request
</span><span class="kw">pub fn </span>get&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.get(<span class="self">self</span>.url(path.as_ref()).as_str())
}
<span class="doccomment">/// Create HTTPS `GET` request
</span><span class="kw">pub fn </span>sget&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.get(<span class="self">self</span>.surl(path.as_ref()).as_str())
}
<span class="doccomment">/// Create `POST` request
</span><span class="kw">pub fn </span>post&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.post(<span class="self">self</span>.url(path.as_ref()).as_str())
}
<span class="doccomment">/// Create HTTPS `POST` request
</span><span class="kw">pub fn </span>spost&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.post(<span class="self">self</span>.surl(path.as_ref()).as_str())
}
<span class="doccomment">/// Create `HEAD` request
</span><span class="kw">pub fn </span>head&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.head(<span class="self">self</span>.url(path.as_ref()).as_str())
}
<span class="doccomment">/// Create HTTPS `HEAD` request
</span><span class="kw">pub fn </span>shead&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.head(<span class="self">self</span>.surl(path.as_ref()).as_str())
}
<span class="doccomment">/// Create `PUT` request
</span><span class="kw">pub fn </span>put&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.put(<span class="self">self</span>.url(path.as_ref()).as_str())
}
<span class="doccomment">/// Create HTTPS `PUT` request
</span><span class="kw">pub fn </span>sput&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.put(<span class="self">self</span>.surl(path.as_ref()).as_str())
}
<span class="doccomment">/// Create `PATCH` request
</span><span class="kw">pub fn </span>patch&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.patch(<span class="self">self</span>.url(path.as_ref()).as_str())
}
<span class="doccomment">/// Create HTTPS `PATCH` request
</span><span class="kw">pub fn </span>spatch&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.patch(<span class="self">self</span>.surl(path.as_ref()).as_str())
}
<span class="doccomment">/// Create `DELETE` request
</span><span class="kw">pub fn </span>delete&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.delete(<span class="self">self</span>.url(path.as_ref()).as_str())
}
<span class="doccomment">/// Create HTTPS `DELETE` request
</span><span class="kw">pub fn </span>sdelete&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.delete(<span class="self">self</span>.surl(path.as_ref()).as_str())
}
<span class="doccomment">/// Create `OPTIONS` request
</span><span class="kw">pub fn </span>options&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.options(<span class="self">self</span>.url(path.as_ref()).as_str())
}
<span class="doccomment">/// Create HTTPS `OPTIONS` request
</span><span class="kw">pub fn </span>soptions&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.options(<span class="self">self</span>.surl(path.as_ref()).as_str())
}
<span class="doccomment">/// Connect to test HTTP server
</span><span class="kw">pub fn </span>request&lt;S: AsRef&lt;str&gt;&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, method: Method, path: S) -&gt; ClientRequest {
<span class="self">self</span>.client.request(method, path.as_ref())
}
<span class="kw">pub async fn </span>load_body&lt;S&gt;(
<span class="kw-2">&amp;mut </span><span class="self">self</span>,
<span class="kw-2">mut </span>response: ClientResponse&lt;S&gt;,
) -&gt; <span class="prelude-ty">Result</span>&lt;Bytes, PayloadError&gt;
<span class="kw">where
</span>S: Stream&lt;Item = <span class="prelude-ty">Result</span>&lt;Bytes, PayloadError&gt;&gt; + Unpin + <span class="lifetime">'static</span>,
{
response.body().limit(<span class="number">10_485_760</span>).<span class="kw">await
</span>}
<span class="doccomment">/// Connect to WebSocket server at a given path.
</span><span class="kw">pub async fn </span>ws_at(
<span class="kw-2">&amp;mut </span><span class="self">self</span>,
path: <span class="kw-2">&amp;</span>str,
) -&gt; <span class="prelude-ty">Result</span>&lt;Framed&lt;<span class="kw">impl </span>AsyncRead + AsyncWrite, ws::Codec&gt;, awc::error::WsClientError&gt; {
<span class="kw">let </span>url = <span class="self">self</span>.url(path);
<span class="kw">let </span>connect = <span class="self">self</span>.client.ws(url).connect();
connect.<span class="kw">await</span>.map(|(<span class="kw">_</span>, framed)| framed)
}
<span class="doccomment">/// Connect to a WebSocket server.
</span><span class="kw">pub async fn </span>ws(
<span class="kw-2">&amp;mut </span><span class="self">self</span>,
) -&gt; <span class="prelude-ty">Result</span>&lt;Framed&lt;<span class="kw">impl </span>AsyncRead + AsyncWrite, ws::Codec&gt;, awc::error::WsClientError&gt; {
<span class="self">self</span>.ws_at(<span class="string">"/"</span>).<span class="kw">await
</span>}
<span class="doccomment">/// Get default HeaderMap of Client.
///
/// Returns Some(&amp;mut HeaderMap) when Client object is unique
/// (No other clone of client exists at the same time).
</span><span class="kw">pub fn </span>client_headers(<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>HeaderMap&gt; {
<span class="self">self</span>.client.headers()
}
<span class="doccomment">/// Stop HTTP server.
///
/// Waits for spawned `Server` and `System` to (force) shutdown.
</span><span class="kw">pub async fn </span>stop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="comment">// signal server to stop
</span><span class="self">self</span>.server.stop(<span class="bool-val">false</span>).<span class="kw">await</span>;
<span class="comment">// also signal system to stop
// though this is handled by `ServerBuilder::exit_system` too
</span><span class="self">self</span>.system.stop();
<span class="comment">// wait for thread to be stopped but don't care about result
</span><span class="kw">let _ </span>= <span class="self">self</span>.thread_stop_rx.recv().<span class="kw">await</span>;
}
}
<span class="kw">impl </span>Drop <span class="kw">for </span>TestServer {
<span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="comment">// calls in this Drop impl should be enough to shut down the server, system, and thread
// without needing to await anything
// signal server to stop
</span><span class="attr">#[allow(clippy::let_underscore_future)]
</span><span class="kw">let _ </span>= <span class="self">self</span>.server.stop(<span class="bool-val">true</span>);
<span class="comment">// signal system to stop
</span><span class="self">self</span>.system.stop();
}
}
<span class="doccomment">/// Get a localhost socket address with random, unused port.
</span><span class="kw">pub fn </span>unused_addr() -&gt; net::SocketAddr {
<span class="kw">let </span>addr: net::SocketAddr = <span class="string">"127.0.0.1:0"</span>.parse().unwrap();
<span class="kw">let </span>socket = Socket::new(Domain::IPV4, Type::STREAM, <span class="prelude-val">Some</span>(Protocol::TCP)).unwrap();
socket.bind(<span class="kw-2">&amp;</span>addr.into()).unwrap();
socket.set_reuse_address(<span class="bool-val">true</span>).unwrap();
<span class="kw">let </span>tcp = net::TcpListener::from(socket);
tcp.local_addr().unwrap()
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,199 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-multipart/src/error.rs`."><title>error.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_multipart" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Error and Result module
</span><span class="kw">use </span>actix_web::{
error::{ParseError, PayloadError},
http::StatusCode,
ResponseError,
};
<span class="kw">use </span>derive_more::{Display, Error, From};
<span class="doccomment">/// A set of errors that can occur during parsing multipart streams.
</span><span class="attr">#[derive(Debug, Display, From, Error)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>MultipartError {
<span class="doccomment">/// Content-Disposition header is not found or is not equal to "form-data".
///
/// According to [RFC 7578 §4.2](https://datatracker.ietf.org/doc/html/rfc7578#section-4.2) a
/// Content-Disposition header must always be present and equal to "form-data".
</span><span class="attr">#[display(fmt = <span class="string">"No Content-Disposition `form-data` header"</span>)]
</span>NoContentDisposition,
<span class="doccomment">/// Content-Type header is not found
</span><span class="attr">#[display(fmt = <span class="string">"No Content-Type header found"</span>)]
</span>NoContentType,
<span class="doccomment">/// Can not parse Content-Type header
</span><span class="attr">#[display(fmt = <span class="string">"Can not parse Content-Type header"</span>)]
</span>ParseContentType,
<span class="doccomment">/// Multipart boundary is not found
</span><span class="attr">#[display(fmt = <span class="string">"Multipart boundary is not found"</span>)]
</span>Boundary,
<span class="doccomment">/// Nested multipart is not supported
</span><span class="attr">#[display(fmt = <span class="string">"Nested multipart is not supported"</span>)]
</span>Nested,
<span class="doccomment">/// Multipart stream is incomplete
</span><span class="attr">#[display(fmt = <span class="string">"Multipart stream is incomplete"</span>)]
</span>Incomplete,
<span class="doccomment">/// Error during field parsing
</span><span class="attr">#[display(fmt = <span class="string">"{}"</span>, _0)]
</span>Parse(ParseError),
<span class="doccomment">/// Payload error
</span><span class="attr">#[display(fmt = <span class="string">"{}"</span>, _0)]
</span>Payload(PayloadError),
<span class="doccomment">/// Not consumed
</span><span class="attr">#[display(fmt = <span class="string">"Multipart stream is not consumed"</span>)]
</span>NotConsumed,
<span class="doccomment">/// An error from a field handler in a form
</span><span class="attr">#[display(
fmt = <span class="string">"An error occurred processing field `{}`: {}"</span>,
field_name,
source
)]
</span>Field {
field_name: String,
source: actix_web::Error,
},
<span class="doccomment">/// Duplicate field
</span><span class="attr">#[display(fmt = <span class="string">"Duplicate field found for: `{}`"</span>, _0)]
#[from(ignore)]
</span>DuplicateField(<span class="attr">#[error(not(source))] </span>String),
<span class="doccomment">/// Missing field
</span><span class="attr">#[display(fmt = <span class="string">"Field with name `{}` is required"</span>, _0)]
#[from(ignore)]
</span>MissingField(<span class="attr">#[error(not(source))] </span>String),
<span class="doccomment">/// Unknown field
</span><span class="attr">#[display(fmt = <span class="string">"Unsupported field `{}`"</span>, _0)]
#[from(ignore)]
</span>UnsupportedField(<span class="attr">#[error(not(source))] </span>String),
}
<span class="doccomment">/// Return `BadRequest` for `MultipartError`
</span><span class="kw">impl </span>ResponseError <span class="kw">for </span>MultipartError {
<span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
<span class="kw">match </span><span class="kw-2">&amp;</span><span class="self">self </span>{
MultipartError::Field { source, .. } =&gt; source.as_response_error().status_code(),
<span class="kw">_ </span>=&gt; StatusCode::BAD_REQUEST,
}
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>test_multipart_error() {
<span class="kw">let </span>resp = MultipartError::Boundary.error_response();
<span class="macro">assert_eq!</span>(resp.status(), StatusCode::BAD_REQUEST);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,87 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-multipart/src/extractor.rs`."><title>extractor.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_multipart" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Multipart payload support
</span><span class="kw">use </span>actix_utils::future::{ready, Ready};
<span class="kw">use </span>actix_web::{dev::Payload, Error, FromRequest, HttpRequest};
<span class="kw">use </span><span class="kw">crate</span>::server::Multipart;
<span class="doccomment">/// Get request's payload as multipart stream.
///
/// Content-type: multipart/form-data;
///
/// # Examples
/// ```
/// use actix_web::{web, HttpResponse, Error};
/// use actix_multipart::Multipart;
/// use futures_util::StreamExt as _;
///
/// async fn index(mut payload: Multipart) -&gt; Result&lt;HttpResponse, Error&gt; {
/// // iterate over multipart stream
/// while let Some(item) = payload.next().await {
/// let mut field = item?;
///
/// // Field in turn is stream of *Bytes* object
/// while let Some(chunk) = field.next().await {
/// println!("-- CHUNK: \n{:?}", std::str::from_utf8(&amp;chunk?));
/// }
/// }
///
/// Ok(HttpResponse::Ok().into())
/// }
/// ```
</span><span class="kw">impl </span>FromRequest <span class="kw">for </span>Multipart {
<span class="kw">type </span>Error = Error;
<span class="kw">type </span>Future = Ready&lt;<span class="prelude-ty">Result</span>&lt;Multipart, Error&gt;&gt;;
<span class="attr">#[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 {
ready(<span class="prelude-val">Ok</span>(<span class="kw">match </span>Multipart::boundary(req.headers()) {
<span class="prelude-val">Ok</span>(boundary) =&gt; Multipart::from_boundary(boundary, payload.take()),
<span class="prelude-val">Err</span>(err) =&gt; Multipart::from_error(err),
}))
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,99 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-multipart/src/form/bytes.rs`."><title>bytes.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_multipart" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Reads a field into memory.
</span><span class="kw">use </span>actix_web::HttpRequest;
<span class="kw">use </span>bytes::BytesMut;
<span class="kw">use </span>futures_core::future::LocalBoxFuture;
<span class="kw">use </span>futures_util::TryStreamExt <span class="kw">as _</span>;
<span class="kw">use </span>mime::Mime;
<span class="kw">use crate</span>::{
form::{FieldReader, Limits},
Field, MultipartError,
};
<span class="doccomment">/// Read the field into memory.
</span><span class="attr">#[derive(Debug)]
</span><span class="kw">pub struct </span>Bytes {
<span class="doccomment">/// The data.
</span><span class="kw">pub </span>data: bytes::Bytes,
<span class="doccomment">/// The value of the `Content-Type` header.
</span><span class="kw">pub </span>content_type: <span class="prelude-ty">Option</span>&lt;Mime&gt;,
<span class="doccomment">/// The `filename` value in the `Content-Disposition` header.
</span><span class="kw">pub </span>file_name: <span class="prelude-ty">Option</span>&lt;String&gt;,
}
<span class="kw">impl</span>&lt;<span class="lifetime">'t</span>&gt; FieldReader&lt;<span class="lifetime">'t</span>&gt; <span class="kw">for </span>Bytes {
<span class="kw">type </span>Future = LocalBoxFuture&lt;<span class="lifetime">'t</span>, <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, MultipartError&gt;&gt;;
<span class="kw">fn </span>read_field(<span class="kw">_</span>: <span class="kw-2">&amp;</span><span class="lifetime">'t </span>HttpRequest, <span class="kw-2">mut </span>field: Field, limits: <span class="kw-2">&amp;</span><span class="lifetime">'t </span><span class="kw-2">mut </span>Limits) -&gt; <span class="self">Self</span>::Future {
Box::pin(<span class="kw">async move </span>{
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::with_capacity(<span class="number">131_072</span>);
<span class="kw">while let </span><span class="prelude-val">Some</span>(chunk) = field.try_next().<span class="kw">await</span><span class="question-mark">? </span>{
limits.try_consume_limits(chunk.len(), <span class="bool-val">true</span>)<span class="question-mark">?</span>;
buf.extend(chunk);
}
<span class="prelude-val">Ok</span>(Bytes {
data: buf.freeze(),
content_type: field.content_type().map(ToOwned::to_owned),
file_name: field
.content_disposition()
.get_filename()
.map(str::to_owned),
})
})
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,423 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-multipart/src/form/json.rs`."><title>json.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_multipart" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Deserializes a field as JSON.
</span><span class="kw">use </span>std::sync::Arc;
<span class="kw">use </span>actix_web::{http::StatusCode, web, Error, HttpRequest, ResponseError};
<span class="kw">use </span>derive_more::{Deref, DerefMut, Display, Error};
<span class="kw">use </span>futures_core::future::LocalBoxFuture;
<span class="kw">use </span>serde::de::DeserializeOwned;
<span class="kw">use </span><span class="kw">super</span>::FieldErrorHandler;
<span class="kw">use crate</span>::{
form::{bytes::Bytes, FieldReader, Limits},
Field, MultipartError,
};
<span class="doccomment">/// Deserialize from JSON.
</span><span class="attr">#[derive(Debug, Deref, DerefMut)]
</span><span class="kw">pub struct </span>Json&lt;T: DeserializeOwned&gt;(<span class="kw">pub </span>T);
<span class="kw">impl</span>&lt;T: DeserializeOwned&gt; Json&lt;T&gt; {
<span class="kw">pub fn </span>into_inner(<span class="self">self</span>) -&gt; T {
<span class="self">self</span>.<span class="number">0
</span>}
}
<span class="kw">impl</span>&lt;<span class="lifetime">'t</span>, T&gt; FieldReader&lt;<span class="lifetime">'t</span>&gt; <span class="kw">for </span>Json&lt;T&gt;
<span class="kw">where
</span>T: DeserializeOwned + <span class="lifetime">'static</span>,
{
<span class="kw">type </span>Future = LocalBoxFuture&lt;<span class="lifetime">'t</span>, <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, MultipartError&gt;&gt;;
<span class="kw">fn </span>read_field(req: <span class="kw-2">&amp;</span><span class="lifetime">'t </span>HttpRequest, field: Field, limits: <span class="kw-2">&amp;</span><span class="lifetime">'t </span><span class="kw-2">mut </span>Limits) -&gt; <span class="self">Self</span>::Future {
Box::pin(<span class="kw">async move </span>{
<span class="kw">let </span>config = JsonConfig::from_req(req);
<span class="kw">let </span>field_name = field.name().to_owned();
<span class="kw">if </span>config.validate_content_type {
<span class="kw">let </span>valid = <span class="kw">if let </span><span class="prelude-val">Some</span>(mime) = field.content_type() {
mime.subtype() == mime::JSON || mime.suffix() == <span class="prelude-val">Some</span>(mime::JSON)
} <span class="kw">else </span>{
<span class="bool-val">false
</span>};
<span class="kw">if </span>!valid {
<span class="kw">return </span><span class="prelude-val">Err</span>(MultipartError::Field {
field_name,
source: config.map_error(req, JsonFieldError::ContentType),
});
}
}
<span class="kw">let </span>bytes = Bytes::read_field(req, field, limits).<span class="kw">await</span><span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(Json(serde_json::from_slice(bytes.data.as_ref()).map_err(
|err| MultipartError::Field {
field_name,
source: config.map_error(req, JsonFieldError::Deserialize(err)),
},
)<span class="question-mark">?</span>))
})
}
}
<span class="attr">#[derive(Debug, Display, Error)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>JsonFieldError {
<span class="doccomment">/// Deserialize error.
</span><span class="attr">#[display(fmt = <span class="string">"Json deserialize error: {}"</span>, _0)]
</span>Deserialize(serde_json::Error),
<span class="doccomment">/// Content type error.
</span><span class="attr">#[display(fmt = <span class="string">"Content type error"</span>)]
</span>ContentType,
}
<span class="kw">impl </span>ResponseError <span class="kw">for </span>JsonFieldError {
<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="doccomment">/// Configuration for the [`Json`] field reader.
</span><span class="attr">#[derive(Clone)]
</span><span class="kw">pub struct </span>JsonConfig {
err_handler: FieldErrorHandler&lt;JsonFieldError&gt;,
validate_content_type: bool,
}
<span class="kw">const </span>DEFAULT_CONFIG: JsonConfig = JsonConfig {
err_handler: <span class="prelude-val">None</span>,
validate_content_type: <span class="bool-val">true</span>,
};
<span class="kw">impl </span>JsonConfig {
<span class="kw">pub fn </span>error_handler&lt;F&gt;(<span class="kw-2">mut </span><span class="self">self</span>, f: F) -&gt; <span class="self">Self
</span><span class="kw">where
</span>F: Fn(JsonFieldError, <span class="kw-2">&amp;</span>HttpRequest) -&gt; Error + Send + Sync + <span class="lifetime">'static</span>,
{
<span class="self">self</span>.err_handler = <span class="prelude-val">Some</span>(Arc::new(f));
<span class="self">self
</span>}
<span class="doccomment">/// Extract payload config from app data. Check both `T` and `Data&lt;T&gt;`, in that order, and fall
/// back to the default payload config.
</span><span class="kw">fn </span>from_req(req: <span class="kw-2">&amp;</span>HttpRequest) -&gt; <span class="kw-2">&amp;</span><span class="self">Self </span>{
req.app_data::&lt;<span class="self">Self</span>&gt;()
.or_else(|| req.app_data::&lt;web::Data&lt;<span class="self">Self</span>&gt;&gt;().map(|d| d.as_ref()))
.unwrap_or(<span class="kw-2">&amp;</span>DEFAULT_CONFIG)
}
<span class="kw">fn </span>map_error(<span class="kw-2">&amp;</span><span class="self">self</span>, req: <span class="kw-2">&amp;</span>HttpRequest, err: JsonFieldError) -&gt; Error {
<span class="kw">if let </span><span class="prelude-val">Some</span>(err_handler) = <span class="self">self</span>.err_handler.as_ref() {
(<span class="kw-2">*</span>err_handler)(err, req)
} <span class="kw">else </span>{
err.into()
}
}
<span class="doccomment">/// Sets whether or not the field must have a valid `Content-Type` header to be parsed.
</span><span class="kw">pub fn </span>validate_content_type(<span class="kw-2">mut </span><span class="self">self</span>, validate_content_type: bool) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.validate_content_type = validate_content_type;
<span class="self">self
</span>}
}
<span class="kw">impl </span>Default <span class="kw">for </span>JsonConfig {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
DEFAULT_CONFIG
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::collections::HashMap;
<span class="kw">use </span>actix_web::{http::StatusCode, web, App, HttpResponse, Responder};
<span class="kw">use </span>bytes::Bytes;
<span class="kw">use </span><span class="kw">crate</span>::form::{
json::{Json, JsonConfig},
MultipartForm,
};
<span class="attr">#[derive(MultipartForm)]
</span><span class="kw">struct </span>JsonForm {
json: Json&lt;HashMap&lt;String, String&gt;&gt;,
}
<span class="kw">async fn </span>test_json_route(form: MultipartForm&lt;JsonForm&gt;) -&gt; <span class="kw">impl </span>Responder {
<span class="kw">let </span><span class="kw-2">mut </span>expected = HashMap::new();
expected.insert(<span class="string">"key1"</span>.to_owned(), <span class="string">"value1"</span>.to_owned());
expected.insert(<span class="string">"key2"</span>.to_owned(), <span class="string">"value2"</span>.to_owned());
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;*</span>form.json, <span class="kw-2">&amp;</span>expected);
HttpResponse::Ok().finish()
}
<span class="kw">const </span>TEST_JSON: <span class="kw-2">&amp;</span>str = <span class="string">r#"{"key1": "value1", "key2": "value2"}"#</span>;
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>test_json_without_content_type() {
<span class="kw">let </span>srv = actix_test::start(|| {
App::new()
.route(<span class="string">"/"</span>, web::post().to(test_json_route))
.app_data(JsonConfig::default().validate_content_type(<span class="bool-val">false</span>))
});
<span class="kw">let </span>(body, headers) = <span class="kw">crate</span>::test::create_form_data_payload_and_headers(
<span class="string">"json"</span>,
<span class="prelude-val">None</span>,
<span class="prelude-val">None</span>,
Bytes::from_static(TEST_JSON.as_bytes()),
);
<span class="kw">let </span><span class="kw-2">mut </span>req = srv.post(<span class="string">"/"</span>);
<span class="kw-2">*</span>req.headers_mut() = headers;
<span class="kw">let </span>res = req.send_body(body).<span class="kw">await</span>.unwrap();
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>test_content_type_validation() {
<span class="kw">let </span>srv = actix_test::start(|| {
App::new()
.route(<span class="string">"/"</span>, web::post().to(test_json_route))
.app_data(JsonConfig::default().validate_content_type(<span class="bool-val">true</span>))
});
<span class="comment">// Deny because wrong content type
</span><span class="kw">let </span>(body, headers) = <span class="kw">crate</span>::test::create_form_data_payload_and_headers(
<span class="string">"json"</span>,
<span class="prelude-val">None</span>,
<span class="prelude-val">Some</span>(mime::APPLICATION_OCTET_STREAM),
Bytes::from_static(TEST_JSON.as_bytes()),
);
<span class="kw">let </span><span class="kw-2">mut </span>req = srv.post(<span class="string">"/"</span>);
<span class="kw-2">*</span>req.headers_mut() = headers;
<span class="kw">let </span>res = req.send_body(body).<span class="kw">await</span>.unwrap();
<span class="macro">assert_eq!</span>(res.status(), StatusCode::BAD_REQUEST);
<span class="comment">// Allow because correct content type
</span><span class="kw">let </span>(body, headers) = <span class="kw">crate</span>::test::create_form_data_payload_and_headers(
<span class="string">"json"</span>,
<span class="prelude-val">None</span>,
<span class="prelude-val">Some</span>(mime::APPLICATION_JSON),
Bytes::from_static(TEST_JSON.as_bytes()),
);
<span class="kw">let </span><span class="kw-2">mut </span>req = srv.post(<span class="string">"/"</span>);
<span class="kw-2">*</span>req.headers_mut() = headers;
<span class="kw">let </span>res = req.send_body(body).<span class="kw">await</span>.unwrap();
<span class="macro">assert_eq!</span>(res.status(), StatusCode::OK);
}
}
</code></pre></div></section></main></body></html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,399 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-multipart/src/form/tempfile.rs`."><title>tempfile.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_multipart" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Writes a field to a temporary file on disk.
</span><span class="kw">use </span>std::{
io,
path::{Path, PathBuf},
sync::Arc,
};
<span class="kw">use </span>actix_web::{http::StatusCode, web, Error, HttpRequest, ResponseError};
<span class="kw">use </span>derive_more::{Display, Error};
<span class="kw">use </span>futures_core::future::LocalBoxFuture;
<span class="kw">use </span>futures_util::TryStreamExt <span class="kw">as _</span>;
<span class="kw">use </span>mime::Mime;
<span class="kw">use </span>tempfile::NamedTempFile;
<span class="kw">use </span>tokio::io::AsyncWriteExt;
<span class="kw">use </span><span class="kw">super</span>::FieldErrorHandler;
<span class="kw">use crate</span>::{
form::{FieldReader, Limits},
Field, MultipartError,
};
<span class="doccomment">/// Write the field to a temporary file on disk.
</span><span class="attr">#[derive(Debug)]
</span><span class="kw">pub struct </span>TempFile {
<span class="doccomment">/// The temporary file on disk.
</span><span class="kw">pub </span>file: NamedTempFile,
<span class="doccomment">/// The value of the `content-type` header.
</span><span class="kw">pub </span>content_type: <span class="prelude-ty">Option</span>&lt;Mime&gt;,
<span class="doccomment">/// The `filename` value in the `content-disposition` header.
</span><span class="kw">pub </span>file_name: <span class="prelude-ty">Option</span>&lt;String&gt;,
<span class="doccomment">/// The size in bytes of the file.
</span><span class="kw">pub </span>size: usize,
}
<span class="kw">impl</span>&lt;<span class="lifetime">'t</span>&gt; FieldReader&lt;<span class="lifetime">'t</span>&gt; <span class="kw">for </span>TempFile {
<span class="kw">type </span>Future = LocalBoxFuture&lt;<span class="lifetime">'t</span>, <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, MultipartError&gt;&gt;;
<span class="kw">fn </span>read_field(req: <span class="kw-2">&amp;</span><span class="lifetime">'t </span>HttpRequest, <span class="kw-2">mut </span>field: Field, limits: <span class="kw-2">&amp;</span><span class="lifetime">'t </span><span class="kw-2">mut </span>Limits) -&gt; <span class="self">Self</span>::Future {
Box::pin(<span class="kw">async move </span>{
<span class="kw">let </span>config = TempFileConfig::from_req(req);
<span class="kw">let </span>field_name = field.name().to_owned();
<span class="kw">let </span><span class="kw-2">mut </span>size = <span class="number">0</span>;
<span class="kw">let </span>file = config
.create_tempfile()
.map_err(|err| config.map_error(req, <span class="kw-2">&amp;</span>field_name, TempFileError::FileIo(err)))<span class="question-mark">?</span>;
<span class="kw">let </span><span class="kw-2">mut </span>file_async =
tokio::fs::File::from_std(file.reopen().map_err(|err| {
config.map_error(req, <span class="kw-2">&amp;</span>field_name, TempFileError::FileIo(err))
})<span class="question-mark">?</span>);
<span class="kw">while let </span><span class="prelude-val">Some</span>(chunk) = field.try_next().<span class="kw">await</span><span class="question-mark">? </span>{
limits.try_consume_limits(chunk.len(), <span class="bool-val">false</span>)<span class="question-mark">?</span>;
size += chunk.len();
file_async.write_all(chunk.as_ref()).<span class="kw">await</span>.map_err(|err| {
config.map_error(req, <span class="kw-2">&amp;</span>field_name, TempFileError::FileIo(err))
})<span class="question-mark">?</span>;
}
file_async
.flush()
.<span class="kw">await
</span>.map_err(|err| config.map_error(req, <span class="kw-2">&amp;</span>field_name, TempFileError::FileIo(err)))<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(TempFile {
file,
content_type: field.content_type().map(ToOwned::to_owned),
file_name: field
.content_disposition()
.get_filename()
.map(str::to_owned),
size,
})
})
}
}
<span class="attr">#[derive(Debug, Display, Error)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>TempFileError {
<span class="doccomment">/// File I/O Error
</span><span class="attr">#[display(fmt = <span class="string">"File I/O error: {}"</span>, _0)]
</span>FileIo(std::io::Error),
}
<span class="kw">impl </span>ResponseError <span class="kw">for </span>TempFileError {
<span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
StatusCode::INTERNAL_SERVER_ERROR
}
}
<span class="doccomment">/// Configuration for the [`TempFile`] field reader.
</span><span class="attr">#[derive(Clone)]
</span><span class="kw">pub struct </span>TempFileConfig {
err_handler: FieldErrorHandler&lt;TempFileError&gt;,
directory: <span class="prelude-ty">Option</span>&lt;PathBuf&gt;,
}
<span class="kw">impl </span>TempFileConfig {
<span class="kw">fn </span>create_tempfile(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; io::Result&lt;NamedTempFile&gt; {
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>dir) = <span class="self">self</span>.directory {
NamedTempFile::new_in(dir)
} <span class="kw">else </span>{
NamedTempFile::new()
}
}
}
<span class="kw">impl </span>TempFileConfig {
<span class="doccomment">/// Sets custom error handler.
</span><span class="kw">pub fn </span>error_handler&lt;F&gt;(<span class="kw-2">mut </span><span class="self">self</span>, f: F) -&gt; <span class="self">Self
</span><span class="kw">where
</span>F: Fn(TempFileError, <span class="kw-2">&amp;</span>HttpRequest) -&gt; Error + Send + Sync + <span class="lifetime">'static</span>,
{
<span class="self">self</span>.err_handler = <span class="prelude-val">Some</span>(Arc::new(f));
<span class="self">self
</span>}
<span class="doccomment">/// Extracts payload config from app data. Check both `T` and `Data&lt;T&gt;`, in that order, and fall
/// back to the default payload config.
</span><span class="kw">fn </span>from_req(req: <span class="kw-2">&amp;</span>HttpRequest) -&gt; <span class="kw-2">&amp;</span><span class="self">Self </span>{
req.app_data::&lt;<span class="self">Self</span>&gt;()
.or_else(|| req.app_data::&lt;web::Data&lt;<span class="self">Self</span>&gt;&gt;().map(|d| d.as_ref()))
.unwrap_or(<span class="kw-2">&amp;</span>DEFAULT_CONFIG)
}
<span class="kw">fn </span>map_error(<span class="kw-2">&amp;</span><span class="self">self</span>, req: <span class="kw-2">&amp;</span>HttpRequest, field_name: <span class="kw-2">&amp;</span>str, err: TempFileError) -&gt; MultipartError {
<span class="kw">let </span>source = <span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>err_handler) = <span class="self">self</span>.err_handler {
(err_handler)(err, req)
} <span class="kw">else </span>{
err.into()
};
MultipartError::Field {
field_name: field_name.to_owned(),
source,
}
}
<span class="doccomment">/// Sets the directory that temp files will be created in.
///
/// The default temporary file location is platform dependent.
</span><span class="kw">pub fn </span>directory(<span class="kw-2">mut </span><span class="self">self</span>, dir: <span class="kw">impl </span>AsRef&lt;Path&gt;) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.directory = <span class="prelude-val">Some</span>(dir.as_ref().to_owned());
<span class="self">self
</span>}
}
<span class="kw">const </span>DEFAULT_CONFIG: TempFileConfig = TempFileConfig {
err_handler: <span class="prelude-val">None</span>,
directory: <span class="prelude-val">None</span>,
};
<span class="kw">impl </span>Default <span class="kw">for </span>TempFileConfig {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
DEFAULT_CONFIG
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::io::{Cursor, Read};
<span class="kw">use </span>actix_multipart_rfc7578::client::multipart;
<span class="kw">use </span>actix_web::{http::StatusCode, web, App, HttpResponse, Responder};
<span class="kw">use </span><span class="kw">crate</span>::form::{tempfile::TempFile, tests::send_form, MultipartForm};
<span class="attr">#[derive(MultipartForm)]
</span><span class="kw">struct </span>FileForm {
file: TempFile,
}
<span class="kw">async fn </span>test_file_route(form: MultipartForm&lt;FileForm&gt;) -&gt; <span class="kw">impl </span>Responder {
<span class="kw">let </span><span class="kw-2">mut </span>form = form.into_inner();
<span class="kw">let </span><span class="kw-2">mut </span>contents = String::new();
form.file.file.read_to_string(<span class="kw-2">&amp;mut </span>contents).unwrap();
<span class="macro">assert_eq!</span>(contents, <span class="string">"Hello, world!"</span>);
<span class="macro">assert_eq!</span>(form.file.file_name.unwrap(), <span class="string">"testfile.txt"</span>);
<span class="macro">assert_eq!</span>(form.file.content_type.unwrap(), mime::TEXT_PLAIN);
HttpResponse::Ok().finish()
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>test_file_upload() {
<span class="kw">let </span>srv = actix_test::start(|| App::new().route(<span class="string">"/"</span>, web::post().to(test_file_route)));
<span class="kw">let </span><span class="kw-2">mut </span>form = multipart::Form::default();
<span class="kw">let </span>bytes = Cursor::new(<span class="string">"Hello, world!"</span>);
form.add_reader_file_with_mime(<span class="string">"file"</span>, bytes, <span class="string">"testfile.txt"</span>, mime::TEXT_PLAIN);
<span class="kw">let </span>response = send_form(<span class="kw-2">&amp;</span>srv, form, <span class="string">"/"</span>).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(response.status(), StatusCode::OK);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,393 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-multipart/src/form/text.rs`."><title>text.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="actix_multipart" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Deserializes a field from plain text.
</span><span class="kw">use </span>std::{str, sync::Arc};
<span class="kw">use </span>actix_web::{http::StatusCode, web, Error, HttpRequest, ResponseError};
<span class="kw">use </span>derive_more::{Deref, DerefMut, Display, Error};
<span class="kw">use </span>futures_core::future::LocalBoxFuture;
<span class="kw">use </span>serde::de::DeserializeOwned;
<span class="kw">use </span><span class="kw">super</span>::FieldErrorHandler;
<span class="kw">use crate</span>::{
form::{bytes::Bytes, FieldReader, Limits},
Field, MultipartError,
};
<span class="doccomment">/// Deserialize from plain text.
///
/// Internally this uses [`serde_plain`] for deserialization, which supports primitive types
/// including strings, numbers, and simple enums.
</span><span class="attr">#[derive(Debug, Deref, DerefMut)]
</span><span class="kw">pub struct </span>Text&lt;T: DeserializeOwned&gt;(<span class="kw">pub </span>T);
<span class="kw">impl</span>&lt;T: DeserializeOwned&gt; Text&lt;T&gt; {
<span class="doccomment">/// Unwraps into inner value.
</span><span class="kw">pub fn </span>into_inner(<span class="self">self</span>) -&gt; T {
<span class="self">self</span>.<span class="number">0
</span>}
}
<span class="kw">impl</span>&lt;<span class="lifetime">'t</span>, T&gt; FieldReader&lt;<span class="lifetime">'t</span>&gt; <span class="kw">for </span>Text&lt;T&gt;
<span class="kw">where
</span>T: DeserializeOwned + <span class="lifetime">'static</span>,
{
<span class="kw">type </span>Future = LocalBoxFuture&lt;<span class="lifetime">'t</span>, <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, MultipartError&gt;&gt;;
<span class="kw">fn </span>read_field(req: <span class="kw-2">&amp;</span><span class="lifetime">'t </span>HttpRequest, field: Field, limits: <span class="kw-2">&amp;</span><span class="lifetime">'t </span><span class="kw-2">mut </span>Limits) -&gt; <span class="self">Self</span>::Future {
Box::pin(<span class="kw">async move </span>{
<span class="kw">let </span>config = TextConfig::from_req(req);
<span class="kw">let </span>field_name = field.name().to_owned();
<span class="kw">if </span>config.validate_content_type {
<span class="kw">let </span>valid = <span class="kw">if let </span><span class="prelude-val">Some</span>(mime) = field.content_type() {
mime.subtype() == mime::PLAIN || mime.suffix() == <span class="prelude-val">Some</span>(mime::PLAIN)
} <span class="kw">else </span>{
<span class="comment">// https://datatracker.ietf.org/doc/html/rfc7578#section-4.4
// content type defaults to text/plain, so None should be considered valid
</span><span class="bool-val">true
</span>};
<span class="kw">if </span>!valid {
<span class="kw">return </span><span class="prelude-val">Err</span>(MultipartError::Field {
field_name,
source: config.map_error(req, TextError::ContentType),
});
}
}
<span class="kw">let </span>bytes = Bytes::read_field(req, field, limits).<span class="kw">await</span><span class="question-mark">?</span>;
<span class="kw">let </span>text = str::from_utf8(<span class="kw-2">&amp;</span>bytes.data).map_err(|err| MultipartError::Field {
field_name: field_name.clone(),
source: config.map_error(req, TextError::Utf8Error(err)),
})<span class="question-mark">?</span>;
<span class="prelude-val">Ok</span>(Text(serde_plain::from_str(text).map_err(|err| {
MultipartError::Field {
field_name,
source: config.map_error(req, TextError::Deserialize(err)),
}
})<span class="question-mark">?</span>))
})
}
}
<span class="attr">#[derive(Debug, Display, Error)]
#[non_exhaustive]
</span><span class="kw">pub enum </span>TextError {
<span class="doccomment">/// UTF-8 decoding error.
</span><span class="attr">#[display(fmt = <span class="string">"UTF-8 decoding error: {}"</span>, _0)]
</span>Utf8Error(str::Utf8Error),
<span class="doccomment">/// Deserialize error.
</span><span class="attr">#[display(fmt = <span class="string">"Plain text deserialize error: {}"</span>, _0)]
</span>Deserialize(serde_plain::Error),
<span class="doccomment">/// Content type error.
</span><span class="attr">#[display(fmt = <span class="string">"Content type error"</span>)]
</span>ContentType,
}
<span class="kw">impl </span>ResponseError <span class="kw">for </span>TextError {
<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="doccomment">/// Configuration for the [`Text`] field reader.
</span><span class="attr">#[derive(Clone)]
</span><span class="kw">pub struct </span>TextConfig {
err_handler: FieldErrorHandler&lt;TextError&gt;,
validate_content_type: bool,
}
<span class="kw">impl </span>TextConfig {
<span class="doccomment">/// Sets custom error handler.
</span><span class="kw">pub fn </span>error_handler&lt;F&gt;(<span class="kw-2">mut </span><span class="self">self</span>, f: F) -&gt; <span class="self">Self
</span><span class="kw">where
</span>F: Fn(TextError, <span class="kw-2">&amp;</span>HttpRequest) -&gt; Error + Send + Sync + <span class="lifetime">'static</span>,
{
<span class="self">self</span>.err_handler = <span class="prelude-val">Some</span>(Arc::new(f));
<span class="self">self
</span>}
<span class="doccomment">/// Extracts payload config from app data. Check both `T` and `Data&lt;T&gt;`, in that order, and fall
/// back to the default payload config.
</span><span class="kw">fn </span>from_req(req: <span class="kw-2">&amp;</span>HttpRequest) -&gt; <span class="kw-2">&amp;</span><span class="self">Self </span>{
req.app_data::&lt;<span class="self">Self</span>&gt;()
.or_else(|| req.app_data::&lt;web::Data&lt;<span class="self">Self</span>&gt;&gt;().map(|d| d.as_ref()))
.unwrap_or(<span class="kw-2">&amp;</span>DEFAULT_CONFIG)
}
<span class="kw">fn </span>map_error(<span class="kw-2">&amp;</span><span class="self">self</span>, req: <span class="kw-2">&amp;</span>HttpRequest, err: TextError) -&gt; Error {
<span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>err_handler) = <span class="self">self</span>.err_handler {
(err_handler)(err, req)
} <span class="kw">else </span>{
err.into()
}
}
<span class="doccomment">/// Sets whether or not the field must have a valid `Content-Type` header to be parsed.
///
/// Note that an empty `Content-Type` is also accepted, as the multipart specification defines
/// `text/plain` as the default for text fields.
</span><span class="kw">pub fn </span>validate_content_type(<span class="kw-2">mut </span><span class="self">self</span>, validate_content_type: bool) -&gt; <span class="self">Self </span>{
<span class="self">self</span>.validate_content_type = validate_content_type;
<span class="self">self
</span>}
}
<span class="kw">const </span>DEFAULT_CONFIG: TextConfig = TextConfig {
err_handler: <span class="prelude-val">None</span>,
validate_content_type: <span class="bool-val">true</span>,
};
<span class="kw">impl </span>Default <span class="kw">for </span>TextConfig {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
DEFAULT_CONFIG
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::io::Cursor;
<span class="kw">use </span>actix_multipart_rfc7578::client::multipart;
<span class="kw">use </span>actix_web::{http::StatusCode, web, App, HttpResponse, Responder};
<span class="kw">use </span><span class="kw">crate</span>::form::{
tests::send_form,
text::{Text, TextConfig},
MultipartForm,
};
<span class="attr">#[derive(MultipartForm)]
</span><span class="kw">struct </span>TextForm {
number: Text&lt;i32&gt;,
}
<span class="kw">async fn </span>test_text_route(form: MultipartForm&lt;TextForm&gt;) -&gt; <span class="kw">impl </span>Responder {
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>form.number, <span class="number">1025</span>);
HttpResponse::Ok().finish()
}
<span class="attr">#[actix_rt::test]
</span><span class="kw">async fn </span>test_content_type_validation() {
<span class="kw">let </span>srv = actix_test::start(|| {
App::new()
.route(<span class="string">"/"</span>, web::post().to(test_text_route))
.app_data(TextConfig::default().validate_content_type(<span class="bool-val">true</span>))
});
<span class="comment">// Deny because wrong content type
</span><span class="kw">let </span>bytes = Cursor::new(<span class="string">"1025"</span>);
<span class="kw">let </span><span class="kw-2">mut </span>form = multipart::Form::default();
form.add_reader_file_with_mime(<span class="string">"number"</span>, bytes, <span class="string">""</span>, mime::APPLICATION_OCTET_STREAM);
<span class="kw">let </span>response = send_form(<span class="kw-2">&amp;</span>srv, form, <span class="string">"/"</span>).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(response.status(), StatusCode::BAD_REQUEST);
<span class="comment">// Allow because correct content type
</span><span class="kw">let </span>bytes = Cursor::new(<span class="string">"1025"</span>);
<span class="kw">let </span><span class="kw-2">mut </span>form = multipart::Form::default();
form.add_reader_file_with_mime(<span class="string">"number"</span>, bytes, <span class="string">""</span>, mime::TEXT_PLAIN);
<span class="kw">let </span>response = send_form(<span class="kw-2">&amp;</span>srv, form, <span class="string">"/"</span>).<span class="kw">await</span>;
<span class="macro">assert_eq!</span>(response.status(), StatusCode::OK);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,123 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-multipart/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_multipart" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Multipart form support for Actix Web.
//! # Examples
//! ```no_run
//! use actix_web::{post, App, HttpServer, Responder};
//!
//! use actix_multipart::form::{json::Json as MPJson, tempfile::TempFile, MultipartForm};
//! use serde::Deserialize;
//!
//! #[derive(Debug, Deserialize)]
//! struct Metadata {
//! name: String,
//! }
//!
//! #[derive(Debug, MultipartForm)]
//! struct UploadForm {
//! #[multipart(limit = "100MB")]
//! file: TempFile,
//! json: MPJson&lt;Metadata&gt;,
//! }
//!
//! #[post("/videos")]
//! pub async fn post_video(MultipartForm(form): MultipartForm&lt;UploadForm&gt;) -&gt; impl Responder {
//! format!(
//! "Uploaded file {}, with size: {}",
//! form.json.name, form.file.size
//! )
//! }
//!
//! #[actix_web::main]
//! async fn main() -&gt; std::io::Result&lt;()&gt; {
//! HttpServer::new(move || App::new().service(post_video))
//! .bind(("127.0.0.1", 8080))?
//! .run()
//! .await
//! }
//! ```
</span><span class="attr">#![deny(rust_2018_idioms, nonstandard_style)]
#![warn(future_incompatible)]
#![allow(clippy::borrow_interior_mutable_const)]
#![doc(html_logo_url = <span class="string">"https://actix.rs/img/logo.png"</span>)]
#![doc(html_favicon_url = <span class="string">"https://actix.rs/favicon.ico"</span>)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
</span><span class="comment">// This allows us to use the actix_multipart_derive within this crate's tests
</span><span class="attr">#[cfg(test)]
</span><span class="kw">extern crate </span><span class="self">self </span><span class="kw">as </span>actix_multipart;
<span class="kw">mod </span>error;
<span class="kw">mod </span>extractor;
<span class="kw">pub mod </span>form;
<span class="kw">mod </span>server;
<span class="kw">pub mod </span>test;
<span class="kw">pub use </span><span class="self">self</span>::{
error::MultipartError,
server::{Field, Multipart},
test::{
create_form_data_payload_and_headers, create_form_data_payload_and_headers_with_boundary,
},
};
</code></pre></div></section></main></body></html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,435 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-multipart/src/test.rs`."><title>test.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_multipart" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>actix_web::http::header::{<span class="self">self</span>, HeaderMap};
<span class="kw">use </span>bytes::{BufMut <span class="kw">as _</span>, Bytes, BytesMut};
<span class="kw">use </span>mime::Mime;
<span class="kw">use </span>rand::{
distributions::{Alphanumeric, DistString <span class="kw">as _</span>},
thread_rng,
};
<span class="kw">const </span>CRLF: <span class="kw-2">&amp;</span>[u8] = <span class="string">b"\r\n"</span>;
<span class="kw">const </span>CRLF_CRLF: <span class="kw-2">&amp;</span>[u8] = <span class="string">b"\r\n\r\n"</span>;
<span class="kw">const </span>HYPHENS: <span class="kw-2">&amp;</span>[u8] = <span class="string">b"--"</span>;
<span class="kw">const </span>BOUNDARY_PREFIX: <span class="kw-2">&amp;</span>str = <span class="string">"------------------------"</span>;
<span class="doccomment">/// Constructs a `multipart/form-data` payload from bytes and metadata.
///
/// Returned header map can be extended or merged with existing headers.
///
/// Multipart boundary used is a random alphanumeric string.
///
/// # Examples
///
/// ```
/// use actix_multipart::test::create_form_data_payload_and_headers;
/// use actix_web::test::TestRequest;
/// use bytes::Bytes;
/// use memchr::memmem::find;
///
/// let (body, headers) = create_form_data_payload_and_headers(
/// "foo",
/// Some("lorem.txt".to_owned()),
/// Some(mime::TEXT_PLAIN_UTF_8),
/// Bytes::from_static(b"Lorem ipsum."),
/// );
///
/// assert!(find(&amp;body, b"foo").is_some());
/// assert!(find(&amp;body, b"lorem.txt").is_some());
/// assert!(find(&amp;body, b"text/plain; charset=utf-8").is_some());
/// assert!(find(&amp;body, b"Lorem ipsum.").is_some());
///
/// let req = TestRequest::default();
///
/// // merge header map into existing test request and set multipart body
/// let req = headers
/// .into_iter()
/// .fold(req, |req, hdr| req.insert_header(hdr))
/// .set_payload(body)
/// .to_http_request();
///
/// assert!(
/// req.headers()
/// .get("content-type")
/// .unwrap()
/// .to_str()
/// .unwrap()
/// .starts_with("multipart/form-data; boundary=\"")
/// );
/// ```
</span><span class="kw">pub fn </span>create_form_data_payload_and_headers(
name: <span class="kw-2">&amp;</span>str,
filename: <span class="prelude-ty">Option</span>&lt;String&gt;,
content_type: <span class="prelude-ty">Option</span>&lt;Mime&gt;,
file: Bytes,
) -&gt; (Bytes, HeaderMap) {
<span class="kw">let </span>boundary = Alphanumeric.sample_string(<span class="kw-2">&amp;mut </span>thread_rng(), <span class="number">32</span>);
create_form_data_payload_and_headers_with_boundary(
<span class="kw-2">&amp;</span>boundary,
name,
filename,
content_type,
file,
)
}
<span class="doccomment">/// Constructs a `multipart/form-data` payload from bytes and metadata with a fixed boundary.
///
/// See [`create_form_data_payload_and_headers`] for more details.
</span><span class="kw">pub fn </span>create_form_data_payload_and_headers_with_boundary(
boundary: <span class="kw-2">&amp;</span>str,
name: <span class="kw-2">&amp;</span>str,
filename: <span class="prelude-ty">Option</span>&lt;String&gt;,
content_type: <span class="prelude-ty">Option</span>&lt;Mime&gt;,
file: Bytes,
) -&gt; (Bytes, HeaderMap) {
<span class="kw">let </span><span class="kw-2">mut </span>buf = BytesMut::with_capacity(file.len() + <span class="number">128</span>);
<span class="kw">let </span>boundary_str = [BOUNDARY_PREFIX, boundary].concat();
<span class="kw">let </span>boundary = boundary_str.as_bytes();
buf.put(HYPHENS);
buf.put(boundary);
buf.put(CRLF);
buf.put(<span class="macro">format!</span>(<span class="string">"Content-Disposition: form-data; name=\"{name}\""</span>).as_bytes());
<span class="kw">if let </span><span class="prelude-val">Some</span>(filename) = filename {
buf.put(<span class="macro">format!</span>(<span class="string">"; filename=\"{filename}\""</span>).as_bytes());
}
buf.put(CRLF);
<span class="kw">if let </span><span class="prelude-val">Some</span>(ct) = content_type {
buf.put(<span class="macro">format!</span>(<span class="string">"Content-Type: {ct}"</span>).as_bytes());
buf.put(CRLF);
}
buf.put(<span class="macro">format!</span>(<span class="string">"Content-Length: {}"</span>, file.len()).as_bytes());
buf.put(CRLF_CRLF);
buf.put(file);
buf.put(CRLF);
buf.put(HYPHENS);
buf.put(boundary);
buf.put(HYPHENS);
buf.put(CRLF);
<span class="kw">let </span><span class="kw-2">mut </span>headers = HeaderMap::new();
headers.insert(
header::CONTENT_TYPE,
<span class="macro">format!</span>(<span class="string">"multipart/form-data; boundary=\"{boundary_str}\""</span>)
.parse()
.unwrap(),
);
(buf.freeze(), headers)
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::convert::Infallible;
<span class="kw">use </span>futures_util::stream;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">fn </span>find_boundary(headers: <span class="kw-2">&amp;</span>HeaderMap) -&gt; String {
headers
.get(<span class="string">"content-type"</span>)
.unwrap()
.to_str()
.unwrap()
.parse::&lt;mime::Mime&gt;()
.unwrap()
.get_param(mime::BOUNDARY)
.unwrap()
.as_str()
.to_owned()
}
<span class="attr">#[test]
</span><span class="kw">fn </span>wire_format() {
<span class="kw">let </span>(pl, headers) = create_form_data_payload_and_headers_with_boundary(
<span class="string">"qWeRtYuIoP"</span>,
<span class="string">"foo"</span>,
<span class="prelude-val">None</span>,
<span class="prelude-val">None</span>,
Bytes::from_static(<span class="string">b"Lorem ipsum dolor\nsit ame."</span>),
);
<span class="macro">assert_eq!</span>(
find_boundary(<span class="kw-2">&amp;</span>headers),
<span class="string">"------------------------qWeRtYuIoP"</span>,
);
<span class="macro">assert_eq!</span>(
std::str::from_utf8(<span class="kw-2">&amp;</span>pl).unwrap(),
<span class="string">"--------------------------qWeRtYuIoP\r\n\
Content-Disposition: form-data; name=\"foo\"\r\n\
Content-Length: 26\r\n\
\r\n\
Lorem ipsum dolor\n\
sit ame.\r\n\
--------------------------qWeRtYuIoP--\r\n"</span>,
);
<span class="kw">let </span>(pl, _headers) = create_form_data_payload_and_headers_with_boundary(
<span class="string">"qWeRtYuIoP"</span>,
<span class="string">"foo"</span>,
<span class="prelude-val">Some</span>(<span class="string">"Lorem.txt"</span>.to_owned()),
<span class="prelude-val">Some</span>(mime::TEXT_PLAIN_UTF_8),
Bytes::from_static(<span class="string">b"Lorem ipsum dolor\nsit ame."</span>),
);
<span class="macro">assert_eq!</span>(
std::str::from_utf8(<span class="kw-2">&amp;</span>pl).unwrap(),
<span class="string">"--------------------------qWeRtYuIoP\r\n\
Content-Disposition: form-data; name=\"foo\"; filename=\"Lorem.txt\"\r\n\
Content-Type: text/plain; charset=utf-8\r\n\
Content-Length: 26\r\n\
\r\n\
Lorem ipsum dolor\n\
sit ame.\r\n\
--------------------------qWeRtYuIoP--\r\n"</span>,
);
}
<span class="doccomment">/// Test using an external library to prevent the two-wrongs-make-a-right class of errors.
</span><span class="attr">#[actix_web::test]
</span><span class="kw">async fn </span>ecosystem_compat() {
<span class="kw">let </span>(pl, headers) = create_form_data_payload_and_headers(
<span class="string">"foo"</span>,
<span class="prelude-val">None</span>,
<span class="prelude-val">None</span>,
Bytes::from_static(<span class="string">b"Lorem ipsum dolor\nsit ame."</span>),
);
<span class="kw">let </span>boundary = find_boundary(<span class="kw-2">&amp;</span>headers);
<span class="kw">let </span>pl = stream::once(<span class="kw">async </span>{ <span class="prelude-val">Ok</span>::&lt;<span class="kw">_</span>, Infallible&gt;(pl) });
<span class="kw">let </span><span class="kw-2">mut </span>form = multer::Multipart::new(pl, boundary);
<span class="kw">let </span>field = form.next_field().<span class="kw">await</span>.unwrap().unwrap();
<span class="macro">assert_eq!</span>(field.name().unwrap(), <span class="string">"foo"</span>);
<span class="macro">assert_eq!</span>(field.file_name(), <span class="prelude-val">None</span>);
<span class="macro">assert_eq!</span>(field.content_type(), <span class="prelude-val">None</span>);
<span class="macro">assert!</span>(field.bytes().<span class="kw">await</span>.unwrap().starts_with(<span class="string">b"Lorem"</span>));
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,631 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-multipart-derive/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_multipart_derive" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
<a href="#292" id="292">292</a>
<a href="#293" id="293">293</a>
<a href="#294" id="294">294</a>
<a href="#295" id="295">295</a>
<a href="#296" id="296">296</a>
<a href="#297" id="297">297</a>
<a href="#298" id="298">298</a>
<a href="#299" id="299">299</a>
<a href="#300" id="300">300</a>
<a href="#301" id="301">301</a>
<a href="#302" id="302">302</a>
<a href="#303" id="303">303</a>
<a href="#304" id="304">304</a>
<a href="#305" id="305">305</a>
<a href="#306" id="306">306</a>
<a href="#307" id="307">307</a>
<a href="#308" id="308">308</a>
<a href="#309" id="309">309</a>
<a href="#310" id="310">310</a>
<a href="#311" id="311">311</a>
<a href="#312" id="312">312</a>
<a href="#313" id="313">313</a>
<a href="#314" id="314">314</a>
<a href="#315" id="315">315</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Multipart form derive macro for Actix Web.
//!
//! See [`macro@MultipartForm`] for usage examples.
</span><span class="attr">#![deny(rust_2018_idioms, nonstandard_style)]
#![warn(future_incompatible)]
#![doc(html_logo_url = <span class="string">"https://actix.rs/img/logo.png"</span>)]
#![doc(html_favicon_url = <span class="string">"https://actix.rs/favicon.ico"</span>)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
</span><span class="kw">use </span>std::collections::HashSet;
<span class="kw">use </span>darling::{FromDeriveInput, FromField, FromMeta};
<span class="kw">use </span>parse_size::parse_size;
<span class="kw">use </span>proc_macro::TokenStream;
<span class="kw">use </span>proc_macro2::Ident;
<span class="kw">use </span>quote::quote;
<span class="kw">use </span>syn::{parse_macro_input, Type};
<span class="attr">#[derive(FromMeta)]
</span><span class="kw">enum </span>DuplicateField {
Ignore,
Deny,
Replace,
}
<span class="kw">impl </span>Default <span class="kw">for </span>DuplicateField {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::Ignore
}
}
<span class="attr">#[derive(FromDeriveInput, Default)]
#[darling(attributes(multipart), default)]
</span><span class="kw">struct </span>MultipartFormAttrs {
deny_unknown_fields: bool,
duplicate_field: DuplicateField,
}
<span class="attr">#[derive(FromField, Default)]
#[darling(attributes(multipart), default)]
</span><span class="kw">struct </span>FieldAttrs {
rename: <span class="prelude-ty">Option</span>&lt;String&gt;,
limit: <span class="prelude-ty">Option</span>&lt;String&gt;,
}
<span class="kw">struct </span>ParsedField&lt;<span class="lifetime">'t</span>&gt; {
serialization_name: String,
rust_name: <span class="kw-2">&amp;</span><span class="lifetime">'t </span>Ident,
limit: <span class="prelude-ty">Option</span>&lt;usize&gt;,
ty: <span class="kw-2">&amp;</span><span class="lifetime">'t </span>Type,
}
<span class="doccomment">/// Implements `MultipartCollect` for a struct so that it can be used with the `MultipartForm`
/// extractor.
///
/// # Basic Use
///
/// Each field type should implement the `FieldReader` trait:
///
/// ```
/// use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm};
///
/// #[derive(MultipartForm)]
/// struct ImageUpload {
/// description: Text&lt;String&gt;,
/// timestamp: Text&lt;i64&gt;,
/// image: TempFile,
/// }
/// ```
///
/// # Optional and List Fields
///
/// You can also use `Vec&lt;T&gt;` and `Option&lt;T&gt;` provided that `T: FieldReader`.
///
/// A [`Vec`] field corresponds to an upload with multiple parts under the [same field
/// name](https://www.rfc-editor.org/rfc/rfc7578#section-4.3).
///
/// ```
/// use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm};
///
/// #[derive(MultipartForm)]
/// struct Form {
/// category: Option&lt;Text&lt;String&gt;&gt;,
/// files: Vec&lt;TempFile&gt;,
/// }
/// ```
///
/// # Field Renaming
///
/// You can use the `#[multipart(rename = "foo")]` attribute to receive a field by a different name.
///
/// ```
/// use actix_multipart::form::{tempfile::TempFile, MultipartForm};
///
/// #[derive(MultipartForm)]
/// struct Form {
/// #[multipart(rename = "files[]")]
/// files: Vec&lt;TempFile&gt;,
/// }
/// ```
///
/// # Field Limits
///
/// You can use the `#[multipart(limit = "&lt;size&gt;")]` attribute to set field level limits. The limit
/// string is parsed using [parse_size].
///
/// Note: the form is also subject to the global limits configured using `MultipartFormConfig`.
///
/// ```
/// use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm};
///
/// #[derive(MultipartForm)]
/// struct Form {
/// #[multipart(limit = "2 KiB")]
/// description: Text&lt;String&gt;,
///
/// #[multipart(limit = "512 MiB")]
/// files: Vec&lt;TempFile&gt;,
/// }
/// ```
///
/// # Unknown Fields
///
/// By default fields with an unknown name are ignored. They can be rejected using the
/// `#[multipart(deny_unknown_fields)]` attribute:
///
/// ```
/// # use actix_multipart::form::MultipartForm;
/// #[derive(MultipartForm)]
/// #[multipart(deny_unknown_fields)]
/// struct Form { }
/// ```
///
/// # Duplicate Fields
///
/// The behaviour for when multiple fields with the same name are received can be changed using the
/// `#[multipart(duplicate_field = "&lt;behavior&gt;")]` attribute:
///
/// - "ignore": (default) Extra fields are ignored. I.e., the first one is persisted.
/// - "deny": A `MultipartError::UnsupportedField` error response is returned.
/// - "replace": Each field is processed, but only the last one is persisted.
///
/// Note that `Vec` fields will ignore this option.
///
/// ```
/// # use actix_multipart::form::MultipartForm;
/// #[derive(MultipartForm)]
/// #[multipart(duplicate_field = "deny")]
/// struct Form { }
/// ```
///
/// [parse_size]: https://docs.rs/parse-size/1/parse_size
</span><span class="attr">#[proc_macro_derive(MultipartForm, attributes(multipart))]
</span><span class="kw">pub fn </span>impl_multipart_form(input: proc_macro::TokenStream) -&gt; proc_macro::TokenStream {
<span class="kw">let </span>input: syn::DeriveInput = <span class="macro">parse_macro_input!</span>(input);
<span class="kw">let </span>name = <span class="kw-2">&amp;</span>input.ident;
<span class="kw">let </span>data_struct = <span class="kw">match </span><span class="kw-2">&amp;</span>input.data {
syn::Data::Struct(data_struct) =&gt; data_struct,
<span class="kw">_ </span>=&gt; {
<span class="kw">return </span>compile_err(syn::Error::new(
input.ident.span(),
<span class="string">"`MultipartForm` can only be derived for structs"</span>,
))
}
};
<span class="kw">let </span>fields = <span class="kw">match </span><span class="kw-2">&amp;</span>data_struct.fields {
syn::Fields::Named(fields_named) =&gt; fields_named,
<span class="kw">_ </span>=&gt; {
<span class="kw">return </span>compile_err(syn::Error::new(
input.ident.span(),
<span class="string">"`MultipartForm` can only be derived for a struct with named fields"</span>,
))
}
};
<span class="kw">let </span>attrs = <span class="kw">match </span>MultipartFormAttrs::from_derive_input(<span class="kw-2">&amp;</span>input) {
<span class="prelude-val">Ok</span>(attrs) =&gt; attrs,
<span class="prelude-val">Err</span>(err) =&gt; <span class="kw">return </span>err.write_errors().into(),
};
<span class="comment">// Parse the field attributes
</span><span class="kw">let </span>parsed = <span class="kw">match </span>fields
.named
.iter()
.map(|field| {
<span class="kw">let </span>rust_name = field.ident.as_ref().unwrap();
<span class="kw">let </span>attrs = FieldAttrs::from_field(field).map_err(|err| err.write_errors())<span class="question-mark">?</span>;
<span class="kw">let </span>serialization_name = attrs.rename.unwrap_or_else(|| rust_name.to_string());
<span class="kw">let </span>limit = <span class="kw">match </span>attrs.limit.map(|limit| <span class="kw">match </span>parse_size(<span class="kw-2">&amp;</span>limit) {
<span class="prelude-val">Ok</span>(size) =&gt; <span class="prelude-val">Ok</span>(usize::try_from(size).unwrap()),
<span class="prelude-val">Err</span>(err) =&gt; <span class="prelude-val">Err</span>(syn::Error::new(
field.ident.as_ref().unwrap().span(),
<span class="macro">format!</span>(<span class="string">"Could not parse size limit `{}`: {}"</span>, limit, err),
)),
}) {
<span class="prelude-val">Some</span>(<span class="prelude-val">Err</span>(err)) =&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(compile_err(err)),
limit =&gt; limit.map(Result::unwrap),
};
<span class="prelude-val">Ok</span>(ParsedField {
serialization_name,
rust_name,
limit,
ty: <span class="kw-2">&amp;</span>field.ty,
})
})
.collect::&lt;<span class="prelude-ty">Result</span>&lt;Vec&lt;<span class="kw">_</span>&gt;, TokenStream&gt;&gt;()
{
<span class="prelude-val">Ok</span>(attrs) =&gt; attrs,
<span class="prelude-val">Err</span>(err) =&gt; <span class="kw">return </span>err,
};
<span class="comment">// Check that field names are unique
</span><span class="kw">let </span><span class="kw-2">mut </span>set = HashSet::new();
<span class="kw">for </span>field <span class="kw">in </span><span class="kw-2">&amp;</span>parsed {
<span class="kw">if </span>!set.insert(field.serialization_name.clone()) {
<span class="kw">return </span>compile_err(syn::Error::new(
field.rust_name.span(),
<span class="macro">format!</span>(<span class="string">"Multiple fields named: `{}`"</span>, field.serialization_name),
));
}
}
<span class="comment">// Return value when a field name is not supported by the form
</span><span class="kw">let </span>unknown_field_result = <span class="kw">if </span>attrs.deny_unknown_fields {
<span class="macro">quote!</span>(::std::result::Result::Err(
::actix_multipart::MultipartError::UnsupportedField(field.name().to_string())
))
} <span class="kw">else </span>{
<span class="macro">quote!</span>(::std::result::Result::Ok(()))
};
<span class="comment">// Value for duplicate action
</span><span class="kw">let </span>duplicate_field = <span class="kw">match </span>attrs.duplicate_field {
DuplicateField::Ignore =&gt; <span class="macro">quote!</span>(::actix_multipart::form::DuplicateField::Ignore),
DuplicateField::Deny =&gt; <span class="macro">quote!</span>(::actix_multipart::form::DuplicateField::Deny),
DuplicateField::Replace =&gt; <span class="macro">quote!</span>(::actix_multipart::form::DuplicateField::Replace),
};
<span class="comment">// limit() implementation
</span><span class="kw">let </span><span class="kw-2">mut </span>limit_impl = <span class="macro">quote!</span>();
<span class="kw">for </span>field <span class="kw">in </span><span class="kw-2">&amp;</span>parsed {
<span class="kw">let </span>name = <span class="kw-2">&amp;</span>field.serialization_name;
<span class="kw">if let </span><span class="prelude-val">Some</span>(value) = field.limit {
limit_impl.extend(<span class="macro">quote!</span>(
#name =&gt; ::std::option::Option::Some(#value),
));
}
}
<span class="comment">// handle_field() implementation
</span><span class="kw">let </span><span class="kw-2">mut </span>handle_field_impl = <span class="macro">quote!</span>();
<span class="kw">for </span>field <span class="kw">in </span><span class="kw-2">&amp;</span>parsed {
<span class="kw">let </span>name = <span class="kw-2">&amp;</span>field.serialization_name;
<span class="kw">let </span>ty = <span class="kw-2">&amp;</span>field.ty;
handle_field_impl.extend(<span class="macro">quote!</span>(
#name =&gt; ::std::boxed::Box::pin(
&lt;#ty <span class="kw">as </span>::actix_multipart::form::FieldGroupReader&gt;::handle_field(req, field, limits, state, #duplicate_field)
),
));
}
<span class="comment">// from_state() implementation
</span><span class="kw">let </span><span class="kw-2">mut </span>from_state_impl = <span class="macro">quote!</span>();
<span class="kw">for </span>field <span class="kw">in </span><span class="kw-2">&amp;</span>parsed {
<span class="kw">let </span>name = <span class="kw-2">&amp;</span>field.serialization_name;
<span class="kw">let </span>rust_name = <span class="kw-2">&amp;</span>field.rust_name;
<span class="kw">let </span>ty = <span class="kw-2">&amp;</span>field.ty;
from_state_impl.extend(<span class="macro">quote!</span>(
#rust_name: &lt;#ty <span class="kw">as </span>::actix_multipart::form::FieldGroupReader&gt;::from_state(#name, <span class="kw-2">&amp;mut </span>state)<span class="question-mark">?</span>,
));
}
<span class="kw">let </span>gen = <span class="macro">quote!</span> {
<span class="kw">impl </span>::actix_multipart::form::MultipartCollect <span class="kw">for </span>#name {
<span class="kw">fn </span>limit(field_name: <span class="kw-2">&amp;</span>str) -&gt; ::std::option::Option&lt;usize&gt; {
<span class="kw">match </span>field_name {
#limit_impl
<span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
}
}
<span class="kw">fn </span>handle_field&lt;<span class="lifetime">'t</span>&gt;(
req: <span class="kw-2">&amp;</span><span class="lifetime">'t </span>::actix_web::HttpRequest,
field: ::actix_multipart::Field,
limits: <span class="kw-2">&amp;</span><span class="lifetime">'t </span><span class="kw-2">mut </span>::actix_multipart::form::Limits,
state: <span class="kw-2">&amp;</span><span class="lifetime">'t </span><span class="kw-2">mut </span>::actix_multipart::form::State,
) -&gt; ::std::pin::Pin&lt;::std::boxed::Box&lt;<span class="kw">dyn </span>::std::future::Future&lt;Output = ::std::result::Result&lt;(), ::actix_multipart::MultipartError&gt;&gt; + <span class="lifetime">'t</span>&gt;&gt; {
<span class="kw">match </span>field.name() {
#handle_field_impl
<span class="kw">_ </span>=&gt; <span class="kw">return </span>::std::boxed::Box::pin(::std::future::ready(#unknown_field_result)),
}
}
<span class="kw">fn </span>from_state(<span class="kw-2">mut </span>state: ::actix_multipart::form::State) -&gt; ::std::result::Result&lt;<span class="self">Self</span>, ::actix_multipart::MultipartError&gt; {
<span class="prelude-val">Ok</span>(<span class="self">Self </span>{
#from_state_impl
})
}
}
};
gen.into()
}
<span class="doccomment">/// Transform a syn error into a token stream for returning.
</span><span class="kw">fn </span>compile_err(err: syn::Error) -&gt; TokenStream {
TokenStream::from(err.to_compile_error())
}
</code></pre></div></section></main></body></html>

1603
src/actix_router/de.rs.html Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,63 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-router/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_router" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Resource path matching and router.
</span><span class="attr">#![deny(rust_2018_idioms, nonstandard_style)]
#![warn(future_incompatible)]
#![doc(html_logo_url = <span class="string">"https://actix.rs/img/logo.png"</span>)]
#![doc(html_favicon_url = <span class="string">"https://actix.rs/favicon.ico"</span>)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
</span><span class="kw">mod </span>de;
<span class="kw">mod </span>path;
<span class="kw">mod </span>pattern;
<span class="kw">mod </span>quoter;
<span class="kw">mod </span>regex_set;
<span class="kw">mod </span>resource;
<span class="kw">mod </span>resource_path;
<span class="kw">mod </span>router;
<span class="attr">#[cfg(feature = <span class="string">"http"</span>)]
</span><span class="kw">mod </span>url;
<span class="attr">#[cfg(feature = <span class="string">"http"</span>)]
</span><span class="kw">pub use </span><span class="self">self</span>::url::Url;
<span class="kw">pub use </span><span class="self">self</span>::{
de::PathDeserializer,
path::Path,
pattern::{IntoPatterns, Patterns},
quoter::Quoter,
resource::ResourceDef,
resource_path::{Resource, ResourcePath},
router::{ResourceId, Router, RouterBuilder},
};
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,523 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-router/src/path.rs`."><title>path.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_router" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
</pre></div><pre class="rust"><code><span class="kw">use </span>std::{
borrow::Cow,
ops::{DerefMut, Index},
};
<span class="kw">use </span>serde::{de, Deserialize};
<span class="kw">use crate</span>::{de::PathDeserializer, Resource, ResourcePath};
<span class="attr">#[derive(Debug, Clone)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">enum </span>PathItem {
Static(Cow&lt;<span class="lifetime">'static</span>, str&gt;),
Segment(u16, u16),
}
<span class="kw">impl </span>Default <span class="kw">for </span>PathItem {
<span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<span class="self">Self</span>::Static(Cow::Borrowed(<span class="string">""</span>))
}
}
<span class="doccomment">/// Resource path match information.
///
/// If resource path contains variable patterns, `Path` stores them.
</span><span class="attr">#[derive(Debug, Clone, Default)]
</span><span class="kw">pub struct </span>Path&lt;T&gt; {
<span class="doccomment">/// Full path representation.
</span>path: T,
<span class="doccomment">/// Number of characters in `path` that have been processed into `segments`.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) skip: u16,
<span class="doccomment">/// List of processed dynamic segments; name-&gt;value pairs.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) segments: Vec&lt;(Cow&lt;<span class="lifetime">'static</span>, str&gt;, PathItem)&gt;,
}
<span class="kw">impl</span>&lt;T: ResourcePath&gt; Path&lt;T&gt; {
<span class="kw">pub fn </span>new(path: T) -&gt; Path&lt;T&gt; {
Path {
path,
skip: <span class="number">0</span>,
segments: Vec::new(),
}
}
<span class="doccomment">/// Returns reference to inner path instance.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>get_ref(<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>.path
}
<span class="doccomment">/// Returns mutable reference to inner path instance.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>get_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>.path
}
<span class="doccomment">/// Returns full path as a string.
</span><span class="attr">#[inline]
</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="self">self</span>.path.path()
}
<span class="doccomment">/// Returns unprocessed part of the path.
///
/// Returns empty string if no more is to be processed.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>unprocessed(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="comment">// clamp skip to path length
</span><span class="kw">let </span>skip = (<span class="self">self</span>.skip <span class="kw">as </span>usize).min(<span class="self">self</span>.as_str().len());
<span class="kw-2">&amp;</span><span class="self">self</span>.path.path()[skip..]
}
<span class="doccomment">/// Returns unprocessed part of the path.
</span><span class="attr">#[doc(hidden)]
#[deprecated(since = <span class="string">"0.6.0"</span>, note = <span class="string">"Use `.as_str()` or `.unprocessed()`."</span>)]
#[inline]
</span><span class="kw">pub fn </span>path(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="kw">let </span>skip = <span class="self">self</span>.skip <span class="kw">as </span>usize;
<span class="kw">let </span>path = <span class="self">self</span>.path.path();
<span class="kw">if </span>skip &lt;= path.len() {
<span class="kw-2">&amp;</span>path[skip..]
} <span class="kw">else </span>{
<span class="string">""
</span>}
}
<span class="doccomment">/// Set new path.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>set(<span class="kw-2">&amp;mut </span><span class="self">self</span>, path: T) {
<span class="self">self</span>.path = path;
<span class="self">self</span>.skip = <span class="number">0</span>;
<span class="self">self</span>.segments.clear();
}
<span class="doccomment">/// Reset state.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>reset(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<span class="self">self</span>.skip = <span class="number">0</span>;
<span class="self">self</span>.segments.clear();
}
<span class="doccomment">/// Skip first `n` chars in path.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>skip(<span class="kw-2">&amp;mut </span><span class="self">self</span>, n: u16) {
<span class="self">self</span>.skip += n;
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>add(<span class="kw-2">&amp;mut </span><span class="self">self</span>, name: <span class="kw">impl </span>Into&lt;Cow&lt;<span class="lifetime">'static</span>, str&gt;&gt;, value: PathItem) {
<span class="kw">match </span>value {
PathItem::Static(seg) =&gt; <span class="self">self</span>.segments.push((name.into(), PathItem::Static(seg))),
PathItem::Segment(begin, end) =&gt; <span class="self">self</span>.segments.push((
name.into(),
PathItem::Segment(<span class="self">self</span>.skip + begin, <span class="self">self</span>.skip + end),
)),
}
}
<span class="attr">#[doc(hidden)]
</span><span class="kw">pub fn </span>add_static(
<span class="kw-2">&amp;mut </span><span class="self">self</span>,
name: <span class="kw">impl </span>Into&lt;Cow&lt;<span class="lifetime">'static</span>, str&gt;&gt;,
value: <span class="kw">impl </span>Into&lt;Cow&lt;<span class="lifetime">'static</span>, str&gt;&gt;,
) {
<span class="self">self</span>.segments
.push((name.into(), PathItem::Static(value.into())));
}
<span class="doccomment">/// Check if there are any matched patterns.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>is_empty(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="self">self</span>.segments.is_empty()
}
<span class="doccomment">/// Returns number of interpolated segments.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>segment_count(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<span class="self">self</span>.segments.len()
}
<span class="doccomment">/// Get matched parameter by name without type conversion
</span><span class="kw">pub fn </span>get(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt; {
<span class="kw">for </span>(seg_name, val) <span class="kw">in </span><span class="self">self</span>.segments.iter() {
<span class="kw">if </span>name == seg_name {
<span class="kw">return match </span>val {
PathItem::Static(<span class="kw-2">ref </span>s) =&gt; <span class="prelude-val">Some</span>(s),
PathItem::Segment(s, e) =&gt; {
<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.path.path()[(<span class="kw-2">*</span>s <span class="kw">as </span>usize)..(<span class="kw-2">*</span>e <span class="kw">as </span>usize)])
}
};
}
}
<span class="prelude-val">None
</span>}
<span class="doccomment">/// Returns matched parameter by name.
///
/// If keyed parameter is not available empty string is used as default value.
</span><span class="kw">pub fn </span>query(<span class="kw-2">&amp;</span><span class="self">self</span>, key: <span class="kw-2">&amp;</span>str) -&gt; <span class="kw-2">&amp;</span>str {
<span class="self">self</span>.get(key).unwrap_or_default()
}
<span class="doccomment">/// Return iterator to items in parameter container.
</span><span class="kw">pub fn </span>iter(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; PathIter&lt;<span class="lifetime">'_</span>, T&gt; {
PathIter {
idx: <span class="number">0</span>,
params: <span class="self">self</span>,
}
}
<span class="doccomment">/// Deserializes matching parameters to a specified type `U`.
///
/// # Errors
///
/// Returns error when dynamic path segments cannot be deserialized into a `U` type.
</span><span class="kw">pub fn </span>load&lt;<span class="lifetime">'de</span>, U: Deserialize&lt;<span class="lifetime">'de</span>&gt;&gt;(<span class="kw-2">&amp;</span><span class="lifetime">'de </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;U, de::value::Error&gt; {
Deserialize::deserialize(PathDeserializer::new(<span class="self">self</span>))
}
}
<span class="attr">#[derive(Debug)]
</span><span class="kw">pub struct </span>PathIter&lt;<span class="lifetime">'a</span>, T&gt; {
idx: usize,
params: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>Path&lt;T&gt;,
}
<span class="kw">impl</span>&lt;<span class="lifetime">'a</span>, T: ResourcePath&gt; Iterator <span class="kw">for </span>PathIter&lt;<span class="lifetime">'a</span>, T&gt; {
<span class="kw">type </span>Item = (<span class="kw-2">&amp;</span><span class="lifetime">'a </span>str, <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str);
<span class="attr">#[inline]
</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="kw-2">&amp;</span><span class="lifetime">'a </span>str, <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str)&gt; {
<span class="kw">if </span><span class="self">self</span>.idx &lt; <span class="self">self</span>.params.segment_count() {
<span class="kw">let </span>idx = <span class="self">self</span>.idx;
<span class="kw">let </span>res = <span class="kw">match </span><span class="self">self</span>.params.segments[idx].<span class="number">1 </span>{
PathItem::Static(<span class="kw-2">ref </span>s) =&gt; s,
PathItem::Segment(s, e) =&gt; <span class="kw-2">&amp;</span><span class="self">self</span>.params.path.path()[(s <span class="kw">as </span>usize)..(e <span class="kw">as </span>usize)],
};
<span class="self">self</span>.idx += <span class="number">1</span>;
<span class="kw">return </span><span class="prelude-val">Some</span>((<span class="kw-2">&amp;</span><span class="self">self</span>.params.segments[idx].<span class="number">0</span>, res));
}
<span class="prelude-val">None
</span>}
}
<span class="kw">impl</span>&lt;<span class="lifetime">'a</span>, T: ResourcePath&gt; Index&lt;<span class="kw-2">&amp;</span><span class="lifetime">'a </span>str&gt; <span class="kw">for </span>Path&lt;T&gt; {
<span class="kw">type </span>Output = str;
<span class="kw">fn </span>index(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str) -&gt; <span class="kw-2">&amp;</span>str {
<span class="self">self</span>.get(name)
.expect(<span class="string">"Value for parameter is not available"</span>)
}
}
<span class="kw">impl</span>&lt;T: ResourcePath&gt; Index&lt;usize&gt; <span class="kw">for </span>Path&lt;T&gt; {
<span class="kw">type </span>Output = str;
<span class="kw">fn </span>index(<span class="kw-2">&amp;</span><span class="self">self</span>, idx: usize) -&gt; <span class="kw-2">&amp;</span>str {
<span class="kw">match </span><span class="self">self</span>.segments[idx].<span class="number">1 </span>{
PathItem::Static(<span class="kw-2">ref </span>s) =&gt; s,
PathItem::Segment(s, e) =&gt; <span class="kw-2">&amp;</span><span class="self">self</span>.path.path()[(s <span class="kw">as </span>usize)..(e <span class="kw">as </span>usize)],
}
}
}
<span class="kw">impl</span>&lt;T: ResourcePath&gt; Resource <span class="kw">for </span>Path&lt;T&gt; {
<span class="kw">type </span>Path = T;
<span class="kw">fn </span>resource_path(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>Path&lt;<span class="self">Self</span>::Path&gt; {
<span class="self">self
</span>}
}
<span class="kw">impl</span>&lt;T, P&gt; Resource <span class="kw">for </span>T
<span class="kw">where
</span>T: DerefMut&lt;Target = Path&lt;P&gt;&gt;,
P: ResourcePath,
{
<span class="kw">type </span>Path = P;
<span class="kw">fn </span>resource_path(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>Path&lt;<span class="self">Self</span>::Path&gt; {
<span class="kw-2">&amp;mut *</span><span class="self">self
</span>}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::cell::RefCell;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[allow(clippy::needless_borrow)]
#[test]
</span><span class="kw">fn </span>deref_impls() {
<span class="kw">let </span><span class="kw-2">mut </span>foo = Path::new(<span class="string">"/foo"</span>);
<span class="kw">let _ </span>= (<span class="kw-2">&amp;mut </span>foo).resource_path();
<span class="kw">let </span>foo = RefCell::new(foo);
<span class="kw">let _ </span>= foo.borrow_mut().resource_path();
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,185 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-router/src/pattern.rs`."><title>pattern.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_router" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
</pre></div><pre class="rust"><code><span class="doccomment">/// One or many patterns.
</span><span class="attr">#[derive(Debug, Clone, PartialEq, Eq, Hash)]
</span><span class="kw">pub enum </span>Patterns {
Single(String),
List(Vec&lt;String&gt;),
}
<span class="kw">impl </span>Patterns {
<span class="kw">pub fn </span>is_empty(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<span class="kw">match </span><span class="self">self </span>{
Patterns::Single(<span class="kw">_</span>) =&gt; <span class="bool-val">false</span>,
Patterns::List(pats) =&gt; pats.is_empty(),
}
}
}
<span class="doccomment">/// Helper trait for type that could be converted to one or more path patterns.
</span><span class="kw">pub trait </span>IntoPatterns {
<span class="kw">fn </span>patterns(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Patterns;
}
<span class="kw">impl </span>IntoPatterns <span class="kw">for </span>String {
<span class="kw">fn </span>patterns(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Patterns {
Patterns::Single(<span class="self">self</span>.clone())
}
}
<span class="kw">impl </span>IntoPatterns <span class="kw">for </span><span class="kw-2">&amp;</span>String {
<span class="kw">fn </span>patterns(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Patterns {
(<span class="kw-2">*</span><span class="self">self</span>).patterns()
}
}
<span class="kw">impl </span>IntoPatterns <span class="kw">for </span>str {
<span class="kw">fn </span>patterns(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Patterns {
Patterns::Single(<span class="self">self</span>.to_owned())
}
}
<span class="kw">impl </span>IntoPatterns <span class="kw">for </span><span class="kw-2">&amp;</span>str {
<span class="kw">fn </span>patterns(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Patterns {
(<span class="kw-2">*</span><span class="self">self</span>).patterns()
}
}
<span class="kw">impl </span>IntoPatterns <span class="kw">for </span>bytestring::ByteString {
<span class="kw">fn </span>patterns(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Patterns {
Patterns::Single(<span class="self">self</span>.to_string())
}
}
<span class="kw">impl </span>IntoPatterns <span class="kw">for </span>Patterns {
<span class="kw">fn </span>patterns(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Patterns {
<span class="self">self</span>.clone()
}
}
<span class="kw">impl</span>&lt;T: AsRef&lt;str&gt;&gt; IntoPatterns <span class="kw">for </span>Vec&lt;T&gt; {
<span class="kw">fn </span>patterns(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Patterns {
<span class="kw">let </span><span class="kw-2">mut </span>patterns = <span class="self">self</span>.iter().map(|v| v.as_ref().to_owned());
<span class="kw">match </span>patterns.size_hint() {
(<span class="number">1</span>, <span class="kw">_</span>) =&gt; Patterns::Single(patterns.next().unwrap()),
<span class="kw">_ </span>=&gt; Patterns::List(patterns.collect()),
}
}
}
<span class="macro">macro_rules!</span> array_patterns_single ((<span class="macro-nonterminal">$tp</span>:ty) =&gt; {
<span class="kw">impl </span>IntoPatterns <span class="kw">for </span>[<span class="macro-nonterminal">$tp</span>; <span class="number">1</span>] {
<span class="kw">fn </span>patterns(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Patterns {
Patterns::Single(<span class="self">self</span>[<span class="number">0</span>].to_owned())
}
}
});
<span class="macro">macro_rules!</span> array_patterns_multiple ((<span class="macro-nonterminal">$tp</span>:ty, <span class="macro-nonterminal">$str_fn</span>:expr, $(<span class="macro-nonterminal">$num</span>:tt) +) =&gt; {
<span class="comment">// for each array length specified in space-separated $num
</span>$(
<span class="kw">impl </span>IntoPatterns <span class="kw">for </span>[<span class="macro-nonterminal">$tp</span>; <span class="macro-nonterminal">$num</span>] {
<span class="kw">fn </span>patterns(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Patterns {
Patterns::List(<span class="self">self</span>.iter().map(<span class="macro-nonterminal">$str_fn</span>).collect())
}
}
)+
});
<span class="macro">array_patterns_single!</span>(<span class="kw-2">&amp;</span>str);
<span class="macro">array_patterns_multiple!</span>(<span class="kw-2">&amp;</span>str, |<span class="kw-2">&amp;</span>v| v.to_owned(), <span class="number">2 3 4 5 6 7 8 9 10 11 12 13 14 15 16</span>);
<span class="macro">array_patterns_single!</span>(String);
<span class="macro">array_patterns_multiple!</span>(String, |v| v.clone(), <span class="number">2 3 4 5 6 7 8 9 10 11 12 13 14 15 16</span>);
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,345 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-router/src/quoter.rs`."><title>quoter.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_router" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
</pre></div><pre class="rust"><code><span class="doccomment">/// Partial percent-decoding.
///
/// Performs percent-decoding on a slice but can selectively skip decoding certain sequences.
///
/// # Examples
/// ```
/// # use actix_router::Quoter;
/// // + is set as a protected character and will not be decoded...
/// let q = Quoter::new(&amp;[], b"+");
///
/// // ...but the other encoded characters (like the hyphen below) will.
/// assert_eq!(q.requote(b"/a%2Db%2Bc").unwrap(), b"/a-b%2Bc");
/// ```
</span><span class="kw">pub struct </span>Quoter {
<span class="doccomment">/// Simple bit-map of protected values in the 0-127 ASCII range.
</span>protected_table: AsciiBitmap,
}
<span class="kw">impl </span>Quoter {
<span class="doccomment">/// Constructs a new `Quoter` instance given a set of protected ASCII bytes.
///
/// The first argument is ignored but is kept for backward compatibility.
///
/// # Panics
/// Panics if any of the `protected` bytes are not in the 0-127 ASCII range.
</span><span class="kw">pub fn </span>new(<span class="kw">_</span>: <span class="kw-2">&amp;</span>[u8], protected: <span class="kw-2">&amp;</span>[u8]) -&gt; Quoter {
<span class="kw">let </span><span class="kw-2">mut </span>protected_table = AsciiBitmap::default();
<span class="comment">// prepare protected table
</span><span class="kw">for </span><span class="kw-2">&amp;</span>ch <span class="kw">in </span>protected {
protected_table.set_bit(ch);
}
Quoter { protected_table }
}
<span class="doccomment">/// Decodes the next escape sequence, if any, and advances `val`.
</span><span class="attr">#[inline(always)]
</span><span class="kw">fn </span>decode_next&lt;<span class="lifetime">'a</span>&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, val: <span class="kw-2">&amp;mut &amp;</span><span class="lifetime">'a </span>[u8]) -&gt; <span class="prelude-ty">Option</span>&lt;(<span class="kw-2">&amp;</span><span class="lifetime">'a </span>[u8], u8)&gt; {
<span class="kw">for </span>i <span class="kw">in </span><span class="number">0</span>..val.len() {
<span class="kw">if let </span>(prev, [<span class="string">b'%'</span>, p1, p2, rem @ ..]) = val.split_at(i) {
<span class="kw">if let </span><span class="prelude-val">Some</span>(ch) = hex_pair_to_char(<span class="kw-2">*</span>p1, <span class="kw-2">*</span>p2)
<span class="comment">// ignore protected ascii bytes
</span>.filter(|<span class="kw-2">&amp;</span>ch| !(ch &lt; <span class="number">128 </span>&amp;&amp; <span class="self">self</span>.protected_table.bit_at(ch)))
{
<span class="kw-2">*</span>val = rem;
<span class="kw">return </span><span class="prelude-val">Some</span>((prev, ch));
}
}
}
<span class="prelude-val">None
</span>}
<span class="doccomment">/// Partially percent-decodes the given bytes.
///
/// Escape sequences of the protected set are *not* decoded.
///
/// Returns `None` when no modification to the original bytes was required.
///
/// Invalid/incomplete percent-encoding sequences are passed unmodified.
</span><span class="kw">pub fn </span>requote(<span class="kw-2">&amp;</span><span class="self">self</span>, val: <span class="kw-2">&amp;</span>[u8]) -&gt; <span class="prelude-ty">Option</span>&lt;Vec&lt;u8&gt;&gt; {
<span class="kw">let </span><span class="kw-2">mut </span>remaining = val;
<span class="comment">// early return indicates that no percent-encoded sequences exist and we can skip allocation
</span><span class="kw">let </span>(pre, decoded_char) = <span class="self">self</span>.decode_next(<span class="kw-2">&amp;mut </span>remaining)<span class="question-mark">?</span>;
<span class="comment">// decoded output will always be shorter than the input
</span><span class="kw">let </span><span class="kw-2">mut </span>decoded = Vec::&lt;u8&gt;::with_capacity(val.len());
<span class="comment">// push first segment and decoded char
</span>decoded.extend_from_slice(pre);
decoded.push(decoded_char);
<span class="comment">// decode and push rest of segments and decoded chars
</span><span class="kw">while let </span><span class="prelude-val">Some</span>((prev, ch)) = <span class="self">self</span>.decode_next(<span class="kw-2">&amp;mut </span>remaining) {
<span class="comment">// this ugly conditional achieves +50% perf in cases where this is a tight loop.
</span><span class="kw">if </span>!prev.is_empty() {
decoded.extend_from_slice(prev);
}
decoded.push(ch);
}
decoded.extend_from_slice(remaining);
<span class="prelude-val">Some</span>(decoded)
}
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>requote_str_lossy(<span class="kw-2">&amp;</span><span class="self">self</span>, val: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;String&gt; {
<span class="self">self</span>.requote(val.as_bytes())
.map(|data| String::from_utf8_lossy(<span class="kw-2">&amp;</span>data).into_owned())
}
}
<span class="doccomment">/// Decode a ASCII hex-encoded pair to an integer.
///
/// Returns `None` if either portion of the decoded pair does not evaluate to a valid hex value.
///
/// - `0x33 ('3'), 0x30 ('0') =&gt; 0x30 ('0')`
/// - `0x34 ('4'), 0x31 ('1') =&gt; 0x41 ('A')`
/// - `0x36 ('6'), 0x31 ('1') =&gt; 0x61 ('a')`
</span><span class="attr">#[inline(always)]
</span><span class="kw">fn </span>hex_pair_to_char(d1: u8, d2: u8) -&gt; <span class="prelude-ty">Option</span>&lt;u8&gt; {
<span class="kw">let </span>d_high = char::from(d1).to_digit(<span class="number">16</span>)<span class="question-mark">?</span>;
<span class="kw">let </span>d_low = char::from(d2).to_digit(<span class="number">16</span>)<span class="question-mark">?</span>;
<span class="comment">// left shift high nibble by 4 bits
</span><span class="prelude-val">Some</span>((d_high <span class="kw">as </span>u8) &lt;&lt; <span class="number">4 </span>| (d_low <span class="kw">as </span>u8))
}
<span class="attr">#[derive(Debug, Default, Clone)]
</span><span class="kw">struct </span>AsciiBitmap {
array: [u8; <span class="number">16</span>],
}
<span class="kw">impl </span>AsciiBitmap {
<span class="doccomment">/// Sets bit in given bit-map to 1=true.
///
/// # Panics
/// Panics if `ch` index is out of bounds.
</span><span class="kw">fn </span>set_bit(<span class="kw-2">&amp;mut </span><span class="self">self</span>, ch: u8) {
<span class="self">self</span>.array[(ch &gt;&gt; <span class="number">3</span>) <span class="kw">as </span>usize] |= <span class="number">0b1 </span>&lt;&lt; (ch &amp; <span class="number">0b111</span>)
}
<span class="doccomment">/// Returns true if bit to true in given bit-map.
///
/// # Panics
/// Panics if `ch` index is out of bounds.
</span><span class="kw">fn </span>bit_at(<span class="kw-2">&amp;</span><span class="self">self</span>, ch: u8) -&gt; bool {
<span class="self">self</span>.array[(ch &gt;&gt; <span class="number">3</span>) <span class="kw">as </span>usize] &amp; (<span class="number">0b1 </span>&lt;&lt; (ch &amp; <span class="number">0b111</span>)) != <span class="number">0
</span>}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="attr">#[test]
</span><span class="kw">fn </span>custom_quoter() {
<span class="kw">let </span>q = Quoter::new(<span class="string">b""</span>, <span class="string">b"+"</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/a%25c"</span>).unwrap(), <span class="string">b"/a%c"</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/a%2Bc"</span>), <span class="prelude-val">None</span>);
<span class="kw">let </span>q = Quoter::new(<span class="string">b"%+"</span>, <span class="string">b"/"</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/a%25b%2Bc"</span>).unwrap(), <span class="string">b"/a%b+c"</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/a%2fb"</span>), <span class="prelude-val">None</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/a%2Fb"</span>), <span class="prelude-val">None</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/a%0Ab"</span>).unwrap(), <span class="string">b"/a\nb"</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/a%FE\xffb"</span>).unwrap(), <span class="string">b"/a\xfe\xffb"</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/a\xfe\xffb"</span>), <span class="prelude-val">None</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>non_ascii() {
<span class="kw">let </span>q = Quoter::new(<span class="string">b"%+"</span>, <span class="string">b"/"</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/a%FE\xffb"</span>).unwrap(), <span class="string">b"/a\xfe\xffb"</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/a\xfe\xffb"</span>), <span class="prelude-val">None</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>invalid_sequences() {
<span class="kw">let </span>q = Quoter::new(<span class="string">b"%+"</span>, <span class="string">b"/"</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/a%2x%2X%%"</span>), <span class="prelude-val">None</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/a%20%2X%%"</span>).unwrap(), <span class="string">b"/a %2X%%"</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>quoter_no_modification() {
<span class="kw">let </span>q = Quoter::new(<span class="string">b""</span>, <span class="string">b""</span>);
<span class="macro">assert_eq!</span>(q.requote(<span class="string">b"/abc/../efg"</span>), <span class="prelude-val">None</span>);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,133 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-router/src/regex_set.rs`."><title>regex_set.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_router" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
</pre></div><pre class="rust"><code><span class="doccomment">//! Abstraction over `regex` and `regex-lite` depending on whether we have `unicode` crate feature
//! enabled.
</span><span class="kw">use </span>cfg_if::cfg_if;
<span class="attr">#[cfg(feature = <span class="string">"unicode"</span>)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">use </span>regex::{escape, Regex};
<span class="attr">#[cfg(not(feature = <span class="string">"unicode"</span>))]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">use </span>regex_lite::{escape, Regex};
<span class="attr">#[cfg(feature = <span class="string">"unicode"</span>)]
#[derive(Debug, Clone)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>RegexSet(regex::RegexSet);
<span class="attr">#[cfg(not(feature = <span class="string">"unicode"</span>))]
#[derive(Debug, Clone)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>RegexSet(Vec&lt;regex_lite::Regex&gt;);
<span class="kw">impl </span>RegexSet {
<span class="doccomment">/// Create a new regex set.
///
/// # Panics
///
/// Panics if any path patterns are malformed.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new(re_set: Vec&lt;String&gt;) -&gt; <span class="self">Self </span>{
<span class="macro">cfg_if!</span> {
<span class="kw">if </span><span class="attr">#[cfg(feature = <span class="string">"unicode"</span>)] </span>{
<span class="self">Self</span>(regex::RegexSet::new(re_set).unwrap())
} <span class="kw">else </span>{
<span class="self">Self</span>(re_set.iter().map(|re| Regex::new(re).unwrap()).collect())
}
}
}
<span class="doccomment">/// Create a new empty regex set.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>empty() -&gt; <span class="self">Self </span>{
<span class="macro">cfg_if!</span> {
<span class="kw">if </span><span class="attr">#[cfg(feature = <span class="string">"unicode"</span>)] </span>{
<span class="self">Self</span>(regex::RegexSet::empty())
} <span class="kw">else </span>{
<span class="self">Self</span>(Vec::new())
}
}
}
<span class="doccomment">/// Returns true if regex set matches `path`.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>is_match(<span class="kw-2">&amp;</span><span class="self">self</span>, path: <span class="kw-2">&amp;</span>str) -&gt; bool {
<span class="macro">cfg_if!</span> {
<span class="kw">if </span><span class="attr">#[cfg(feature = <span class="string">"unicode"</span>)] </span>{
<span class="self">self</span>.<span class="number">0</span>.is_match(path)
} <span class="kw">else </span>{
<span class="self">self</span>.<span class="number">0</span>.iter().any(|re| re.is_match(path))
}
}
}
<span class="doccomment">/// Returns index within `path` of first match.
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>first_match_idx(<span class="kw-2">&amp;</span><span class="self">self</span>, path: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;usize&gt; {
<span class="macro">cfg_if!</span> {
<span class="kw">if </span><span class="attr">#[cfg(feature = <span class="string">"unicode"</span>)] </span>{
<span class="self">self</span>.<span class="number">0</span>.matches(path).into_iter().next()
} <span class="kw">else </span>{
<span class="prelude-val">Some</span>(<span class="self">self</span>.<span class="number">0</span>.iter().enumerate().find(|(<span class="kw">_</span>, re)| re.is_match(path))<span class="question-mark">?</span>.<span class="number">0</span>)
}
}
}
}
</code></pre></div></section></main></body></html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-router/src/resource_path.rs`."><title>resource_path.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_router" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
</pre></div><pre class="rust"><code><span class="kw">use </span><span class="kw">crate</span>::Path;
<span class="comment">// TODO: this trait is necessary, document it
// see impl Resource for ServiceRequest
</span><span class="kw">pub trait </span>Resource {
<span class="doccomment">/// Type of resource's path returned in `resource_path`.
</span><span class="kw">type </span>Path: ResourcePath;
<span class="kw">fn </span>resource_path(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;mut </span>Path&lt;<span class="self">Self</span>::Path&gt;;
}
<span class="kw">pub trait </span>ResourcePath {
<span class="kw">fn </span>path(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str;
}
<span class="kw">impl </span>ResourcePath <span class="kw">for </span>String {
<span class="kw">fn </span>path(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="self">self</span>.as_str()
}
}
<span class="kw">impl</span>&lt;<span class="lifetime">'a</span>&gt; ResourcePath <span class="kw">for </span><span class="kw-2">&amp;</span><span class="lifetime">'a </span>str {
<span class="kw">fn </span>path(<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="kw">impl </span>ResourcePath <span class="kw">for </span>bytestring::ByteString {
<span class="kw">fn </span>path(<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="attr">#[cfg(feature = <span class="string">"http"</span>)]
</span><span class="kw">impl </span>ResourcePath <span class="kw">for </span>http::Uri {
<span class="kw">fn </span>path(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="self">self</span>.path()
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,565 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-router/src/router.rs`."><title>router.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_router" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
</pre></div><pre class="rust"><code><span class="kw">use crate</span>::{IntoPatterns, Resource, ResourceDef};
<span class="attr">#[derive(Debug, Copy, Clone, PartialEq, Eq)]
</span><span class="kw">pub struct </span>ResourceId(<span class="kw">pub </span>u16);
<span class="doccomment">/// Resource router.
///
/// It matches a [routing resource](Resource) to an ordered list of _routes_. Each is defined by a
/// single [`ResourceDef`] and contains two types of custom data:
/// 1. The route _value_, of the generic type `T`.
/// 1. Some _context_ data, of the generic type `U`, which is only provided to the check function in
/// [`recognize_fn`](Self::recognize_fn). This parameter defaults to `()` and can be omitted if
/// not required.
</span><span class="kw">pub struct </span>Router&lt;T, U = ()&gt; {
routes: Vec&lt;(ResourceDef, T, U)&gt;,
}
<span class="kw">impl</span>&lt;T, U&gt; Router&lt;T, U&gt; {
<span class="doccomment">/// Constructs new `RouterBuilder` with empty route list.
</span><span class="kw">pub fn </span>build() -&gt; RouterBuilder&lt;T, U&gt; {
RouterBuilder { routes: Vec::new() }
}
<span class="doccomment">/// Finds the value in the router that matches a given [routing resource](Resource).
///
/// The match result, including the captured dynamic segments, in the `resource`.
</span><span class="kw">pub fn </span>recognize&lt;R&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, resource: <span class="kw-2">&amp;mut </span>R) -&gt; <span class="prelude-ty">Option</span>&lt;(<span class="kw-2">&amp;</span>T, ResourceId)&gt;
<span class="kw">where
</span>R: Resource,
{
<span class="self">self</span>.recognize_fn(resource, |<span class="kw">_</span>, <span class="kw">_</span>| <span class="bool-val">true</span>)
}
<span class="doccomment">/// Same as [`recognize`](Self::recognize) but returns a mutable reference to the matched value.
</span><span class="kw">pub fn </span>recognize_mut&lt;R&gt;(<span class="kw-2">&amp;mut </span><span class="self">self</span>, resource: <span class="kw-2">&amp;mut </span>R) -&gt; <span class="prelude-ty">Option</span>&lt;(<span class="kw-2">&amp;mut </span>T, ResourceId)&gt;
<span class="kw">where
</span>R: Resource,
{
<span class="self">self</span>.recognize_mut_fn(resource, |<span class="kw">_</span>, <span class="kw">_</span>| <span class="bool-val">true</span>)
}
<span class="doccomment">/// Finds the value in the router that matches a given [routing resource](Resource) and passes
/// an additional predicate check using context data.
///
/// Similar to [`recognize`](Self::recognize). However, before accepting the route as matched,
/// the `check` closure is executed, passing the resource and each route's context data. If the
/// closure returns true then the match result is stored into `resource` and a reference to
/// the matched _value_ is returned.
</span><span class="kw">pub fn </span>recognize_fn&lt;R, F&gt;(<span class="kw-2">&amp;</span><span class="self">self</span>, resource: <span class="kw-2">&amp;mut </span>R, <span class="kw-2">mut </span>check: F) -&gt; <span class="prelude-ty">Option</span>&lt;(<span class="kw-2">&amp;</span>T, ResourceId)&gt;
<span class="kw">where
</span>R: Resource,
F: FnMut(<span class="kw-2">&amp;</span>R, <span class="kw-2">&amp;</span>U) -&gt; bool,
{
<span class="kw">for </span>(rdef, val, ctx) <span class="kw">in </span><span class="self">self</span>.routes.iter() {
<span class="kw">if </span>rdef.capture_match_info_fn(resource, |res| check(res, ctx)) {
<span class="kw">return </span><span class="prelude-val">Some</span>((val, ResourceId(rdef.id())));
}
}
<span class="prelude-val">None
</span>}
<span class="doccomment">/// Same as [`recognize_fn`](Self::recognize_fn) but returns a mutable reference to the matched
/// value.
</span><span class="kw">pub fn </span>recognize_mut_fn&lt;R, F&gt;(
<span class="kw-2">&amp;mut </span><span class="self">self</span>,
resource: <span class="kw-2">&amp;mut </span>R,
<span class="kw-2">mut </span>check: F,
) -&gt; <span class="prelude-ty">Option</span>&lt;(<span class="kw-2">&amp;mut </span>T, ResourceId)&gt;
<span class="kw">where
</span>R: Resource,
F: FnMut(<span class="kw-2">&amp;</span>R, <span class="kw-2">&amp;</span>U) -&gt; bool,
{
<span class="kw">for </span>(rdef, val, ctx) <span class="kw">in </span><span class="self">self</span>.routes.iter_mut() {
<span class="kw">if </span>rdef.capture_match_info_fn(resource, |res| check(res, ctx)) {
<span class="kw">return </span><span class="prelude-val">Some</span>((val, ResourceId(rdef.id())));
}
}
<span class="prelude-val">None
</span>}
}
<span class="doccomment">/// Builder for an ordered [routing](Router) list.
</span><span class="kw">pub struct </span>RouterBuilder&lt;T, U = ()&gt; {
routes: Vec&lt;(ResourceDef, T, U)&gt;,
}
<span class="kw">impl</span>&lt;T, U&gt; RouterBuilder&lt;T, U&gt; {
<span class="doccomment">/// Adds a new route to the end of the routing list.
///
/// Returns mutable references to elements of the new route.
</span><span class="kw">pub fn </span>push(
<span class="kw-2">&amp;mut </span><span class="self">self</span>,
rdef: ResourceDef,
val: T,
ctx: U,
) -&gt; (<span class="kw-2">&amp;mut </span>ResourceDef, <span class="kw-2">&amp;mut </span>T, <span class="kw-2">&amp;mut </span>U) {
<span class="self">self</span>.routes.push((rdef, val, ctx));
<span class="attr">#[allow(clippy::map_identity)] </span><span class="comment">// map is used to distribute &amp;mut-ness to tuple elements
</span><span class="self">self</span>.routes
.last_mut()
.map(|(rdef, val, ctx)| (rdef, val, ctx))
.unwrap()
}
<span class="doccomment">/// Finish configuration and create router instance.
</span><span class="kw">pub fn </span>finish(<span class="self">self</span>) -&gt; Router&lt;T, U&gt; {
Router {
routes: <span class="self">self</span>.routes,
}
}
}
<span class="doccomment">/// Convenience methods provided when context data impls [`Default`]
</span><span class="kw">impl</span>&lt;T, U&gt; RouterBuilder&lt;T, U&gt;
<span class="kw">where
</span>U: Default,
{
<span class="doccomment">/// Registers resource for specified path.
</span><span class="kw">pub fn </span>path(<span class="kw-2">&amp;mut </span><span class="self">self</span>, path: <span class="kw">impl </span>IntoPatterns, val: T) -&gt; (<span class="kw-2">&amp;mut </span>ResourceDef, <span class="kw-2">&amp;mut </span>T, <span class="kw-2">&amp;mut </span>U) {
<span class="self">self</span>.push(ResourceDef::new(path), val, U::default())
}
<span class="doccomment">/// Registers resource for specified path prefix.
</span><span class="kw">pub fn </span>prefix(
<span class="kw-2">&amp;mut </span><span class="self">self</span>,
prefix: <span class="kw">impl </span>IntoPatterns,
val: T,
) -&gt; (<span class="kw-2">&amp;mut </span>ResourceDef, <span class="kw-2">&amp;mut </span>T, <span class="kw-2">&amp;mut </span>U) {
<span class="self">self</span>.push(ResourceDef::prefix(prefix), val, U::default())
}
<span class="doccomment">/// Registers resource for [`ResourceDef`].
</span><span class="kw">pub fn </span>rdef(<span class="kw-2">&amp;mut </span><span class="self">self</span>, rdef: ResourceDef, val: T) -&gt; (<span class="kw-2">&amp;mut </span>ResourceDef, <span class="kw-2">&amp;mut </span>T, <span class="kw-2">&amp;mut </span>U) {
<span class="self">self</span>.push(rdef, val, U::default())
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use crate</span>::{
path::Path,
router::{ResourceId, Router},
};
<span class="attr">#[allow(clippy::cognitive_complexity)]
#[test]
</span><span class="kw">fn </span>test_recognizer_1() {
<span class="kw">let </span><span class="kw-2">mut </span>router = Router::&lt;usize&gt;::build();
router.path(<span class="string">"/name"</span>, <span class="number">10</span>).<span class="number">0</span>.set_id(<span class="number">0</span>);
router.path(<span class="string">"/name/{val}"</span>, <span class="number">11</span>).<span class="number">0</span>.set_id(<span class="number">1</span>);
router.path(<span class="string">"/name/{val}/index.html"</span>, <span class="number">12</span>).<span class="number">0</span>.set_id(<span class="number">2</span>);
router.path(<span class="string">"/file/{file}.{ext}"</span>, <span class="number">13</span>).<span class="number">0</span>.set_id(<span class="number">3</span>);
router.path(<span class="string">"/v{val}/{val2}/index.html"</span>, <span class="number">14</span>).<span class="number">0</span>.set_id(<span class="number">4</span>);
router.path(<span class="string">"/v/{tail:.*}"</span>, <span class="number">15</span>).<span class="number">0</span>.set_id(<span class="number">5</span>);
router.path(<span class="string">"/test2/{test}.html"</span>, <span class="number">16</span>).<span class="number">0</span>.set_id(<span class="number">6</span>);
router.path(<span class="string">"/{test}/index.html"</span>, <span class="number">17</span>).<span class="number">0</span>.set_id(<span class="number">7</span>);
<span class="kw">let </span><span class="kw-2">mut </span>router = router.finish();
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/unknown"</span>);
<span class="macro">assert!</span>(router.recognize_mut(<span class="kw-2">&amp;mut </span>path).is_none());
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/name"</span>);
<span class="kw">let </span>(h, info) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">10</span>);
<span class="macro">assert_eq!</span>(info, ResourceId(<span class="number">0</span>));
<span class="macro">assert!</span>(path.is_empty());
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/name/value"</span>);
<span class="kw">let </span>(h, info) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">11</span>);
<span class="macro">assert_eq!</span>(info, ResourceId(<span class="number">1</span>));
<span class="macro">assert_eq!</span>(path.get(<span class="string">"val"</span>).unwrap(), <span class="string">"value"</span>);
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>path[<span class="string">"val"</span>], <span class="string">"value"</span>);
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/name/value2/index.html"</span>);
<span class="kw">let </span>(h, info) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">12</span>);
<span class="macro">assert_eq!</span>(info, ResourceId(<span class="number">2</span>));
<span class="macro">assert_eq!</span>(path.get(<span class="string">"val"</span>).unwrap(), <span class="string">"value2"</span>);
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/file/file.gz"</span>);
<span class="kw">let </span>(h, info) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">13</span>);
<span class="macro">assert_eq!</span>(info, ResourceId(<span class="number">3</span>));
<span class="macro">assert_eq!</span>(path.get(<span class="string">"file"</span>).unwrap(), <span class="string">"file"</span>);
<span class="macro">assert_eq!</span>(path.get(<span class="string">"ext"</span>).unwrap(), <span class="string">"gz"</span>);
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/v2/ttt/index.html"</span>);
<span class="kw">let </span>(h, info) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">14</span>);
<span class="macro">assert_eq!</span>(info, ResourceId(<span class="number">4</span>));
<span class="macro">assert_eq!</span>(path.get(<span class="string">"val"</span>).unwrap(), <span class="string">"2"</span>);
<span class="macro">assert_eq!</span>(path.get(<span class="string">"val2"</span>).unwrap(), <span class="string">"ttt"</span>);
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/v/blah-blah/index.html"</span>);
<span class="kw">let </span>(h, info) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">15</span>);
<span class="macro">assert_eq!</span>(info, ResourceId(<span class="number">5</span>));
<span class="macro">assert_eq!</span>(path.get(<span class="string">"tail"</span>).unwrap(), <span class="string">"blah-blah/index.html"</span>);
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/test2/index.html"</span>);
<span class="kw">let </span>(h, info) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">16</span>);
<span class="macro">assert_eq!</span>(info, ResourceId(<span class="number">6</span>));
<span class="macro">assert_eq!</span>(path.get(<span class="string">"test"</span>).unwrap(), <span class="string">"index"</span>);
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/bbb/index.html"</span>);
<span class="kw">let </span>(h, info) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">17</span>);
<span class="macro">assert_eq!</span>(info, ResourceId(<span class="number">7</span>));
<span class="macro">assert_eq!</span>(path.get(<span class="string">"test"</span>).unwrap(), <span class="string">"bbb"</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_recognizer_2() {
<span class="kw">let </span><span class="kw-2">mut </span>router = Router::&lt;usize&gt;::build();
router.path(<span class="string">"/index.json"</span>, <span class="number">10</span>);
router.path(<span class="string">"/{source}.json"</span>, <span class="number">11</span>);
<span class="kw">let </span><span class="kw-2">mut </span>router = router.finish();
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/index.json"</span>);
<span class="kw">let </span>(h, <span class="kw">_</span>) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">10</span>);
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/test.json"</span>);
<span class="kw">let </span>(h, <span class="kw">_</span>) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">11</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>test_recognizer_with_prefix() {
<span class="kw">let </span><span class="kw-2">mut </span>router = Router::&lt;usize&gt;::build();
router.path(<span class="string">"/name"</span>, <span class="number">10</span>).<span class="number">0</span>.set_id(<span class="number">0</span>);
router.path(<span class="string">"/name/{val}"</span>, <span class="number">11</span>).<span class="number">0</span>.set_id(<span class="number">1</span>);
<span class="kw">let </span><span class="kw-2">mut </span>router = router.finish();
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/name"</span>);
path.skip(<span class="number">5</span>);
<span class="macro">assert!</span>(router.recognize_mut(<span class="kw-2">&amp;mut </span>path).is_none());
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/test/name"</span>);
path.skip(<span class="number">5</span>);
<span class="kw">let </span>(h, <span class="kw">_</span>) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">10</span>);
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/test/name/value"</span>);
path.skip(<span class="number">5</span>);
<span class="kw">let </span>(h, id) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">11</span>);
<span class="macro">assert_eq!</span>(id, ResourceId(<span class="number">1</span>));
<span class="macro">assert_eq!</span>(path.get(<span class="string">"val"</span>).unwrap(), <span class="string">"value"</span>);
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>path[<span class="string">"val"</span>], <span class="string">"value"</span>);
<span class="comment">// same patterns
</span><span class="kw">let </span><span class="kw-2">mut </span>router = Router::&lt;usize&gt;::build();
router.path(<span class="string">"/name"</span>, <span class="number">10</span>);
router.path(<span class="string">"/name/{val}"</span>, <span class="number">11</span>);
<span class="kw">let </span><span class="kw-2">mut </span>router = router.finish();
<span class="comment">// test skip beyond path length
</span><span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/name"</span>);
path.skip(<span class="number">6</span>);
<span class="macro">assert!</span>(router.recognize_mut(<span class="kw-2">&amp;mut </span>path).is_none());
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/test2/name"</span>);
path.skip(<span class="number">6</span>);
<span class="kw">let </span>(h, <span class="kw">_</span>) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">10</span>);
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/test2/name-test"</span>);
path.skip(<span class="number">6</span>);
<span class="macro">assert!</span>(router.recognize_mut(<span class="kw-2">&amp;mut </span>path).is_none());
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(<span class="string">"/test2/name/ttt"</span>);
path.skip(<span class="number">6</span>);
<span class="kw">let </span>(h, <span class="kw">_</span>) = router.recognize_mut(<span class="kw-2">&amp;mut </span>path).unwrap();
<span class="macro">assert_eq!</span>(<span class="kw-2">*</span>h, <span class="number">11</span>);
<span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>path[<span class="string">"val"</span>], <span class="string">"ttt"</span>);
}
}
</code></pre></div></section></main></body></html>

View File

@ -0,0 +1,287 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-router/src/url.rs`."><title>url.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../static.files/rustdoc-dd39b87e5fcfba68.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="actix_router" data-themes="" data-resource-suffix="" data-rustdoc-version="1.80.0-nightly (bdbbb6c6a 2024-05-26)" data-channel="nightly" data-search-js="search-d52510db62a78183.js" data-settings-js="settings-4313503d2e1961c2.js" ><script src="../../static.files/storage-118b08c4c78b968e.js"></script><script defer src="../../static.files/src-script-e66d777a5a92e9b2.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-20a3ad099b048cf2.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-df360f571f6edeae.css"></noscript><link rel="icon" href="https://actix.rs/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="example-wrap"><div data-nosnippet><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
</pre></div><pre class="rust"><code><span class="kw">use crate</span>::{Quoter, ResourcePath};
<span class="macro">thread_local!</span> {
<span class="kw">static </span>DEFAULT_QUOTER: Quoter = Quoter::new(<span class="string">b""</span>, <span class="string">b"%/+"</span>);
}
<span class="attr">#[derive(Debug, Clone, Default)]
</span><span class="kw">pub struct </span>Url {
uri: http::Uri,
path: <span class="prelude-ty">Option</span>&lt;String&gt;,
}
<span class="kw">impl </span>Url {
<span class="attr">#[inline]
</span><span class="kw">pub fn </span>new(uri: http::Uri) -&gt; Url {
<span class="kw">let </span>path = DEFAULT_QUOTER.with(|q| q.requote_str_lossy(uri.path()));
Url { uri, path }
}
<span class="attr">#[inline]
</span><span class="kw">pub fn </span>new_with_quoter(uri: http::Uri, quoter: <span class="kw-2">&amp;</span>Quoter) -&gt; Url {
Url {
path: quoter.requote_str_lossy(uri.path()),
uri,
}
}
<span class="doccomment">/// Returns URI.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>uri(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>http::Uri {
<span class="kw-2">&amp;</span><span class="self">self</span>.uri
}
<span class="doccomment">/// Returns path.
</span><span class="attr">#[inline]
</span><span class="kw">pub fn </span>path(<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>.path {
<span class="prelude-val">Some</span>(<span class="kw-2">ref </span>path) =&gt; path,
<span class="kw">_ </span>=&gt; <span class="self">self</span>.uri.path(),
}
}
<span class="attr">#[inline]
</span><span class="kw">pub fn </span>update(<span class="kw-2">&amp;mut </span><span class="self">self</span>, uri: <span class="kw-2">&amp;</span>http::Uri) {
<span class="self">self</span>.uri = uri.clone();
<span class="self">self</span>.path = DEFAULT_QUOTER.with(|q| q.requote_str_lossy(uri.path()));
}
<span class="attr">#[inline]
</span><span class="kw">pub fn </span>update_with_quoter(<span class="kw-2">&amp;mut </span><span class="self">self</span>, uri: <span class="kw-2">&amp;</span>http::Uri, quoter: <span class="kw-2">&amp;</span>Quoter) {
<span class="self">self</span>.uri = uri.clone();
<span class="self">self</span>.path = quoter.requote_str_lossy(uri.path());
}
}
<span class="kw">impl </span>ResourcePath <span class="kw">for </span>Url {
<span class="attr">#[inline]
</span><span class="kw">fn </span>path(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<span class="self">self</span>.path()
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use </span>std::fmt::Write <span class="kw">as _</span>;
<span class="kw">use </span>http::Uri;
<span class="kw">use super</span>::<span class="kw-2">*</span>;
<span class="kw">use crate</span>::{Path, ResourceDef};
<span class="kw">const </span>PROTECTED: <span class="kw-2">&amp;</span>[u8] = <span class="string">b"%/+"</span>;
<span class="kw">fn </span>match_url(pattern: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str, url: <span class="kw">impl </span>AsRef&lt;str&gt;) -&gt; Path&lt;Url&gt; {
<span class="kw">let </span>re = ResourceDef::new(pattern);
<span class="kw">let </span>uri = Uri::try_from(url.as_ref()).unwrap();
<span class="kw">let </span><span class="kw-2">mut </span>path = Path::new(Url::new(uri));
<span class="macro">assert!</span>(re.capture_match_info(<span class="kw-2">&amp;mut </span>path));
path
}
<span class="kw">fn </span>percent_encode(data: <span class="kw-2">&amp;</span>[u8]) -&gt; String {
data.iter()
.fold(String::with_capacity(data.len() * <span class="number">3</span>), |<span class="kw-2">mut </span>buf, c| {
<span class="macro">write!</span>(<span class="kw-2">&amp;mut </span>buf, <span class="string">"%{:02X}"</span>, c).unwrap();
buf
})
}
<span class="attr">#[test]
</span><span class="kw">fn </span>parse_url() {
<span class="kw">let </span>re = <span class="string">"/user/{id}/test"</span>;
<span class="kw">let </span>path = match_url(re, <span class="string">"/user/2345/test"</span>);
<span class="macro">assert_eq!</span>(path.get(<span class="string">"id"</span>).unwrap(), <span class="string">"2345"</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>protected_chars() {
<span class="kw">let </span>re = <span class="string">"/user/{id}/test"</span>;
<span class="kw">let </span>encoded = percent_encode(PROTECTED);
<span class="kw">let </span>path = match_url(re, <span class="macro">format!</span>(<span class="string">"/user/{}/test"</span>, encoded));
<span class="comment">// characters in captured segment remain unencoded
</span><span class="macro">assert_eq!</span>(path.get(<span class="string">"id"</span>).unwrap(), <span class="kw-2">&amp;</span>encoded);
<span class="comment">// "%25" should never be decoded into '%' to guarantee the output is a valid
// percent-encoded format
</span><span class="kw">let </span>path = match_url(re, <span class="string">"/user/qwe%25/test"</span>);
<span class="macro">assert_eq!</span>(path.get(<span class="string">"id"</span>).unwrap(), <span class="string">"qwe%25"</span>);
<span class="kw">let </span>path = match_url(re, <span class="string">"/user/qwe%25rty/test"</span>);
<span class="macro">assert_eq!</span>(path.get(<span class="string">"id"</span>).unwrap(), <span class="string">"qwe%25rty"</span>);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>non_protected_ascii() {
<span class="kw">let </span>non_protected_ascii = (<span class="string">'\u{0}'</span>..=<span class="string">'\u{7F}'</span>)
.filter(|<span class="kw-2">&amp;</span>c| c.is_ascii() &amp;&amp; !PROTECTED.contains(<span class="kw-2">&amp;</span>(c <span class="kw">as </span>u8)))
.collect::&lt;String&gt;();
<span class="kw">let </span>encoded = percent_encode(non_protected_ascii.as_bytes());
<span class="kw">let </span>path = match_url(<span class="string">"/user/{id}/test"</span>, <span class="macro">format!</span>(<span class="string">"/user/{}/test"</span>, encoded));
<span class="macro">assert_eq!</span>(path.get(<span class="string">"id"</span>).unwrap(), <span class="kw-2">&amp;</span>non_protected_ascii);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>valid_utf8_multi_byte() {
<span class="kw">let </span>test = (<span class="string">'\u{FF00}'</span>..=<span class="string">'\u{FFFF}'</span>).collect::&lt;String&gt;();
<span class="kw">let </span>encoded = percent_encode(test.as_bytes());
<span class="kw">let </span>path = match_url(<span class="string">"/a/{id}/b"</span>, <span class="macro">format!</span>(<span class="string">"/a/{}/b"</span>, <span class="kw-2">&amp;</span>encoded));
<span class="macro">assert_eq!</span>(path.get(<span class="string">"id"</span>).unwrap(), <span class="kw-2">&amp;</span>test);
}
<span class="attr">#[test]
</span><span class="kw">fn </span>invalid_utf8() {
<span class="kw">let </span>invalid_utf8 = percent_encode((<span class="number">0x80</span>..=<span class="number">0xff</span>).collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;().as_slice());
<span class="kw">let </span>uri = Uri::try_from(<span class="macro">format!</span>(<span class="string">"/{}"</span>, invalid_utf8)).unwrap();
<span class="kw">let </span>path = Path::new(Url::new(uri));
<span class="comment">// We should always get a valid utf8 string
</span><span class="macro">assert!</span>(String::from_utf8(path.as_str().as_bytes().to_owned()).is_ok());
}
}
</code></pre></div></section></main></body></html>

Some files were not shown because too many files have changed in this diff Show More