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
10use http::HeaderValue;
11
12/// The maximum number of pending requests that can be passed to `select`.
13///
14/// In practice, a program will be limited first by the number of requests it can create.
15pub const MAX_PENDING_REQS: u32 = 16 * 1024;
16
17// These should always be a very high number that is not `MAX`, to avoid clashing with both
18// legitimate handles, as well as other sentinel values defined by cranelift_entity.
19pub const INVALID_ACL_HANDLE: u32 = std::u32::MAX - 1;
20pub const INVALID_BODY_HANDLE: u32 = std::u32::MAX - 1;
21pub const INVALID_CACHE_BUSY_HANDLE: u32 = std::u32::MAX - 1;
22pub const INVALID_CACHE_HANDLE: u32 = std::u32::MAX - 1;
23pub const INVALID_CACHE_REPLACE_HANDLE: u32 = std::u32::MAX - 1;
24pub const INVALID_CONFIG_STORE_HANDLE: u32 = std::u32::MAX - 1;
25pub const INVALID_DICTIONARY_HANDLE: u32 = std::u32::MAX - 1;
26pub const INVALID_KV_PENDING_DELETE_HANDLE: u32 = std::u32::MAX - 1;
27pub const INVALID_KV_PENDING_INSERT_HANDLE: u32 = std::u32::MAX - 1;
28pub const INVALID_KV_PENDING_LIST_HANDLE: u32 = std::u32::MAX - 1;
29pub const INVALID_KV_PENDING_LOOKUP_HANDLE: u32 = std::u32::MAX - 1;
30pub const INVALID_KV_STORE_HANDLE: u32 = std::u32::MAX - 1;
31pub const INVALID_PENDING_REQUEST_HANDLE: u32 = std::u32::MAX - 1;
32pub const INVALID_REQUEST_HANDLE: u32 = std::u32::MAX - 1;
33pub const INVALID_RESPONSE_HANDLE: u32 = std::u32::MAX - 1;
34pub const INVALID_SECRET_HANDLE: u32 = std::u32::MAX - 1;
35pub const INVALID_SECRET_STORE_HANDLE: u32 = std::u32::MAX - 1;
36
37/// Constants for defining minimum/maximum TLS versions for connecting to backends.
38#[allow(non_snake_case)]
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
40#[repr(u32)]
41pub enum SslVersion {
42    TLS1 = 0,
43    TLS1_1 = 1,
44    TLS1_2 = 2,
45    TLS1_3 = 3,
46}
47
48impl SslVersion {
49    pub fn as_u32(&self) -> u32 {
50        *self as u32
51    }
52}
53
54// TODO KTM 2023-02-08: could use num-derive for this, but I don't think it's worth pulling in a
55// whole new set of dependencies when this will likely be encoded by witx shortly (see HttpVersion)
56impl TryFrom<u32> for SslVersion {
57    type Error = String;
58    fn try_from(x: u32) -> Result<Self, Self::Error> {
59        if x == Self::TLS1 as u32 {
60            Ok(Self::TLS1)
61        } else if x == Self::TLS1_1 as u32 {
62            Ok(Self::TLS1_1)
63        } else if x == Self::TLS1_2 as u32 {
64            Ok(Self::TLS1_2)
65        } else if x == Self::TLS1_3 as u32 {
66            Ok(Self::TLS1_3)
67        } else {
68            Err(format!("unknown ssl version enum value: {}", x))
69        }
70    }
71}
72
73#[derive(Clone, Copy, Eq, PartialEq)]
74#[repr(transparent)]
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, 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    Automatic = 0,
276
277    /// Use the exact framing headers set in the message, falling back to [`Automatic`][`Self::Automatic`]
278    /// if invalid.
279    ///
280    /// In "from headers" mode, any `Content-Length` or `Transfer-Encoding` headers will be honored.
281    /// You must ensure that those headers have correct values permitted by the
282    /// [HTTP/1.1 specification][spec]. If the provided headers are not permitted by the spec,
283    /// the headers will revert to automatic mode and a log diagnostic will be issued about what was
284    /// wrong. If a `Content-Length` is permitted by the spec, but the value doesn't match the size of
285    /// the actual body, the body will either be truncated (if it is too long), or the connection will
286    /// be hung up early (if it is too short).
287    ///
288    /// [spec]: https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1
289    ManuallyFromHeaders = 1,
290}
291
292impl Default for FramingHeadersMode {
293    fn default() -> Self {
294        Self::Automatic
295    }
296}
297
298/// Determines whether the client is encouraged to stop using the current connection and to open a
299/// new one for the next request.
300///
301/// Most applications do not need to change this setting.
302#[doc(hidden)]
303#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
304#[repr(u32)]
305pub enum HttpKeepaliveMode {
306    /// This is the default behavor.
307    Automatic = 0,
308
309    /// Send `Connection: close` in HTTP/1 and a GOAWAY frame in HTTP/2 and HTTP/3.  This prompts
310    /// the client to close the current connection and to open a new one for the next request.
311    NoKeepalive = 1,
312}
313
314impl Default for HttpKeepaliveMode {
315    fn default() -> Self {
316        Self::Automatic
317    }
318}
319
320/// Optional override for response caching behavior.
321#[derive(Clone, Debug)]
322pub enum CacheOverride {
323    /// Do not override the behavior specified in the origin response's cache control headers.
324    None,
325    /// Do not cache the response to this request, regardless of the origin response's headers.
326    Pass,
327    /// Override particular cache control settings.
328    ///
329    /// The origin response's cache control headers will be used for ttl and stale_while_revalidate if `None`.
330    Override {
331        ttl: Option<u32>,
332        stale_while_revalidate: Option<u32>,
333        pci: bool,
334        surrogate_key: Option<HeaderValue>,
335    },
336}
337
338impl Default for CacheOverride {
339    fn default() -> Self {
340        Self::default()
341    }
342}
343
344impl CacheOverride {
345    pub const fn none() -> Self {
346        Self::None
347    }
348
349    pub const fn pass() -> Self {
350        Self::Pass
351    }
352
353    pub fn is_pass(&self) -> bool {
354        if let Self::Pass = self {
355            true
356        } else {
357            false
358        }
359    }
360
361    pub const fn ttl(ttl: u32) -> Self {
362        Self::Override {
363            ttl: Some(ttl),
364            stale_while_revalidate: None,
365            pci: false,
366            surrogate_key: None,
367        }
368    }
369
370    pub const fn stale_while_revalidate(swr: u32) -> Self {
371        Self::Override {
372            ttl: None,
373            stale_while_revalidate: Some(swr),
374            pci: false,
375            surrogate_key: None,
376        }
377    }
378
379    pub const fn pci(pci: bool) -> Self {
380        Self::Override {
381            ttl: None,
382            stale_while_revalidate: None,
383            pci,
384            surrogate_key: None,
385        }
386    }
387
388    pub const fn surrogate_key(sk: HeaderValue) -> Self {
389        Self::Override {
390            ttl: None,
391            stale_while_revalidate: None,
392            pci: false,
393            surrogate_key: Some(sk),
394        }
395    }
396
397    pub fn set_none(&mut self) {
398        *self = Self::None;
399    }
400
401    pub fn set_pass(&mut self, pass: bool) {
402        if pass {
403            *self = Self::Pass;
404        } else if let Self::Pass = self {
405            *self = Self::None;
406        }
407    }
408
409    pub fn get_ttl(&self) -> Option<u32> {
410        if let Self::Override { ttl, .. } = self {
411            *ttl
412        } else {
413            None
414        }
415    }
416
417    pub fn set_ttl(&mut self, new_ttl: u32) {
418        match self {
419            Self::Override { ttl, .. } => *ttl = Some(new_ttl),
420            _ => *self = Self::ttl(new_ttl),
421        }
422    }
423
424    pub fn get_stale_while_revalidate(&self) -> Option<u32> {
425        if let Self::Override {
426            stale_while_revalidate,
427            ..
428        } = self
429        {
430            *stale_while_revalidate
431        } else {
432            None
433        }
434    }
435
436    pub fn set_stale_while_revalidate(&mut self, new_swr: u32) {
437        match self {
438            Self::Override {
439                stale_while_revalidate,
440                ..
441            } => *stale_while_revalidate = Some(new_swr),
442            _ => *self = Self::stale_while_revalidate(new_swr),
443        }
444    }
445
446    pub fn get_pci(&self) -> Option<bool> {
447        if let Self::Override { pci, .. } = self {
448            Some(*pci)
449        } else {
450            None
451        }
452    }
453
454    pub fn set_pci(&mut self, new_pci: bool) {
455        match self {
456            Self::Override { pci, .. } => *pci = new_pci,
457            _ => *self = Self::pci(new_pci),
458        }
459    }
460
461    pub fn get_surrogate_key(&self) -> Option<&HeaderValue> {
462        if let Self::Override { surrogate_key, .. } = self {
463            surrogate_key.as_ref()
464        } else {
465            None
466        }
467    }
468
469    pub fn set_surrogate_key(&mut self, new_surrogate_key: HeaderValue) {
470        match self {
471            Self::Override { surrogate_key, .. } => *surrogate_key = Some(new_surrogate_key),
472            _ => *self = Self::surrogate_key(new_surrogate_key),
473        }
474    }
475
476    pub const fn default() -> Self {
477        Self::None
478    }
479
480    /// Convert to a representation suitable for passing across the ABI boundary.
481    ///
482    /// The representation contains the `CacheOverrideTag` along with all of the possible fields:
483    /// `(tag, ttl, swr, sk)`.
484    #[doc(hidden)]
485    pub fn to_abi(&self) -> (u32, u32, u32, Option<&[u8]>) {
486        match *self {
487            Self::None => (CacheOverrideTag::empty().bits(), 0, 0, None),
488            Self::Pass => (CacheOverrideTag::PASS.bits(), 0, 0, None),
489            Self::Override {
490                ttl,
491                stale_while_revalidate,
492                pci,
493                ref surrogate_key,
494            } => {
495                let mut tag = CacheOverrideTag::empty();
496                let ttl = if let Some(ttl) = ttl {
497                    tag |= CacheOverrideTag::TTL;
498                    ttl
499                } else {
500                    0
501                };
502                let swr = if let Some(swr) = stale_while_revalidate {
503                    tag |= CacheOverrideTag::STALE_WHILE_REVALIDATE;
504                    swr
505                } else {
506                    0
507                };
508                if pci {
509                    tag |= CacheOverrideTag::PCI;
510                }
511                let sk = surrogate_key.as_ref().map(HeaderValue::as_bytes);
512                (tag.bits(), ttl, swr, sk)
513            }
514        }
515    }
516}
517
518bitflags::bitflags! {
519    /// A bit field used to tell the host which fields are used when setting the cache override.
520    ///
521    /// If the `PASS` bit is set, all other bits are ignored.
522    struct CacheOverrideTag: u32 {
523        const PASS = 1 << 0;
524        const TTL = 1 << 1;
525        const STALE_WHILE_REVALIDATE = 1 << 2;
526        const PCI = 1 << 3;
527    }
528}
529
530#[derive(Debug)]
531pub enum ClientCertVerifyResult {
532    /// Success value.
533    ///
534    /// This indicates that client certificate verified successfully.
535    Ok,
536    /// Bad certificate error.
537    ///
538    /// This error means the certificate is corrupt
539    /// (e.g., the certificate signatures do not verify correctly).
540    BadCertificate,
541    /// Certificate revoked error.
542    ///
543    /// This error means the client certificate is revoked by its signer.
544    CertificateRevoked,
545    /// Certificate expired error.
546    ///
547    /// This error means the client certificate has expired or is not currently valid.
548    CertificateExpired,
549    /// Unknown CA error.
550    ///
551    /// This error means the valid certificate chain or partial chain was received, but the
552    /// certificate was not accepted because the CA certificate could not be located or could not
553    /// be matched with a known trust anchor.
554    UnknownCa,
555    /// Certificate missing error.
556    ///
557    /// This error means the client did not provide a certificate during the handshake.
558    CertificateMissing,
559    /// Certificate unknown error.
560    ///
561    /// This error means the client certificate was received, but some other (unspecified) issue
562    /// arose in processing the certificate, rendering it unacceptable.
563    CertificateUnknown,
564}
565
566impl ClientCertVerifyResult {
567    pub fn from_u32(value: u32) -> ClientCertVerifyResult {
568        match value {
569            0 => ClientCertVerifyResult::Ok,
570            1 => ClientCertVerifyResult::BadCertificate,
571            2 => ClientCertVerifyResult::CertificateRevoked,
572            3 => ClientCertVerifyResult::CertificateExpired,
573            4 => ClientCertVerifyResult::UnknownCa,
574            5 => ClientCertVerifyResult::CertificateMissing,
575            _ => ClientCertVerifyResult::CertificateUnknown,
576        }
577    }
578}