@@ -4,9 +4,12 @@ use crate::{metadata::ContentType, CatalystSignedDocument};
44
55/// `content-type` field validation rule
66#[ derive( Debug ) ]
7- pub ( crate ) struct ContentTypeRule {
8- /// expected `content-type` field
9- pub ( crate ) exp : ContentType ,
7+ pub ( crate ) enum ContentTypeRule {
8+ Specified {
9+ /// expected `content-type` field
10+ exp : ContentType ,
11+ } ,
12+ NotSpecified ,
1013}
1114
1215impl ContentTypeRule {
@@ -23,14 +26,16 @@ impl ContentTypeRule {
2326 ) ;
2427 return Ok ( false ) ;
2528 } ;
26- if content_type != self . exp {
27- doc. report ( ) . invalid_value (
28- "content-type" ,
29- content_type. to_string ( ) . as_str ( ) ,
30- self . exp . to_string ( ) . as_str ( ) ,
31- "Invalid Document content-type value" ,
32- ) ;
33- return Ok ( false ) ;
29+ if let Self :: Specified { exp } = & self {
30+ if content_type != * exp {
31+ doc. report ( ) . invalid_value (
32+ "content-type" ,
33+ content_type. to_string ( ) . as_str ( ) ,
34+ exp. to_string ( ) . as_str ( ) ,
35+ "Invalid Document content-type value" ,
36+ ) ;
37+ return Ok ( false ) ;
38+ }
3439 }
3540 let Ok ( content) = doc. decoded_content ( ) else {
3641 doc. report ( ) . functional_validation (
@@ -57,34 +62,37 @@ impl ContentTypeRule {
5762 & self ,
5863 content : & [ u8 ] ,
5964 ) -> anyhow:: Result < ( ) > {
60- match self . exp {
61- ContentType :: Json => {
62- if let Err ( e) = serde_json:: from_slice :: < & serde_json:: value:: RawValue > ( content) {
63- anyhow:: bail!( "Invalid {} content: {e}" , self . exp)
64- }
65- } ,
66- ContentType :: Cbor => {
67- let mut decoder = minicbor:: Decoder :: new ( content) ;
68-
69- decoder. skip ( ) ?;
70-
71- if decoder. position ( ) != content. len ( ) {
72- anyhow:: bail!( "Unused bytes remain in the input after decoding" )
73- }
74- } ,
75- ContentType :: Cddl
76- | ContentType :: JsonSchema
77- | ContentType :: Css
78- | ContentType :: CssHandlebars
79- | ContentType :: Html
80- | ContentType :: HtmlHandlebars
81- | ContentType :: Markdown
82- | ContentType :: MarkdownHandlebars
83- | ContentType :: Plain
84- | ContentType :: PlainHandlebars => {
85- // TODO: not implemented yet
86- anyhow:: bail!( "`{}` is valid but unavailable yet" , self . exp)
87- } ,
65+ if let Self :: Specified { exp } = self {
66+ match exp {
67+ ContentType :: Json => {
68+ if let Err ( e) = serde_json:: from_slice :: < & serde_json:: value:: RawValue > ( content)
69+ {
70+ anyhow:: bail!( "Invalid {} content: {e}" , exp)
71+ }
72+ } ,
73+ ContentType :: Cbor => {
74+ let mut decoder = minicbor:: Decoder :: new ( content) ;
75+
76+ decoder. skip ( ) ?;
77+
78+ if decoder. position ( ) != content. len ( ) {
79+ anyhow:: bail!( "Unused bytes remain in the input after decoding" )
80+ }
81+ } ,
82+ ContentType :: Cddl
83+ | ContentType :: JsonSchema
84+ | ContentType :: Css
85+ | ContentType :: CssHandlebars
86+ | ContentType :: Html
87+ | ContentType :: HtmlHandlebars
88+ | ContentType :: Markdown
89+ | ContentType :: MarkdownHandlebars
90+ | ContentType :: Plain
91+ | ContentType :: PlainHandlebars => {
92+ // TODO: not implemented yet
93+ anyhow:: bail!( "`{}` is valid but unavailable yet" , exp)
94+ } ,
95+ }
8896 }
8997 Ok ( ( ) )
9098 }
@@ -103,12 +111,11 @@ mod tests {
103111 enc. map ( 1 ) . unwrap ( ) . u8 ( 1 ) . unwrap ( ) . u8 ( 2 ) . unwrap ( ) ;
104112 buf. push ( 0xFF ) ; // extra byte
105113
106- let cbor_rule = ContentTypeRule {
107- exp : ContentType :: Cbor ,
108- } ;
114+ let content_type = ContentType :: Cbor ;
115+ let cbor_rule = ContentTypeRule :: Specified { exp : content_type } ;
109116
110117 let doc = Builder :: new ( )
111- . with_metadata_field ( SupportedField :: ContentType ( cbor_rule . exp ) )
118+ . with_metadata_field ( SupportedField :: ContentType ( content_type ) )
112119 . with_content ( buf)
113120 . build ( ) ;
114121
@@ -120,12 +127,11 @@ mod tests {
120127 // 0xa2 means a map with 2 key-value pairs, but we only give 1 key
121128 let invalid_bytes = & [ 0xA2 , 0x01 ] ;
122129
123- let cbor_rule = ContentTypeRule {
124- exp : ContentType :: Cbor ,
125- } ;
130+ let content_type = ContentType :: Cbor ;
131+ let cbor_rule = ContentTypeRule :: Specified { exp : content_type } ;
126132
127133 let doc = Builder :: new ( )
128- . with_metadata_field ( SupportedField :: ContentType ( cbor_rule . exp ) )
134+ . with_metadata_field ( SupportedField :: ContentType ( content_type ) )
129135 . with_content ( invalid_bytes. into ( ) )
130136 . build ( ) ;
131137
@@ -134,66 +140,66 @@ mod tests {
134140
135141 #[ tokio:: test]
136142 async fn content_type_cbor_rule_test ( ) {
137- let cbor_rule = ContentTypeRule {
138- exp : ContentType :: Cbor ,
139- } ;
143+ let content_type = ContentType :: Cbor ;
144+ let cbor_rule = ContentTypeRule :: Specified { exp : content_type } ;
140145
141146 // with json bytes
142147 let doc = Builder :: new ( )
143- . with_metadata_field ( SupportedField :: ContentType ( cbor_rule . exp ) )
148+ . with_metadata_field ( SupportedField :: ContentType ( content_type ) )
144149 . with_content ( serde_json:: to_vec ( & serde_json:: json!( { } ) ) . unwrap ( ) )
145150 . build ( ) ;
146151 assert ! ( matches!( cbor_rule. check( & doc) . await , Ok ( false ) ) ) ;
147152
148153 // with cbor bytes
149154 let doc = Builder :: new ( )
150- . with_metadata_field ( SupportedField :: ContentType ( cbor_rule . exp ) )
155+ . with_metadata_field ( SupportedField :: ContentType ( content_type ) )
151156 . with_content ( minicbor:: to_vec ( minicbor:: data:: Token :: Null ) . unwrap ( ) )
152157 . build ( ) ;
153158 assert ! ( matches!( cbor_rule. check( & doc) . await , Ok ( true ) ) ) ;
154159
155160 // without content
156161 let doc = Builder :: new ( )
157- . with_metadata_field ( SupportedField :: ContentType ( cbor_rule . exp ) )
162+ . with_metadata_field ( SupportedField :: ContentType ( content_type ) )
158163 . build ( ) ;
159164 assert ! ( matches!( cbor_rule. check( & doc) . await , Ok ( false ) ) ) ;
160165
161166 // with empty content
162167 let doc = Builder :: new ( )
163- . with_metadata_field ( SupportedField :: ContentType ( cbor_rule . exp ) )
168+ . with_metadata_field ( SupportedField :: ContentType ( content_type ) )
164169 . build ( ) ;
165170 assert ! ( matches!( cbor_rule. check( & doc) . await , Ok ( false ) ) ) ;
166171 }
167172
168173 #[ tokio:: test]
169174 async fn content_type_json_rule_test ( ) {
170- let json_rule = ContentTypeRule {
175+ let content_type = ContentType :: Json ;
176+ let json_rule = ContentTypeRule :: Specified {
171177 exp : ContentType :: Json ,
172178 } ;
173179
174180 // with json bytes
175181 let doc = Builder :: new ( )
176- . with_metadata_field ( SupportedField :: ContentType ( json_rule . exp ) )
182+ . with_metadata_field ( SupportedField :: ContentType ( content_type ) )
177183 . with_content ( serde_json:: to_vec ( & serde_json:: json!( { } ) ) . unwrap ( ) )
178184 . build ( ) ;
179185 assert ! ( matches!( json_rule. check( & doc) . await , Ok ( true ) ) ) ;
180186
181187 // with cbor bytes
182188 let doc = Builder :: new ( )
183- . with_metadata_field ( SupportedField :: ContentType ( json_rule . exp ) )
189+ . with_metadata_field ( SupportedField :: ContentType ( content_type ) )
184190 . with_content ( minicbor:: to_vec ( minicbor:: data:: Token :: Null ) . unwrap ( ) )
185191 . build ( ) ;
186192 assert ! ( matches!( json_rule. check( & doc) . await , Ok ( false ) ) ) ;
187193
188194 // without content
189195 let doc = Builder :: new ( )
190- . with_metadata_field ( SupportedField :: ContentType ( json_rule . exp ) )
196+ . with_metadata_field ( SupportedField :: ContentType ( content_type ) )
191197 . build ( ) ;
192198 assert ! ( matches!( json_rule. check( & doc) . await , Ok ( false ) ) ) ;
193199
194200 // with empty content
195201 let doc = Builder :: new ( )
196- . with_metadata_field ( SupportedField :: ContentType ( json_rule . exp ) )
202+ . with_metadata_field ( SupportedField :: ContentType ( content_type ) )
197203 . build ( ) ;
198204 assert ! ( matches!( json_rule. check( & doc) . await , Ok ( false ) ) ) ;
199205
0 commit comments