1use crate::{pushpin::PushpinRedirectInfo, wiggle_abi::types::FastlyStatus};
4use std::error::Error as StdError;
5use std::io;
6use url::Url;
7use wiggle::GuestError;
8
9#[derive(Debug, thiserror::Error)]
10#[non_exhaustive]
11pub enum Error {
12 #[error("Buffer length error: {buf} too long to fit in {len}")]
14 BufferLengthError {
15 buf: &'static str,
16 len: &'static str,
17 },
18
19 #[error("Fatal error: [{0}]")]
22 FatalError(String),
23
24 #[error("Expected a valid Wasm file")]
26 FileFormat,
27
28 #[error("Expected a valid wastime's profiling strategy")]
29 ProfilingStrategy,
30
31 #[error(transparent)]
32 FastlyConfig(#[from] FastlyConfigError),
33
34 #[error("Could not determine address from backend URL: {0}")]
35 BackendUrl(Url),
36
37 #[error("Guest error: [{0}]")]
42 GuestError(#[from] wiggle::GuestError),
43
44 #[error(transparent)]
45 HandleError(#[from] HandleError),
46
47 #[error(transparent)]
48 HyperError(#[from] hyper::Error),
49
50 #[error(transparent)]
51 Infallible(#[from] std::convert::Infallible),
52
53 #[error("Invalid argument given")]
55 InvalidArgument,
56
57 #[error(transparent)]
58 InvalidHeaderName(#[from] http::header::InvalidHeaderName),
59
60 #[error(transparent)]
61 InvalidHeaderValue(#[from] http::header::InvalidHeaderValue),
62
63 #[error(transparent)]
64 InvalidMethod(#[from] http::method::InvalidMethod),
65
66 #[error(transparent)]
67 InvalidStatusCode(#[from] http::status::InvalidStatusCode),
68
69 #[error(transparent)]
70 InvalidUri(#[from] http::uri::InvalidUri),
71
72 #[error(transparent)]
73 IoError(#[from] std::io::Error),
74
75 #[error("Limit exceeded: {msg}")]
76 LimitExceeded { msg: &'static str },
77
78 #[error("Missing downstream metadata for request")]
79 MissingDownstreamMetadata,
80
81 #[error(transparent)]
82 Other(#[from] anyhow::Error),
83
84 #[error("Unsupported operation: {msg}")]
85 Unsupported { msg: &'static str },
86
87 #[error("Downstream response already sending")]
89 DownstreamRespSending,
90
91 #[error("Unexpected error sending a chunk to a streaming body")]
92 StreamingChunkSend,
93
94 #[error("Unknown backend: {0}")]
95 UnknownBackend(String),
96
97 #[error(transparent)]
98 DictionaryError(#[from] crate::wiggle_abi::DictionaryError),
99
100 #[error(transparent)]
101 DeviceDetectionError(#[from] crate::wiggle_abi::DeviceDetectionError),
102
103 #[error(transparent)]
104 ObjectStoreError(#[from] crate::object_store::ObjectStoreError),
105
106 #[error(transparent)]
107 KvStoreError(#[from] crate::object_store::KvStoreError),
108
109 #[error(transparent)]
110 SecretStoreError(#[from] crate::wiggle_abi::SecretStoreError),
111
112 #[error{"Expected UTF-8"}]
113 Utf8Expected(#[from] std::str::Utf8Error),
114
115 #[error{"Unsupported ABI version"}]
116 AbiVersionMismatch,
117
118 #[error(transparent)]
119 DownstreamRequestError(#[from] DownstreamRequestError),
120
121 #[error("{0} is not currently supported for local testing")]
122 NotAvailable(&'static str),
123
124 #[error("Could not load native certificates: {0}")]
125 BadCerts(std::io::Error),
126
127 #[error("Could not generate new backend name from '{0}'")]
128 BackendNameRegistryError(String),
129
130 #[error(transparent)]
131 HttpError(#[from] http::Error),
132
133 #[error("Object Store '{0}' does not exist")]
134 UnknownObjectStore(String),
135
136 #[error("Invalid Object Store `key` value used: {0}.")]
137 ObjectStoreKeyValidationError(#[from] crate::object_store::KeyValidationError),
138
139 #[error("Unfinished streaming body")]
140 UnfinishedStreamingBody,
141
142 #[error("Shared memory not supported yet")]
143 SharedMemory,
144
145 #[error("Value absent from structure")]
146 ValueAbsent,
147
148 #[error("String conversion error")]
149 ToStr(#[from] http::header::ToStrError),
150
151 #[error("invalid client certificate")]
152 InvalidClientCert(#[from] crate::config::ClientCertError),
153
154 #[error("Invalid response to ALPN request; wanted '{0}', got '{1}'")]
155 InvalidAlpnRepsonse(&'static str, String),
156
157 #[error("Resource temporarily unavailable")]
158 Again,
159
160 #[error("cache error: {0}")]
161 CacheError(crate::cache::Error),
162}
163
164impl Error {
165 pub fn to_fastly_status(&self) -> FastlyStatus {
172 match self {
173 Error::BufferLengthError { .. } => FastlyStatus::Buflen,
174 Error::InvalidArgument => FastlyStatus::Inval,
175 Error::ValueAbsent => FastlyStatus::None,
176 Error::Unsupported { .. } | Error::NotAvailable(_) => FastlyStatus::Unsupported,
177 Error::HandleError { .. } => FastlyStatus::Badf,
178 Error::InvalidStatusCode { .. } => FastlyStatus::Inval,
179 Error::UnknownBackend(_) | Error::InvalidClientCert(_) => FastlyStatus::Inval,
180 Error::HyperError(e) if e.is_parse() => FastlyStatus::Httpinvalid,
182 Error::HyperError(e) if e.is_user() => FastlyStatus::Httpuser,
183 Error::HyperError(e) if e.is_incomplete_message() => FastlyStatus::Httpincomplete,
184 Error::HyperError(e)
185 if e.source()
186 .and_then(|e| e.downcast_ref::<io::Error>())
187 .map(|ioe| ioe.kind())
188 == Some(io::ErrorKind::UnexpectedEof) =>
189 {
190 FastlyStatus::Httpincomplete
191 }
192 Error::HyperError(_) => FastlyStatus::Error,
193 Error::GuestError(e) => Self::guest_error_fastly_status(e),
195 Error::DictionaryError(e) => e.to_fastly_status(),
197 Error::DeviceDetectionError(e) => e.to_fastly_status(),
198 Error::ObjectStoreError(e) => e.into(),
199 Error::KvStoreError(e) => e.into(),
200 Error::SecretStoreError(e) => e.into(),
201 Error::Again => FastlyStatus::Again,
202 Error::LimitExceeded { .. } => FastlyStatus::Limitexceeded,
203 Error::CacheError(e) => e.into(),
204 Error::AbiVersionMismatch
206 | Error::BackendUrl(_)
207 | Error::BadCerts(_)
208 | Error::DownstreamRequestError(_)
209 | Error::DownstreamRespSending
210 | Error::FastlyConfig(_)
211 | Error::FatalError(_)
212 | Error::FileFormat
213 | Error::Infallible(_)
214 | Error::InvalidHeaderName(_)
215 | Error::InvalidHeaderValue(_)
216 | Error::InvalidMethod(_)
217 | Error::InvalidUri(_)
218 | Error::IoError(_)
219 | Error::MissingDownstreamMetadata
220 | Error::Other(_)
221 | Error::ProfilingStrategy
222 | Error::StreamingChunkSend
223 | Error::Utf8Expected(_)
224 | Error::BackendNameRegistryError(_)
225 | Error::HttpError(_)
226 | Error::UnknownObjectStore(_)
227 | Error::ObjectStoreKeyValidationError(_)
228 | Error::UnfinishedStreamingBody
229 | Error::SharedMemory
230 | Error::ToStr(_)
231 | Error::InvalidAlpnRepsonse(_, _) => FastlyStatus::Error,
232 }
233 }
234
235 fn guest_error_fastly_status(e: &GuestError) -> FastlyStatus {
236 use GuestError::*;
237 match e {
238 PtrNotAligned { .. } => FastlyStatus::Badalign,
239 InvalidFlagValue { .. }
242 | InvalidEnumValue { .. }
243 | PtrOutOfBounds { .. }
244 | PtrOverflow { .. }
245 | InvalidUtf8 { .. }
246 | TryFromIntError { .. } => FastlyStatus::Inval,
247 SliceLengthsDiffer => FastlyStatus::Error,
250 InFunc { err, .. } => Self::guest_error_fastly_status(err),
253 }
254 }
255}
256
257#[derive(Debug, thiserror::Error)]
259pub enum HandleError {
260 #[error("Invalid request handle: {0}")]
262 InvalidRequestHandle(crate::wiggle_abi::types::RequestHandle),
263
264 #[error("Invalid response handle: {0}")]
266 InvalidResponseHandle(crate::wiggle_abi::types::ResponseHandle),
267
268 #[error("Invalid body handle: {0}")]
270 InvalidBodyHandle(crate::wiggle_abi::types::BodyHandle),
271
272 #[error("Invalid endpoint handle: {0}")]
274 InvalidEndpointHandle(crate::wiggle_abi::types::EndpointHandle),
275
276 #[error("Invalid pending request promise handle: {0}")]
278 InvalidPendingRequestHandle(crate::wiggle_abi::types::PendingRequestHandle),
279
280 #[error("Invalid pending downstream request handle: {0}")]
282 InvalidPendingDownstreamHandle(crate::wiggle_abi::types::AsyncItemHandle),
283
284 #[error("Invalid pending KV lookup handle: {0}")]
286 InvalidPendingKvLookupHandle(crate::wiggle_abi::types::PendingKvLookupHandle),
287
288 #[error("Invalid pending KV insert handle: {0}")]
290 InvalidPendingKvInsertHandle(crate::wiggle_abi::types::PendingKvInsertHandle),
291
292 #[error("Invalid pending KV delete handle: {0}")]
294 InvalidPendingKvDeleteHandle(crate::wiggle_abi::types::PendingKvDeleteHandle),
295
296 #[error("Invalid pending KV list handle: {0}")]
298 InvalidPendingKvListHandle(crate::wiggle_abi::types::PendingKvListHandle),
299
300 #[error("Invalid dictionary handle: {0}")]
302 InvalidDictionaryHandle(crate::wiggle_abi::types::DictionaryHandle),
303
304 #[error("Invalid object-store handle: {0}")]
306 InvalidObjectStoreHandle(crate::wiggle_abi::types::ObjectStoreHandle),
307
308 #[error("Invalid secret store handle: {0}")]
310 InvalidSecretStoreHandle(crate::wiggle_abi::types::SecretStoreHandle),
311
312 #[error("Invalid secret handle: {0}")]
314 InvalidSecretHandle(crate::wiggle_abi::types::SecretHandle),
315
316 #[error("Invalid async item handle: {0}")]
318 InvalidAsyncItemHandle(crate::wiggle_abi::types::AsyncItemHandle),
319
320 #[error("Invalid acl handle: {0}")]
322 InvalidAclHandle(crate::wiggle_abi::types::AclHandle),
323
324 #[error("Invalid cache handle: {0}")]
326 InvalidCacheHandle(crate::wiggle_abi::types::CacheHandle),
327}
328
329#[derive(Debug, thiserror::Error)]
337pub(crate) enum ExecutionError {
338 #[error("WebAssembly execution trapped: {0}")]
344 WasmTrap(anyhow::Error),
345
346 #[error("Error creating context: {0}")]
348 Context(anyhow::Error),
349
350 #[error("Error type-checking WebAssembly instantiation: {0}")]
352 Typechecking(anyhow::Error),
353
354 #[error("Error instantiating WebAssembly: {0}")]
356 Instantiation(anyhow::Error),
357}
358
359#[derive(Debug, thiserror::Error)]
361pub enum FastlyConfigError {
362 #[error("error reading '{path}': {err}")]
364 IoError {
365 path: String,
366 #[source]
367 err: std::io::Error,
368 },
369
370 #[error("invalid configuration for '{name}': {err}")]
371 InvalidDeviceDetectionDefinition {
372 name: String,
373 #[source]
374 err: DeviceDetectionConfigError,
375 },
376
377 #[error("invalid configuration for '{name}': {err}")]
378 InvalidGeolocationDefinition {
379 name: String,
380 #[source]
381 err: GeolocationConfigError,
382 },
383
384 #[error("invalid configuration for '{name}': {err}")]
385 InvalidAclDefinition {
386 name: String,
387 #[source]
388 err: AclConfigError,
389 },
390
391 #[error("invalid configuration for '{name}': {err}")]
392 InvalidBackendDefinition {
393 name: String,
394 #[source]
395 err: BackendConfigError,
396 },
397
398 #[error("invalid configuration for '{name}': {err}")]
399 InvalidDictionaryDefinition {
400 name: String,
401 #[source]
402 err: DictionaryConfigError,
403 },
404
405 #[error("invalid configuration for '{name}': {err}")]
406 InvalidObjectStoreDefinition {
407 name: String,
408 #[source]
409 err: ObjectStoreConfigError,
410 },
411
412 #[error("invalid configuration for '{name}': {err}")]
413 InvalidSecretStoreDefinition {
414 name: String,
415 #[source]
416 err: SecretStoreConfigError,
417 },
418
419 #[error("invalid configuration for '{name}': {err}")]
420 InvalidShieldingSiteDefinition {
421 name: String,
422 #[source]
423 err: ShieldingSiteConfigError,
424 },
425
426 #[error("error parsing `fastly.toml`: {0}")]
430 InvalidFastlyToml(#[from] toml::de::Error),
431
432 #[error("invalid manifest version: {0}")]
439 InvalidManifestVersion(#[from] semver::SemVerError),
440}
441
442#[derive(Debug, thiserror::Error)]
444pub enum AclConfigError {
445 #[error(transparent)]
447 IoError(std::io::Error),
448
449 #[error(transparent)]
451 JsonError(serde_json::error::Error),
452
453 #[error("acl must be a TOML table or string")]
454 InvalidType,
455
456 #[error("missing 'file' field")]
457 MissingFile,
458}
459
460#[derive(Debug, thiserror::Error)]
462pub enum BackendConfigError {
463 #[error("definition was not provided as a TOML table")]
464 InvalidEntryType,
465
466 #[error("invalid override_host: {0}")]
467 InvalidOverrideHost(#[from] http::header::InvalidHeaderValue),
468
469 #[error("'override_host' field is empty")]
470 EmptyOverrideHost,
471
472 #[error("'override_host' field was not a string")]
473 InvalidOverrideHostEntry,
474
475 #[error("'cert_host' field is empty")]
476 EmptyCertHost,
477
478 #[error("'cert_host' field was not a string")]
479 InvalidCertHostEntry,
480
481 #[error("'ca_certificate' field is empty")]
482 EmptyCACert,
483
484 #[error("'ca_certificate' field was invalid: {0}")]
485 InvalidCACertEntry(String),
486
487 #[error("'use_sni' field was not a boolean")]
488 InvalidUseSniEntry,
489
490 #[error("'grpc' field was not a boolean")]
491 InvalidGrpcEntry,
492
493 #[error("invalid url: {0}")]
494 InvalidUrl(#[from] http::uri::InvalidUri),
495
496 #[error("'url' field was not a string")]
497 InvalidUrlEntry,
498
499 #[error("no default definition provided")]
500 MissingDefault,
501
502 #[error("missing 'url' field")]
503 MissingUrl,
504
505 #[error("unrecognized key '{0}'")]
506 UnrecognizedKey(String),
507
508 #[error(transparent)]
509 ClientCertError(#[from] crate::config::ClientCertError),
510}
511
512#[derive(Debug, thiserror::Error)]
514pub enum DictionaryConfigError {
515 #[error(transparent)]
517 IoError(std::io::Error),
518
519 #[error("'contents' was not provided as a TOML table")]
520 InvalidContentsType,
521
522 #[error("inline dictionary value was not a string")]
523 InvalidInlineEntryType,
524
525 #[error("definition was not provided as a TOML table")]
526 InvalidEntryType,
527
528 #[error("'name' field was not a string")]
529 InvalidNameEntry,
530
531 #[error("'{0}' is not a valid format for the dictionary. Supported format(s) are: 'inline-toml', 'json'.")]
532 InvalidDictionaryFormat(String),
533
534 #[error("'file' field is empty")]
535 EmptyFileEntry,
536
537 #[error("'format' field is empty")]
538 EmptyFormatEntry,
539
540 #[error("'file' field was not a string")]
541 InvalidFileEntry,
542
543 #[error("'format' field was not a string")]
544 InvalidFormatEntry,
545
546 #[error("missing 'contents' field")]
547 MissingContents,
548
549 #[error("no default definition provided")]
550 MissingDefault,
551
552 #[error("missing 'name' field")]
553 MissingName,
554
555 #[error("missing 'file' field")]
556 MissingFile,
557
558 #[error("missing 'format' field")]
559 MissingFormat,
560
561 #[error("unrecognized key '{0}'")]
562 UnrecognizedKey(String),
563
564 #[error("Item key named '{key}' is too long, max size is {size}")]
565 DictionaryItemKeyTooLong { key: String, size: i32 },
566
567 #[error("too many items, max amount is {size}")]
568 DictionaryCountTooLong { size: i32 },
569
570 #[error("Item value under key named '{key}' is of the wrong format. The value is expected to be a JSON String")]
571 DictionaryItemValueWrongFormat { key: String },
572
573 #[error("Item value named '{key}' is too long, max size is {size}")]
574 DictionaryItemValueTooLong { key: String, size: i32 },
575
576 #[error(
577 "The file is of the wrong format. The file is expected to contain a single JSON Object"
578 )]
579 DictionaryFileWrongFormat,
580}
581
582#[derive(Debug, thiserror::Error)]
584pub enum DeviceDetectionConfigError {
585 #[error(transparent)]
587 IoError(std::io::Error),
588
589 #[error("definition was not provided as a TOML table")]
590 InvalidEntryType,
591
592 #[error("missing 'file' field")]
593 MissingFile,
594
595 #[error("'file' field is empty")]
596 EmptyFileEntry,
597
598 #[error("missing 'user_agents' field")]
599 MissingUserAgents,
600
601 #[error("inline device detection value was not a string")]
602 InvalidInlineEntryType,
603
604 #[error("'file' field was not a string")]
605 InvalidFileEntry,
606
607 #[error("'user_agents' was not provided as a TOML table")]
608 InvalidUserAgentsType,
609
610 #[error("unrecognized key '{0}'")]
611 UnrecognizedKey(String),
612
613 #[error("missing 'format' field")]
614 MissingFormat,
615
616 #[error("'format' field was not a string")]
617 InvalidFormatEntry,
618
619 #[error("'{0}' is not a valid format for the device detection mapping. Supported format(s) are: 'inline-toml', 'json'.")]
620 InvalidDeviceDetectionMappingFormat(String),
621
622 #[error(
623 "The file is of the wrong format. The file is expected to contain a single JSON Object"
624 )]
625 DeviceDetectionFileWrongFormat,
626
627 #[error("'format' field is empty")]
628 EmptyFormatEntry,
629
630 #[error("Item value under key named '{key}' is of the wrong format. The value is expected to be a JSON String")]
631 DeviceDetectionItemValueWrongFormat { key: String },
632}
633
634#[derive(Debug, thiserror::Error)]
636pub enum GeolocationConfigError {
637 #[error(transparent)]
639 IoError(std::io::Error),
640
641 #[error("definition was not provided as a TOML table")]
642 InvalidEntryType,
643
644 #[error("missing 'file' field")]
645 MissingFile,
646
647 #[error("'file' field is empty")]
648 EmptyFileEntry,
649
650 #[error("missing 'addresses' field")]
651 MissingAddresses,
652
653 #[error("inline geolocation value was not a string")]
654 InvalidInlineEntryType,
655
656 #[error("'file' field was not a string")]
657 InvalidFileEntry,
658
659 #[error("'addresses' was not provided as a TOML table")]
660 InvalidAddressesType,
661
662 #[error("unrecognized key '{0}'")]
663 UnrecognizedKey(String),
664
665 #[error("missing 'format' field")]
666 MissingFormat,
667
668 #[error("'format' field was not a string")]
669 InvalidFormatEntry,
670
671 #[error("IP address not valid: '{0}'")]
672 InvalidAddressEntry(String),
673
674 #[error("'{0}' is not a valid format for the geolocation mapping. Supported format(s) are: 'inline-toml', 'json'.")]
675 InvalidGeolocationMappingFormat(String),
676
677 #[error(
678 "The file is of the wrong format. The file is expected to contain a single JSON Object"
679 )]
680 GeolocationFileWrongFormat,
681
682 #[error("'format' field is empty")]
683 EmptyFormatEntry,
684
685 #[error("Item value under key named '{key}' is of the wrong format. The value is expected to be a JSON String")]
686 GeolocationItemValueWrongFormat { key: String },
687}
688
689#[derive(Debug, thiserror::Error)]
691pub enum ObjectStoreConfigError {
692 #[error(transparent)]
694 IoError(std::io::Error),
695 #[error("The `file` and `data` keys for the object `{0}` are set. Only one can be used.")]
696 FileAndData(String),
697 #[error("The `file` or `data` key for the object `{0}` is not set. One must be used.")]
698 NoFileOrData(String),
699 #[error("The `data` value for the object `{0}` is not a string.")]
700 DataNotAString(String),
701 #[error("The `metadata` value for the object `{0}` is not a string.")]
702 MetadataNotAString(String),
703 #[error("The `file` value for the object `{0}` is not a string.")]
704 FileNotAString(String),
705 #[error("The `key` key for an object is not set. It must be used.")]
706 NoKey,
707 #[error("The `key` value for an object is not a string.")]
708 KeyNotAString,
709 #[error("There is no array of objects for the given store.")]
710 NotAnArray,
711 #[error("There is an object in the given store that is not a table of keys.")]
712 NotATable,
713 #[error("There was an error when manipulating the ObjectStore: {0}.")]
714 ObjectStoreError(#[from] crate::object_store::ObjectStoreError),
715 #[error("There was an error when manipulating the KvStore: {0}.")]
716 KvStoreError(#[from] crate::object_store::KvStoreError),
717 #[error("Invalid `key` value used: {0}.")]
718 KeyValidationError(#[from] crate::object_store::KeyValidationError),
719 #[error("'{0}' is not a valid format for the config store. Supported format(s) are: 'json'.")]
720 InvalidFileFormat(String),
721 #[error("When using a top-level 'file' to load data, both 'file' and 'format' must be set.")]
722 OnlyOneFormatOrFileSet,
723 #[error(
724 "The file is of the wrong format. The file is expected to contain a single JSON Object."
725 )]
726 FileWrongFormat,
727 #[error("Item value under key named '{key}' is of the wrong format. The value is expected to be a JSON String.")]
728 FileValueWrongFormat { key: String },
729 #[error("Item value under key named '{key}' is of the wrong format. 'data' and 'file' are mutually exclusive.")]
730 BothDataAndFilePresent { key: String },
731 #[error("Item value under key named '{key}' is of the wrong format. One of 'data' or 'file' must be present.")]
732 MissingDataOrFile { key: String },
733}
734
735#[derive(Debug, thiserror::Error)]
737pub enum SecretStoreConfigError {
738 #[error(transparent)]
740 IoError(std::io::Error),
741
742 #[error("'{0}' is not a valid format for the secret store. Supported format(s) are: 'json'.")]
743 InvalidFileFormat(String),
744 #[error("When using a top-level 'file' to load data, both 'file' and 'format' must be set.")]
745 OnlyOneFormatOrFileSet,
746 #[error(
747 "The file is of the wrong format. The file is expected to contain a single JSON object."
748 )]
749 FileWrongFormat,
750 #[error("More than one of `file`, `data`, or `env` keys for the object `{0}` are set. Only one can be used.")]
751 FileDataEnvExclusive(String),
752 #[error(
753 "None of `file`, `data`, or `env` keys for the object `{0}` is set. One must be used."
754 )]
755 FileDataEnvNotSet(String),
756 #[error("The `data` value for the object `{0}` is not a string.")]
757 DataNotAString(String),
758 #[error("The `file` value for the object `{0}` is not a string.")]
759 FileNotAString(String),
760 #[error("The `env` value for the object `{0}` is not a string.")]
761 EnvNotAString(String),
762
763 #[error("The `key` key for an object is not set. It must be used.")]
764 NoKey,
765 #[error("The `key` value for an object is not a string.")]
766 KeyNotAString,
767
768 #[error("There is no array of objects for the given store.")]
769 NotAnArray,
770 #[error("There is an object in the given store that is not a table of keys.")]
771 NotATable,
772
773 #[error("Invalid secret store name: {0}")]
774 InvalidSecretStoreName(String),
775
776 #[error("Invalid secret name: {0}")]
777 InvalidSecretName(String),
778}
779
780#[derive(Debug, thiserror::Error)]
782pub enum ShieldingSiteConfigError {
783 #[error("Illegal TOML value for shielding site; must be either the string 'local' or a table containin an encrypted and unencrypted URL.")]
784 IllegalSiteValue,
785
786 #[error("Illegal TOML string for shielding site; must be 'local'")]
787 IllegalSiteString,
788
789 #[error("Illegal table for shielding site; must have exactly one key named 'encrypted', and one named 'unencrypted'")]
790 IllegalSiteDefinition,
791
792 #[error("Illegal URL ({url}): {error}")]
793 IllegalUrl { url: String, error: url::ParseError },
794}
795
796#[derive(Debug, thiserror::Error)]
798pub enum DownstreamRequestError {
799 #[error("Request HOST header is missing or invalid")]
800 InvalidHost,
801
802 #[error("Request URL is invalid")]
803 InvalidUrl,
804}
805
806#[derive(Debug, thiserror::Error)]
809pub enum NonHttpResponse {
810 #[error("graceful Pushpin redirect")]
811 PushpinRedirect(PushpinRedirectInfo),
812 }