3
3
pub use error_chain:: bail;
4
4
use error_chain:: error_chain;
5
5
6
+ /// Defines who caused an ambiguous error message so we can reliably create an HTTP status code. Specific status codes may be provided
7
+ /// in either case, or the defaults (400 for client, 500 for server) will be used.
8
+ #[ derive( Debug ) ]
9
+ pub enum ErrorCause {
10
+ Client ( Option < u16 > ) ,
11
+ Server ( Option < u16 > )
12
+ }
13
+
14
+ // TODO disclose what information may be revealed over the network through these errors in docs
6
15
// The `error_chain` setup for the whole crate
7
16
error_chain ! {
8
17
// The custom errors for this crate (very broad)
9
18
errors {
10
- /// For indistinct JavaScript errors.
19
+ /// For indistinct JavaScript errors (potentially sensitive, but only generated on the client-side) .
11
20
JsErr ( err: String ) {
12
21
description( "an error occurred while interfacing with javascript" )
13
22
display( "the following error occurred while interfacing with javascript: {:?}" , err)
14
23
}
24
+ /// For when a fetched URL didn't return a string, which it must.
25
+ AssetNotString ( url: String ) {
26
+ description( "the fetched asset wasn't a string" )
27
+ display( "the fetched asset at '{}' wasn't a string" , url)
28
+ }
29
+ /// For when the server returned a non-200 error code (not including 404, that's handled separately).
30
+ AssetNotOk ( url: String , status: u16 , err: String ) {
31
+ description( "the asset couldn't be fecthed with a 200 OK" )
32
+ display( "the asset at '{}' returned status code '{}' with payload '{}'" , url, status, err)
33
+ }
15
34
35
+ /// For when a necessary template feautre was expected but not present. This just pertains to rendering strategies, and shouldn't
36
+ /// ever be sensitive.
16
37
TemplateFeatureNotEnabled ( name: String , feature: String ) {
17
38
description( "a template feature required by a function called was not present" )
18
39
display( "the template '{}' is missing the feature '{}'" , name, feature)
19
40
}
41
+ /// For when the given path wasn't found, a 404 should never be sensitive.
20
42
PageNotFound ( path: String ) {
21
43
description( "the requested page was not found" )
22
44
display( "the requested page at path '{}' was not found" , path)
23
45
}
24
- NoRenderOpts ( template_path: String ) {
25
- description( "a template had no rendering options for use at request-time" )
26
- display( "the template '{}' had no rendering options for use at request-time" , template_path)
27
- }
46
+ /// For when the user misconfigured their revalidation length, which should be caught at build time, and hence shouldn't be
47
+ /// sensitive.
28
48
InvalidDatetimeIntervalIndicator ( indicator: String ) {
29
49
description( "invalid indicator in timestring" )
30
50
display( "invalid indicator '{}' in timestring, must be one of: s, m, h, d, w, M, y" , indicator)
31
51
}
52
+ /// For when a template defined both build and request states when it can't amalgamate them sensibly, which indicates a misconfiguration.
53
+ /// Revealing the rendering strategies of a template in this way should never be sensitive. Due to the execution context, this
54
+ /// doesn't disclose the offending template.
32
55
BothStatesDefined {
33
56
description( "both build and request states were defined for a template when only one or fewer were expected" )
34
57
display( "both build and request states were defined for a template when only one or fewer were expected" )
35
58
}
36
- RenderFnFailed ( fn_name: String , template: String , err_str: String ) {
59
+ /// For when a render function failed. Only request-time functions can generate errors that will be transmitted over the network,
60
+ /// so **render functions must not disclose sensitive information in errors**. Other information shouldn't be sensitive.
61
+ RenderFnFailed ( fn_name: String , template: String , cause: ErrorCause , err_str: String ) {
37
62
description( "error while calling render function" )
38
- display( "an error occurred while calling render function '{}' on template '{}': '{}'" , fn_name, template, err_str)
63
+ display( "an error caused by '{:?}' occurred while calling render function '{}' on template '{}': '{}'" , cause , fn_name, template, err_str)
39
64
}
40
65
}
41
66
links {
@@ -48,3 +73,31 @@ error_chain! {
48
73
ChronoParse ( :: chrono:: ParseError ) ;
49
74
}
50
75
}
76
+
77
+ pub fn err_to_status_code ( err : & Error ) -> u16 {
78
+ match err. kind ( ) {
79
+ // Misconfiguration
80
+ ErrorKind :: TemplateFeatureNotEnabled ( _, _) => 500 ,
81
+ // Bad request
82
+ ErrorKind :: PageNotFound ( _) => 404 ,
83
+ // Misconfiguration
84
+ ErrorKind :: InvalidDatetimeIntervalIndicator ( _) => 500 ,
85
+ // Misconfiguration
86
+ ErrorKind :: BothStatesDefined => 500 ,
87
+ // Ambiguous, we'll rely on the given cause
88
+ ErrorKind :: RenderFnFailed ( _, _, cause, _) => match cause {
89
+ ErrorCause :: Client ( code) => code. unwrap_or ( 400 ) ,
90
+ ErrorCause :: Server ( code) => code. unwrap_or ( 500 ) ,
91
+ } ,
92
+ // We shouldn't be generating JS errors on the server...
93
+ ErrorKind :: JsErr ( _) => panic ! ( "function 'err_to_status_code' is only intended for server-side usage" ) ,
94
+ // These are nearly always server-induced
95
+ ErrorKind :: ConfigManager ( _) => 500 ,
96
+ ErrorKind :: Io ( _) => 500 ,
97
+ ErrorKind :: ChronoParse ( _) => 500 ,
98
+ // JSON errors can be caused by the client, but we don't have enough information
99
+ ErrorKind :: Json ( _) => 500 ,
100
+ // Any other errors go to a 500
101
+ _ => 500
102
+ }
103
+ }
0 commit comments