Skip to main content

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