fastly_shared/lib.rs
1// Warnings (other than unused variables) in doctests are promoted to errors.
2#![doc(test(attr(deny(warnings))))]
3#![doc(test(attr(allow(dead_code))))]
4#![doc(test(attr(allow(unused_variables))))]
5#![deny(rustdoc::broken_intra_doc_links)]
6#![deny(rustdoc::invalid_codeblock_attributes)]
7
8use std::fmt;
9
10/// The maximum number of pending requests that can be passed to `select`.
11///
12/// In practice, a program will be limited first by the number of requests it can create.
13pub const MAX_PENDING_REQS: u32 = 16 * 1024;
14
15// These should always be a very high number that is not `MAX`, to avoid clashing with both
16// legitimate handles, as well as other sentinel values defined by cranelift_entity.
17pub const INVALID_ACL_HANDLE: u32 = u32::MAX - 1;
18pub const INVALID_BODY_HANDLE: u32 = u32::MAX - 1;
19pub const INVALID_CACHE_BUSY_HANDLE: u32 = u32::MAX - 1;
20pub const INVALID_CACHE_HANDLE: u32 = u32::MAX - 1;
21pub const INVALID_CACHE_REPLACE_HANDLE: u32 = u32::MAX - 1;
22pub const INVALID_CONFIG_STORE_HANDLE: u32 = u32::MAX - 1;
23pub const INVALID_DICTIONARY_HANDLE: u32 = u32::MAX - 1;
24pub const INVALID_KV_PENDING_DELETE_HANDLE: u32 = u32::MAX - 1;
25pub const INVALID_KV_PENDING_INSERT_HANDLE: u32 = u32::MAX - 1;
26pub const INVALID_KV_PENDING_LIST_HANDLE: u32 = u32::MAX - 1;
27pub const INVALID_KV_PENDING_LOOKUP_HANDLE: u32 = u32::MAX - 1;
28pub const INVALID_KV_STORE_HANDLE: u32 = u32::MAX - 1;
29pub const INVALID_PENDING_REQUEST_HANDLE: u32 = u32::MAX - 1;
30pub const INVALID_REQUEST_HANDLE: u32 = u32::MAX - 1;
31pub const INVALID_REQUEST_PROMISE_HANDLE: u32 = u32::MAX - 1;
32pub const INVALID_RESPONSE_HANDLE: u32 = u32::MAX - 1;
33pub const INVALID_SECRET_HANDLE: u32 = u32::MAX - 1;
34pub const INVALID_SECRET_STORE_HANDLE: u32 = u32::MAX - 1;
35
36/// Constants for defining minimum/maximum TLS versions for connecting to backends.
37#[allow(non_snake_case)]
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39#[repr(u32)]
40pub enum SslVersion {
41 TLS1 = 0,
42 TLS1_1 = 1,
43 TLS1_2 = 2,
44 TLS1_3 = 3,
45}
46
47impl SslVersion {
48 pub fn as_u32(&self) -> u32 {
49 *self as u32
50 }
51}
52
53// TODO KTM 2023-02-08: could use num-derive for this, but I don't think it's worth pulling in a
54// whole new set of dependencies when this will likely be encoded by witx shortly (see HttpVersion)
55impl TryFrom<u32> for SslVersion {
56 type Error = String;
57 fn try_from(x: u32) -> Result<Self, Self::Error> {
58 if x == Self::TLS1 as u32 {
59 Ok(Self::TLS1)
60 } else if x == Self::TLS1_1 as u32 {
61 Ok(Self::TLS1_1)
62 } else if x == Self::TLS1_2 as u32 {
63 Ok(Self::TLS1_2)
64 } else if x == Self::TLS1_3 as u32 {
65 Ok(Self::TLS1_3)
66 } else {
67 Err(format!("unknown ssl version enum value: {x}"))
68 }
69 }
70}
71
72#[derive(Clone, Copy, Eq, PartialEq)]
73#[repr(transparent)]
74#[must_use = "Errors should never pass silently."]
75pub struct FastlyStatus {
76 pub code: i32,
77}
78
79impl FastlyStatus {
80 /// Success value.
81 ///
82 /// This indicates that a hostcall finished successfully.
83 pub const OK: Self = Self { code: 0 };
84 /// Generic error value.
85 ///
86 /// This means that some unexpected error occurred during a hostcall.
87 pub const ERROR: Self = Self { code: 1 };
88 /// Invalid argument.
89 pub const INVAL: Self = Self { code: 2 };
90 /// Invalid handle.
91 ///
92 /// Returned when a request, response, or body handle is not valid.
93 pub const BADF: Self = Self { code: 3 };
94 /// Buffer length error.
95 ///
96 /// Returned when a buffer is too long.
97 pub const BUFLEN: Self = Self { code: 4 };
98 /// Unsupported operation error.
99 ///
100 /// This error is returned when some operation cannot be performed, because it is not supported.
101 pub const UNSUPPORTED: Self = Self { code: 5 };
102 /// Alignment error.
103 ///
104 /// This is returned when a pointer does not point to a properly aligned slice of memory.
105 pub const BADALIGN: Self = Self { code: 6 };
106 /// Invalid HTTP error.
107 ///
108 /// This can be returned when a method, URI, or header is not valid.
109 pub const HTTPINVALID: Self = Self { code: 7 };
110 /// HTTP user error.
111 ///
112 /// This is returned in cases where user code caused an HTTP error. For example, attempt to send
113 /// a 1xx response code, or a request with a non-absolute URI. This can also be caused by
114 /// an unexpected header: both `content-length` and `transfer-encoding`, for example.
115 pub const HTTPUSER: Self = Self { code: 8 };
116 /// HTTP incomplete message error.
117 ///
118 /// This can be returned when a stream ended unexpectedly.
119 pub const HTTPINCOMPLETE: Self = Self { code: 9 };
120 /// A `None` error.
121 ///
122 /// This status code is used to indicate when an optional value did not exist, as opposed to
123 /// an empty value.
124 pub const NONE: Self = Self { code: 10 };
125 /// HTTP head too large error.
126 ///
127 /// This error will be returned when the message head is too large.
128 pub const HTTPHEADTOOLARGE: Self = Self { code: 11 };
129 /// HTTP invalid status error.
130 ///
131 /// This error will be returned when the HTTP message contains an invalid status code.
132 pub const HTTPINVALIDSTATUS: Self = Self { code: 12 };
133 /// Limit exceeded
134 ///
135 /// This is returned when an attempt to allocate a resource has exceeded the maximum number of
136 /// resources permitted. For example, creating too many response handles.
137 pub const LIMITEXCEEDED: Self = Self { code: 13 };
138 /// Resource temporarily unavailable
139 ///
140 /// This is returned when an attempting to retrieve a resource that is not yet available.
141 /// For example when attempting to read trailers from a Body that has not yet been consumed.
142 pub const AGAIN: Self = Self { code: 14 };
143
144 pub fn is_ok(&self) -> bool {
145 self == &Self::OK
146 }
147
148 pub fn is_err(&self) -> bool {
149 !self.is_ok()
150 }
151
152 /// Convert a `FastlyStatus` value to a `Result<(), FastlyStatus>`.
153 ///
154 /// This will consume a status code, and return `Ok(())` if and only if the value was
155 /// `FastlyStatus::OK`. If the status code was some error, then it will be returned in the
156 /// result's `Err` variant.
157 pub fn result(self) -> Result<(), Self> {
158 if let Self::OK = self {
159 Ok(())
160 } else {
161 Err(self)
162 }
163 }
164}
165
166impl fmt::Debug for FastlyStatus {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 write!(f, "FastlyStatus::")?;
169 match *self {
170 Self::OK => write!(f, "OK"),
171 Self::ERROR => write!(f, "ERROR"),
172 Self::INVAL => write!(f, "INVAL"),
173 Self::BADF => write!(f, "BADF"),
174 Self::BUFLEN => write!(f, "BUFLEN"),
175 Self::UNSUPPORTED => write!(f, "UNSUPPORTED"),
176 Self::BADALIGN => write!(f, "BADALIGN"),
177 Self::HTTPINVALID => write!(f, "HTTP_INVALID_ERROR"),
178 Self::HTTPUSER => write!(f, "HTTP_USER_ERROR"),
179 Self::HTTPINCOMPLETE => write!(f, "HTTP_INCOMPLETE_MESSAGE"),
180 Self::NONE => write!(f, "NONE"),
181 Self::HTTPHEADTOOLARGE => write!(f, "HTTP_HEAD_TOO_LARGE"),
182 Self::HTTPINVALIDSTATUS => write!(f, "HTTP_INVALID_STATUS"),
183 Self::LIMITEXCEEDED => write!(f, "LIMIT_EXCEEDED"),
184 Self::AGAIN => write!(f, "AGAIN"),
185 _ => write!(f, "UNKNOWN ({})", self.code),
186 }
187 }
188}
189
190pub const FASTLY_ABI_VERSION: u64 = 1;
191
192// define our own enum rather than using `http`'s, so that we can easily convert it to a scalar
193#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
194#[repr(u32)]
195pub enum HttpVersion {
196 Http09 = 0,
197 Http10 = 1,
198 Http11 = 2,
199 H2 = 3,
200 H3 = 4,
201}
202
203impl HttpVersion {
204 pub fn as_u32(&self) -> u32 {
205 *self as u32
206 }
207}
208
209// TODO ACF 2019-12-04: could use num-derive for this, but I don't think it's worth pulling in a
210// whole new set of dependencies when this will likely be encoded by witx shortly
211impl TryFrom<u32> for HttpVersion {
212 type Error = String;
213
214 fn try_from(x: u32) -> Result<Self, Self::Error> {
215 if x == Self::Http09 as u32 {
216 Ok(Self::Http09)
217 } else if x == Self::Http10 as u32 {
218 Ok(Self::Http10)
219 } else if x == Self::Http11 as u32 {
220 Ok(Self::Http11)
221 } else if x == Self::H2 as u32 {
222 Ok(Self::H2)
223 } else if x == Self::H3 as u32 {
224 Ok(Self::H3)
225 } else {
226 Err(format!("unknown http version enum value: {x}"))
227 }
228 }
229}
230
231impl From<http::Version> for HttpVersion {
232 fn from(v: http::Version) -> Self {
233 match v {
234 http::Version::HTTP_09 => Self::Http09,
235 http::Version::HTTP_10 => Self::Http10,
236 http::Version::HTTP_11 => Self::Http11,
237 http::Version::HTTP_2 => Self::H2,
238 http::Version::HTTP_3 => Self::H3,
239 _ => unreachable!(),
240 }
241 }
242}
243
244impl From<HttpVersion> for http::Version {
245 fn from(v: HttpVersion) -> Self {
246 match v {
247 HttpVersion::Http09 => Self::HTTP_09,
248 HttpVersion::Http10 => Self::HTTP_10,
249 HttpVersion::Http11 => Self::HTTP_11,
250 HttpVersion::H2 => Self::HTTP_2,
251 HttpVersion::H3 => Self::HTTP_3,
252 }
253 }
254}
255
256#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
257#[repr(u32)]
258pub enum BodyWriteEnd {
259 Back = 0,
260 Front = 1,
261}
262
263/// Determines how the framing headers (`Content-Length`/`Transfer-Encoding`) are set for a
264/// request or response.
265#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
266#[repr(u32)]
267pub enum FramingHeadersMode {
268 /// Determine the framing headers automatically based on the message body, and discard any framing
269 /// headers already set in the message. This is the default behavior.
270 ///
271 /// In automatic mode, a `Content-Length` is used when the size of the body can be determined
272 /// before it is sent. Requests/responses sent in streaming mode, where headers are sent immediately
273 /// but the content of the body is streamed later, will receive a `Transfer-Encoding: chunked`
274 /// to accommodate the dynamic generation of the body.
275 #[default]
276 Automatic = 0,
277
278 /// Use the exact framing headers set in the message, falling back to [`Automatic`][`Self::Automatic`]
279 /// if invalid.
280 ///
281 /// In "from headers" mode, any `Content-Length` or `Transfer-Encoding` headers will be honored.
282 /// You must ensure that those headers have correct values permitted by the
283 /// [HTTP/1.1 specification][spec]. If the provided headers are not permitted by the spec,
284 /// the headers will revert to automatic mode and a log diagnostic will be issued about what was
285 /// wrong. If a `Content-Length` is permitted by the spec, but the value doesn't match the size of
286 /// the actual body, the body will either be truncated (if it is too long), or the connection will
287 /// be hung up early (if it is too short).
288 ///
289 /// [spec]: https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1
290 ManuallyFromHeaders = 1,
291}
292
293/// Determines whether the client is encouraged to stop using the current connection and to open a
294/// new one for the next request.
295///
296/// Most applications do not need to change this setting.
297#[doc(hidden)]
298#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
299#[repr(u32)]
300pub enum HttpKeepaliveMode {
301 /// This is the default behavior.
302 #[default]
303 Automatic = 0,
304
305 /// Send `Connection: close` in HTTP/1 and a GOAWAY frame in HTTP/2 and HTTP/3. This prompts
306 /// the client to close the current connection and to open a new one for the next request.
307 NoKeepalive = 1,
308}
309
310#[derive(Debug, Clone, Copy, Eq, PartialEq)]
311pub enum ClientCertVerifyResult {
312 /// Success value.
313 ///
314 /// This indicates that client certificate verified successfully.
315 Ok,
316 /// Bad certificate error.
317 ///
318 /// This error means the certificate is corrupt
319 /// (e.g., the certificate signatures do not verify correctly).
320 BadCertificate,
321 /// Certificate revoked error.
322 ///
323 /// This error means the client certificate is revoked by its signer.
324 CertificateRevoked,
325 /// Certificate expired error.
326 ///
327 /// This error means the client certificate has expired or is not currently valid.
328 CertificateExpired,
329 /// Unknown CA error.
330 ///
331 /// This error means the valid certificate chain or partial chain was received, but the
332 /// certificate was not accepted because the CA certificate could not be located or could not
333 /// be matched with a known trust anchor.
334 UnknownCa,
335 /// Certificate missing error.
336 ///
337 /// This error means the client did not provide a certificate during the handshake.
338 CertificateMissing,
339 /// Certificate unknown error.
340 ///
341 /// This error means the client certificate was received, but some other (unspecified) issue
342 /// arose in processing the certificate, rendering it unacceptable.
343 CertificateUnknown,
344}
345
346impl ClientCertVerifyResult {
347 pub fn from_u32(value: u32) -> ClientCertVerifyResult {
348 match value {
349 0 => ClientCertVerifyResult::Ok,
350 1 => ClientCertVerifyResult::BadCertificate,
351 2 => ClientCertVerifyResult::CertificateRevoked,
352 3 => ClientCertVerifyResult::CertificateExpired,
353 4 => ClientCertVerifyResult::UnknownCa,
354 5 => ClientCertVerifyResult::CertificateMissing,
355 _ => ClientCertVerifyResult::CertificateUnknown,
356 }
357 }
358}