@@ -95,36 +95,27 @@ impl std::fmt::Display for FilenameError {
9595impl std:: error:: Error for FilenameError { }
9696
9797/// A validated MIME content-type for form parts.
98- ///
99- /// Content types are validated to have a valid `type/subtype` format.
10098#[ derive( Debug , Clone , PartialEq , Eq ) ]
10199pub struct ContentType ( String ) ;
102100
103101impl ContentType {
104102 /// Create a new content-type, validating the format.
105- ///
106- /// # Errors
107- /// Returns an error if the content-type doesn't follow the `type/subtype` format.
108103 pub fn new ( content_type : impl Into < String > ) -> Result < Self , ContentTypeError > {
109104 let content_type = content_type. into ( ) ;
110- // Basic validation: must contain exactly one '/' and non-empty parts
111- let parts: Vec < & str > = content_type. split ( '/' ) . collect ( ) ;
112- if parts. len ( ) != 2 {
105+ let Some ( ( type_part, rest) ) = content_type. split_once ( '/' ) else {
113106 return Err ( ContentTypeError :: InvalidFormat ) ;
114- }
115- // Get type and subtype (subtype may have parameters like charset)
116- let type_part = parts[ 0 ] . trim ( ) ;
117- let subtype_part = parts[ 1 ] . split ( ';' ) . next ( ) . unwrap_or ( "" ) . trim ( ) ;
118- if type_part. is_empty ( ) || subtype_part. is_empty ( ) {
107+ } ;
108+ let subtype_part = rest. split_once ( ';' ) . map_or ( rest, |( s, _) | s) ;
109+ if type_part. trim ( ) . is_empty ( )
110+ || subtype_part. trim ( ) . is_empty ( )
111+ || subtype_part. contains ( '/' )
112+ {
119113 return Err ( ContentTypeError :: InvalidFormat ) ;
120114 }
121115 Ok ( Self ( content_type) )
122116 }
123117
124118 /// Create a content-type without validation.
125- ///
126- /// # Safety
127- /// The caller must ensure the content-type is valid.
128119 pub fn new_unchecked ( content_type : impl Into < String > ) -> Self {
129120 Self ( content_type. into ( ) )
130121 }
@@ -139,34 +130,19 @@ impl ContentType {
139130 self . 0
140131 }
141132
142- /// Common content type: `application/json`
143- pub fn json ( ) -> Self {
144- Self ( "application/json" . to_string ( ) )
145- }
146-
147- /// Common content type: `application/octet-stream`
148- pub fn octet_stream ( ) -> Self {
149- Self ( "application/octet-stream" . to_string ( ) )
150- }
151-
152- /// Common content type: `text/plain`
153- pub fn text_plain ( ) -> Self {
154- Self ( "text/plain" . to_string ( ) )
155- }
156-
157- /// Common content type: `application/pdf`
158- pub fn pdf ( ) -> Self {
159- Self ( "application/pdf" . to_string ( ) )
133+ /// Create `application/{subtype}` content type.
134+ pub fn application ( subtype : impl AsRef < str > ) -> Self {
135+ Self ( format ! ( "application/{}" , subtype. as_ref( ) ) )
160136 }
161137
162- /// Common content type: `image/png`
163- pub fn png ( ) -> Self {
164- Self ( "image/png" . to_string ( ) )
138+ /// Create `text/{subtype}` content type.
139+ pub fn text ( subtype : impl AsRef < str > ) -> Self {
140+ Self ( format ! ( "text/{}" , subtype . as_ref ( ) ) )
165141 }
166142
167- /// Common content type: `image/jpeg`
168- pub fn jpeg ( ) -> Self {
169- Self ( "image/jpeg" . to_string ( ) )
143+ /// Create `image/{subtype}` content type.
144+ pub fn image ( subtype : impl AsRef < str > ) -> Self {
145+ Self ( format ! ( "image/{}" , subtype . as_ref ( ) ) )
170146 }
171147}
172148
@@ -286,7 +262,7 @@ impl TextFormPart {
286262 pub fn json < T : serde:: Serialize > ( value : & T ) -> Result < Self , serde_json:: Error > {
287263 Ok ( Self {
288264 value : serde_json:: to_string ( value) ?,
289- content_type : Some ( ContentType :: json ( ) ) ,
265+ content_type : Some ( ContentType :: application ( "json" ) ) ,
290266 } )
291267 }
292268
0 commit comments