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_REQUEST_PROMISE_HANDLE: u32 = std::u32::MAX - 1;
34pub const INVALID_RESPONSE_HANDLE: u32 = std::u32::MAX - 1;
35pub const INVALID_SECRET_HANDLE: u32 = std::u32::MAX - 1;
36pub const INVALID_SECRET_STORE_HANDLE: u32 = std::u32::MAX - 1;
37
38/// Constants for defining minimum/maximum TLS versions for connecting to backends.
39#[allow(non_snake_case)]
40#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41#[repr(u32)]
42pub enum SslVersion {
43    TLS1 = 0,
44    TLS1_1 = 1,
45    TLS1_2 = 2,
46    TLS1_3 = 3,
47}
48
49impl SslVersion {
50    pub fn as_u32(&self) -> u32 {
51        *self as u32
52    }
53}
54
55// TODO KTM 2023-02-08: could use num-derive for this, but I don't think it's worth pulling in a
56// whole new set of dependencies when this will likely be encoded by witx shortly (see HttpVersion)
57impl TryFrom<u32> for SslVersion {
58    type Error = String;
59    fn try_from(x: u32) -> Result<Self, Self::Error> {
60        if x == Self::TLS1 as u32 {
61            Ok(Self::TLS1)
62        } else if x == Self::TLS1_1 as u32 {
63            Ok(Self::TLS1_1)
64        } else if x == Self::TLS1_2 as u32 {
65            Ok(Self::TLS1_2)
66        } else if x == Self::TLS1_3 as u32 {
67            Ok(Self::TLS1_3)
68        } else {
69            Err(format!("unknown ssl version enum value: {}", x))
70        }
71    }
72}
73
74#[derive(Clone, Copy, Eq, PartialEq)]
75#[repr(transparent)]
76pub struct FastlyStatus {
77    pub code: i32,
78}
79
80impl FastlyStatus {
81    /// Success value.
82    ///
83    /// This indicates that a hostcall finished successfully.
84    pub const OK: Self = Self { code: 0 };
85    /// Generic error value.
86    ///
87    /// This means that some unexpected error occurred during a hostcall.
88    pub const ERROR: Self = Self { code: 1 };
89    /// Invalid argument.
90    pub const INVAL: Self = Self { code: 2 };
91    /// Invalid handle.
92    ///
93    /// Returned when a request, response, or body handle is not valid.
94    pub const BADF: Self = Self { code: 3 };
95    /// Buffer length error.
96    ///
97    /// Returned when a buffer is too long.
98    pub const BUFLEN: Self = Self { code: 4 };
99    /// Unsupported operation error.
100    ///
101    /// This error is returned when some operation cannot be performed, because it is not supported.
102    pub const UNSUPPORTED: Self = Self { code: 5 };
103    /// Alignment error.
104    ///
105    /// This is returned when a pointer does not point to a properly aligned slice of memory.
106    pub const BADALIGN: Self = Self { code: 6 };
107    /// Invalid HTTP error.
108    ///
109    /// This can be returned when a method, URI, or header is not valid.
110    pub const HTTPINVALID: Self = Self { code: 7 };
111    /// HTTP user error.
112    ///
113    /// This is returned in cases where user code caused an HTTP error. For example, attempt to send
114    /// a 1xx response code, or a request with a non-absolute URI. This can also be caused by
115    /// an unexpected header: both `content-length` and `transfer-encoding`, for example.
116    pub const HTTPUSER: Self = Self { code: 8 };
117    /// HTTP incomplete message error.
118    ///
119    /// This can be returned when a stream ended unexpectedly.
120    pub const HTTPINCOMPLETE: Self = Self { code: 9 };
121    /// A `None` error.
122    ///
123    /// This status code is used to indicate when an optional value did not exist, as opposed to
124    /// an empty value.
125    pub const NONE: Self = Self { code: 10 };
126    /// HTTP head too large error.
127    ///
128    /// This error will be returned when the message head is too large.
129    pub const HTTPHEADTOOLARGE: Self = Self { code: 11 };
130    /// HTTP invalid status error.
131    ///
132    /// This error will be returned when the HTTP message contains an invalid status code.
133    pub const HTTPINVALIDSTATUS: Self = Self { code: 12 };
134    /// Limit exceeded
135    ///
136    /// This is returned when an attempt to allocate a resource has exceeded the maximum number of
137    /// resources permitted. For example, creating too many response handles.
138    pub const LIMITEXCEEDED: Self = Self { code: 13 };
139    /// Resource temporarily unavailable
140    ///
141    /// This is returned when an attempting to retrieve a resource that is not yet available.
142    /// For example when attempting to read trailers from a Body that has not yet been consumed.
143    pub const AGAIN: Self = Self { code: 14 };
144
145    pub fn is_ok(&self) -> bool {
146        self == &Self::OK
147    }
148
149    pub fn is_err(&self) -> bool {
150        !self.is_ok()
151    }
152
153    /// Convert a `FastlyStatus` value to a `Result<(), FastlyStatus>`.
154    ///
155    /// This will consume a status code, and return `Ok(())` if and only if the value was
156    /// `FastlyStatus::OK`. If the status code was some error, then it will be returned in the
157    /// result's `Err` variant.
158    pub fn result(self) -> Result<(), Self> {
159        if let Self::OK = self {
160            Ok(())
161        } else {
162            Err(self)
163        }
164    }
165}
166
167impl fmt::Debug for FastlyStatus {
168    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169        write!(f, "FastlyStatus::")?;
170        match *self {
171            Self::OK => write!(f, "OK"),
172            Self::ERROR => write!(f, "ERROR"),
173            Self::INVAL => write!(f, "INVAL"),
174            Self::BADF => write!(f, "BADF"),
175            Self::BUFLEN => write!(f, "BUFLEN"),
176            Self::UNSUPPORTED => write!(f, "UNSUPPORTED"),
177            Self::BADALIGN => write!(f, "BADALIGN"),
178            Self::HTTPINVALID => write!(f, "HTTP_INVALID_ERROR"),
179            Self::HTTPUSER => write!(f, "HTTP_USER_ERROR"),
180            Self::HTTPINCOMPLETE => write!(f, "HTTP_INCOMPLETE_MESSAGE"),
181            Self::NONE => write!(f, "NONE"),
182            Self::HTTPHEADTOOLARGE => write!(f, "HTTP_HEAD_TOO_LARGE"),
183            Self::HTTPINVALIDSTATUS => write!(f, "HTTP_INVALID_STATUS"),
184            Self::LIMITEXCEEDED => write!(f, "LIMIT_EXCEEDED"),
185            Self::AGAIN => write!(f, "AGAIN"),
186            _ => write!(f, "UNKNOWN ({})", self.code),
187        }
188    }
189}
190
191pub const FASTLY_ABI_VERSION: u64 = 1;
192
193// define our own enum rather than using `http`'s, so that we can easily convert it to a scalar
194#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
195#[repr(u32)]
196pub enum HttpVersion {
197    Http09 = 0,
198    Http10 = 1,
199    Http11 = 2,
200    H2 = 3,
201    H3 = 4,
202}
203
204impl HttpVersion {
205    pub fn as_u32(&self) -> u32 {
206        *self as u32
207    }
208}
209
210// TODO ACF 2019-12-04: could use num-derive for this, but I don't think it's worth pulling in a
211// whole new set of dependencies when this will likely be encoded by witx shortly
212impl TryFrom<u32> for HttpVersion {
213    type Error = String;
214
215    fn try_from(x: u32) -> Result<Self, Self::Error> {
216        if x == Self::Http09 as u32 {
217            Ok(Self::Http09)
218        } else if x == Self::Http10 as u32 {
219            Ok(Self::Http10)
220        } else if x == Self::Http11 as u32 {
221            Ok(Self::Http11)
222        } else if x == Self::H2 as u32 {
223            Ok(Self::H2)
224        } else if x == Self::H3 as u32 {
225            Ok(Self::H3)
226        } else {
227            Err(format!("unknown http version enum value: {}", x))
228        }
229    }
230}
231
232impl From<http::Version> for HttpVersion {
233    fn from(v: http::Version) -> Self {
234        match v {
235            http::Version::HTTP_09 => Self::Http09,
236            http::Version::HTTP_10 => Self::Http10,
237            http::Version::HTTP_11 => Self::Http11,
238            http::Version::HTTP_2 => Self::H2,
239            http::Version::HTTP_3 => Self::H3,
240            _ => unreachable!(),
241        }
242    }
243}
244
245impl From<HttpVersion> for http::Version {
246    fn from(v: HttpVersion) -> Self {
247        match v {
248            HttpVersion::Http09 => Self::HTTP_09,
249            HttpVersion::Http10 => Self::HTTP_10,
250            HttpVersion::Http11 => Self::HTTP_11,
251            HttpVersion::H2 => Self::HTTP_2,
252            HttpVersion::H3 => Self::HTTP_3,
253        }
254    }
255}
256
257#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
258#[repr(u32)]
259pub enum BodyWriteEnd {
260    Back = 0,
261    Front = 1,
262}
263
264/// Determines how the framing headers (`Content-Length`/`Transfer-Encoding`) are set for a
265/// request or response.
266#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
267#[repr(u32)]
268pub enum FramingHeadersMode {
269    /// Determine the framing headers automatically based on the message body, and discard any framing
270    /// headers already set in the message. This is the default behavior.
271    ///
272    /// In automatic mode, a `Content-Length` is used when the size of the body can be determined
273    /// before it is sent. Requests/responses sent in streaming mode, where headers are sent immediately
274    /// but the content of the body is streamed later, will receive a `Transfer-Encoding: chunked`
275    /// to accommodate the dynamic generation of the body.
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
293impl Default for FramingHeadersMode {
294    fn default() -> Self {
295        Self::Automatic
296    }
297}
298
299/// Determines whether the client is encouraged to stop using the current connection and to open a
300/// new one for the next request.
301///
302/// Most applications do not need to change this setting.
303#[doc(hidden)]
304#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
305#[repr(u32)]
306pub enum HttpKeepaliveMode {
307    /// This is the default behavor.
308    Automatic = 0,
309
310    /// Send `Connection: close` in HTTP/1 and a GOAWAY frame in HTTP/2 and HTTP/3.  This prompts
311    /// the client to close the current connection and to open a new one for the next request.
312    NoKeepalive = 1,
313}
314
315impl Default for HttpKeepaliveMode {
316    fn default() -> Self {
317        Self::Automatic
318    }
319}
320
321/// Optional override for response caching behavior.
322#[derive(Clone, Debug)]
323pub enum CacheOverride {
324    /// Do not override the behavior specified in the origin response's cache control headers.
325    None,
326    /// Do not cache the response to this request, regardless of the origin response's headers.
327    Pass,
328    /// Override particular cache control settings.
329    ///
330    /// The origin response's cache control headers will be used for ttl and stale_while_revalidate if `None`.
331    Override {
332        ttl: Option<u32>,
333        stale_while_revalidate: Option<u32>,
334        pci: bool,
335        surrogate_key: Option<HeaderValue>,
336    },
337}
338
339impl Default for CacheOverride {
340    fn default() -> Self {
341        Self::default()
342    }
343}
344
345impl CacheOverride {
346    pub const fn none() -> Self {
347        Self::None
348    }
349
350    pub const fn pass() -> Self {
351        Self::Pass
352    }
353
354    pub fn is_pass(&self) -> bool {
355        if let Self::Pass = self {
356            true
357        } else {
358            false
359        }
360    }
361
362    pub const fn ttl(ttl: u32) -> Self {
363        Self::Override {
364            ttl: Some(ttl),
365            stale_while_revalidate: None,
366            pci: false,
367            surrogate_key: None,
368        }
369    }
370
371    pub const fn stale_while_revalidate(swr: u32) -> Self {
372        Self::Override {
373            ttl: None,
374            stale_while_revalidate: Some(swr),
375            pci: false,
376            surrogate_key: None,
377        }
378    }
379
380    pub const fn pci(pci: bool) -> Self {
381        Self::Override {
382            ttl: None,
383            stale_while_revalidate: None,
384            pci,
385            surrogate_key: None,
386        }
387    }
388
389    pub const fn surrogate_key(sk: HeaderValue) -> Self {
390        Self::Override {
391            ttl: None,
392            stale_while_revalidate: None,
393            pci: false,
394            surrogate_key: Some(sk),
395        }
396    }
397
398    pub fn set_none(&mut self) {
399        *self = Self::None;
400    }
401
402    pub fn set_pass(&mut self, pass: bool) {
403        if pass {
404            *self = Self::Pass;
405        } else if let Self::Pass = self {
406            *self = Self::None;
407        }
408    }
409
410    pub fn get_ttl(&self) -> Option<u32> {
411        if let Self::Override { ttl, .. } = self {
412            *ttl
413        } else {
414            None
415        }
416    }
417
418    pub fn set_ttl(&mut self, new_ttl: u32) {
419        match self {
420            Self::Override { ttl, .. } => *ttl = Some(new_ttl),
421            _ => *self = Self::ttl(new_ttl),
422        }
423    }
424
425    pub fn get_stale_while_revalidate(&self) -> Option<u32> {
426        if let Self::Override {
427            stale_while_revalidate,
428            ..
429        } = self
430        {
431            *stale_while_revalidate
432        } else {
433            None
434        }
435    }
436
437    pub fn set_stale_while_revalidate(&mut self, new_swr: u32) {
438        match self {
439            Self::Override {
440                stale_while_revalidate,
441                ..
442            } => *stale_while_revalidate = Some(new_swr),
443            _ => *self = Self::stale_while_revalidate(new_swr),
444        }
445    }
446
447    pub fn get_pci(&self) -> Option<bool> {
448        if let Self::Override { pci, .. } = self {
449            Some(*pci)
450        } else {
451            None
452        }
453    }
454
455    pub fn set_pci(&mut self, new_pci: bool) {
456        match self {
457            Self::Override { pci, .. } => *pci = new_pci,
458            _ => *self = Self::pci(new_pci),
459        }
460    }
461
462    pub fn get_surrogate_key(&self) -> Option<&HeaderValue> {
463        if let Self::Override { surrogate_key, .. } = self {
464            surrogate_key.as_ref()
465        } else {
466            None
467        }
468    }
469
470    pub fn set_surrogate_key(&mut self, new_surrogate_key: HeaderValue) {
471        match self {
472            Self::Override { surrogate_key, .. } => *surrogate_key = Some(new_surrogate_key),
473            _ => *self = Self::surrogate_key(new_surrogate_key),
474        }
475    }
476
477    pub const fn default() -> Self {
478        Self::None
479    }
480
481    /// Convert to a representation suitable for passing across the ABI boundary.
482    ///
483    /// The representation contains the `CacheOverrideTag` along with all of the possible fields:
484    /// `(tag, ttl, swr, sk)`.
485    #[doc(hidden)]
486    pub fn to_abi(&self) -> (u32, u32, u32, Option<&[u8]>) {
487        match *self {
488            Self::None => (CacheOverrideTag::empty().bits(), 0, 0, None),
489            Self::Pass => (CacheOverrideTag::PASS.bits(), 0, 0, None),
490            Self::Override {
491                ttl,
492                stale_while_revalidate,
493                pci,
494                ref surrogate_key,
495            } => {
496                let mut tag = CacheOverrideTag::empty();
497                let ttl = if let Some(ttl) = ttl {
498                    tag |= CacheOverrideTag::TTL;
499                    ttl
500                } else {
501                    0
502                };
503                let swr = if let Some(swr) = stale_while_revalidate {
504                    tag |= CacheOverrideTag::STALE_WHILE_REVALIDATE;
505                    swr
506                } else {
507                    0
508                };
509                if pci {
510                    tag |= CacheOverrideTag::PCI;
511                }
512                let sk = surrogate_key.as_ref().map(HeaderValue::as_bytes);
513                (tag.bits(), ttl, swr, sk)
514            }
515        }
516    }
517}
518
519bitflags::bitflags! {
520    /// A bit field used to tell the host which fields are used when setting the cache override.
521    ///
522    /// If the `PASS` bit is set, all other bits are ignored.
523    struct CacheOverrideTag: u32 {
524        const PASS = 1 << 0;
525        const TTL = 1 << 1;
526        const STALE_WHILE_REVALIDATE = 1 << 2;
527        const PCI = 1 << 3;
528    }
529}
530
531#[derive(Debug, Clone, Copy, Eq, PartialEq)]
532pub enum ClientCertVerifyResult {
533    /// Success value.
534    ///
535    /// This indicates that client certificate verified successfully.
536    Ok,
537    /// Bad certificate error.
538    ///
539    /// This error means the certificate is corrupt
540    /// (e.g., the certificate signatures do not verify correctly).
541    BadCertificate,
542    /// Certificate revoked error.
543    ///
544    /// This error means the client certificate is revoked by its signer.
545    CertificateRevoked,
546    /// Certificate expired error.
547    ///
548    /// This error means the client certificate has expired or is not currently valid.
549    CertificateExpired,
550    /// Unknown CA error.
551    ///
552    /// This error means the valid certificate chain or partial chain was received, but the
553    /// certificate was not accepted because the CA certificate could not be located or could not
554    /// be matched with a known trust anchor.
555    UnknownCa,
556    /// Certificate missing error.
557    ///
558    /// This error means the client did not provide a certificate during the handshake.
559    CertificateMissing,
560    /// Certificate unknown error.
561    ///
562    /// This error means the client certificate was received, but some other (unspecified) issue
563    /// arose in processing the certificate, rendering it unacceptable.
564    CertificateUnknown,
565}
566
567impl ClientCertVerifyResult {
568    pub fn from_u32(value: u32) -> ClientCertVerifyResult {
569        match value {
570            0 => ClientCertVerifyResult::Ok,
571            1 => ClientCertVerifyResult::BadCertificate,
572            2 => ClientCertVerifyResult::CertificateRevoked,
573            3 => ClientCertVerifyResult::CertificateExpired,
574            4 => ClientCertVerifyResult::UnknownCa,
575            5 => ClientCertVerifyResult::CertificateMissing,
576            _ => ClientCertVerifyResult::CertificateUnknown,
577        }
578    }
579}