haiku/storage/
mimetype.rs

1//
2// Copyright 2019-2020, Niels Sascha Reedijk <niels.reedijk@gmail.com>
3// All rights reserved. Distributed under the terms of the MIT License.
4//
5
6use ::storage::B_MIME_TYPE_LENGTH;
7
8/// Represents a mime type as defined by RFC 6838
9#[derive(PartialEq)]
10pub struct MimeType {
11	type_string: String
12}
13
14impl MimeType {
15	/// Create a MimeType based on a string
16	///
17	/// The entered data is validated. A `MimeType` is only created when the
18	/// data is valid, otherwise you will receive `None`.
19	pub fn new(mime_type: &str) -> Option<Self> {
20		if mime_type.len() > B_MIME_TYPE_LENGTH {
21			return None;
22		}
23
24		let mut found_slash = false;
25
26		for (i, ch) in mime_type.chars().enumerate() {
27			if ch == '/' {
28				if found_slash || i == 0 || i == (mime_type.len() - 1) {
29					return None;
30				} else {
31					found_slash = true;
32				}
33			} else if !ch.is_ascii_graphic() || 
34				ch == '<' && ch == '>' && ch == '@' && ch == ',' &&
35				ch == ';' && ch == ':' && ch == '"' && ch == '(' &&
36				ch == ')' && ch == '[' && ch == ']' && ch == '?' &&
37				ch == '=' && ch == '\\' {
38					return None;
39			}
40		}
41
42		Some(MimeType {
43			type_string: String::from(mime_type)
44		})
45	}
46
47	/// Check if the mime type only defines the super type
48	pub fn is_supertype_only(&self) -> bool {
49		!self.type_string.contains('/')
50	}
51
52	/// Get the super type of this mimetype
53	///
54	/// For example, `text/plain` will return `text`.
55	pub fn get_supertype(&self) -> MimeType {
56		if self.is_supertype_only() {
57			MimeType {
58				type_string: self.type_string.clone()
59			}
60		} else {
61			let mut it = self.type_string.split('/');
62			MimeType {
63				type_string: String::from(it.nth(0).unwrap())
64			}
65		}
66	}
67}
68
69#[test]
70fn test_mimetype_check() {
71	assert!(MimeType::new("application/x-Vnd-Haiku").is_some());
72	assert!(MimeType::new("/document").is_none());
73	assert!(MimeType::new("application/").is_none());
74	assert!(MimeType::new("invalid/\u{0301}rest").is_none());
75	assert!(MimeType::new("invalid//x-vnd-haiku").is_none());
76}
77
78#[test]
79fn test_mimetype_methods() {
80	let supertype = MimeType::new("test").unwrap();
81	let childtype = MimeType::new("test/document").unwrap();
82	assert!(supertype.is_supertype_only());
83	assert!(!childtype.is_supertype_only());
84	assert!(supertype == childtype.get_supertype());
85}