1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.util.MimeType;
13 
14 import hunt.util.AcceptMimeType;
15 
16 import hunt.collection;
17 import hunt.logging;
18 import hunt.io.ByteBuffer;
19 import hunt.io.BufferUtils;
20 
21 import hunt.text.Charset;
22 import hunt.text.Common;
23 import hunt.Exceptions;
24 import hunt.util.ObjectUtils;
25 
26 import std.algorithm;
27 import std.array;
28 import std.container.array;
29 import std.conv;
30 import std.file;
31 import std.path;
32 import std.range;
33 import std.stdio;
34 import std.string;
35 import std.uni;
36 
37 class MimeType {
38     /**
39 	 * A string equivalent of {@link MimeType#ALL}.
40 	 */
41 	enum string ALL_VALUE = "*/*";
42 
43 	/**
44 	 * A string equivalent of {@link MimeType#APPLICATION_JSON}.
45 	 */
46 	enum string APPLICATION_JSON_VALUE = "application/json";    
47     
48 	/**
49 	 * A string equivalent of {@link MimeType#APPLICATION_OCTET_STREAM}.
50 	 */
51 	enum string APPLICATION_OCTET_STREAM_VALUE = "application/octet-stream";
52 
53 	/**
54 	 * A string equivalent of {@link MimeType#APPLICATION_XML}.
55 	 */
56 	enum string APPLICATION_XML_VALUE = "application/xml";
57     
58     /** 
59      * 
60      */
61 	enum string APPLICATION_X_WWW_FORM_VALUE = "application/x-www-form-urlencoded";
62 
63 	/**
64 	 * A string equivalent of {@link MimeType#IMAGE_GIF}.
65 	 */
66 	enum string IMAGE_GIF_VALUE = "image/gif";
67 
68 	/**
69 	 * A string equivalent of {@link MimeType#IMAGE_JPEG}.
70 	 */
71 	enum string IMAGE_JPEG_VALUE = "image/jpeg";
72 
73 	/**
74 	 * A string equivalent of {@link MimeType#IMAGE_PNG}.
75 	 */
76 	enum string IMAGE_PNG_VALUE = "image/png";
77 
78 	/**
79 	 * A string equivalent of {@link MimeType#TEXT_HTML}.
80 	 */
81 	enum string TEXT_HTML_VALUE = "text/html";
82 
83 	/**
84 	 * A string equivalent of {@link MimeType#TEXT_PLAIN}.
85 	 */
86 	enum string TEXT_PLAIN_VALUE = "text/plain";
87 
88 	/**
89 	 * A string equivalent of {@link MimeType#TEXT_XML}.
90 	 */
91 	enum string TEXT_XML_VALUE = "text/xml";   
92 
93     /** 
94      * 
95      */
96 	enum string TEXT_JSON_VALUE = "text/json"; 
97 
98     /**
99      * The "mixed" subtype of "multipart" is intended for use when the body parts are independent and
100      * need to be bundled in a particular order. Any "multipart" subtypes that an implementation does
101      * not recognize must be treated as being of subtype "mixed".
102      */
103     enum string MULTIPART_MIXED_VALUE = "multipart/mixed";
104 
105     /**
106      * The "multipart/alternative" type is syntactically identical to "multipart/mixed", but the
107      * semantics are different. In particular, each of the body parts is an "alternative" version of
108      * the same information.
109      */
110     enum string MULTIPART_ALTERNATIVE_VALUE = "multipart/alternative";
111 
112     /**
113      * This type is syntactically identical to "multipart/mixed", but the semantics are different. In
114      * particular, in a digest, the default {@code Content-Type} value for a body part is changed from
115      * "text/plain" to "message/rfc822".
116      */
117     enum string MULTIPART_DIGEST_VALUE = "multipart/digest";
118 
119     /**
120      * This type is syntactically identical to "multipart/mixed", but the semantics are different. In
121      * particular, in a parallel entity, the order of body parts is not significant.
122      */
123     enum string MULTIPART_PARALLEL_VALUE = "multipart/parallel";
124 
125     /**
126      * The media-type multipart/form-data follows the rules of all multipart MIME data streams as
127      * outlined in RFC 2046. In forms, there are a series of fields to be supplied by the user who
128      * fills out the form. Each field has a name. Within a given form, the names are unique.
129      */
130     enum string MULTIPART_FORM_VALUE = "multipart/form-data";         
131 
132 	/**
133 	 * Public constant mime type that includes all media ranges (i.e. "*/*").
134 	 */
135 	__gshared MimeType ALL;
136     __gshared MimeType APPLICATION_JSON;
137     __gshared MimeType APPLICATION_XML;
138     __gshared MimeType APPLICATION_JSON_8859_1;
139     __gshared MimeType APPLICATION_JSON_UTF_8;
140     __gshared MimeType APPLICATION_OCTET_STREAM;
141     __gshared MimeType APPLICATION_X_WWW_FORM;
142 
143     __gshared MimeType FORM_ENCODED;
144 
145     __gshared MimeType IMAGE_GIF;
146     __gshared MimeType IMAGE_JPEG;
147     __gshared MimeType IMAGE_PNG;
148 
149     __gshared MimeType MESSAGE_HTTP;
150     __gshared MimeType MULTIPART_BYTERANGES;
151 
152     __gshared MimeType TEXT_HTML;
153     __gshared MimeType TEXT_PLAIN;
154     __gshared MimeType TEXT_XML;
155     __gshared MimeType TEXT_JSON;
156 
157     __gshared MimeType TEXT_HTML_8859_1;
158     __gshared MimeType TEXT_HTML_UTF_8;
159 
160     __gshared MimeType TEXT_PLAIN_8859_1;
161     __gshared MimeType TEXT_PLAIN_UTF_8;
162 
163     __gshared MimeType TEXT_XML_8859_1;
164     __gshared MimeType TEXT_XML_UTF_8;
165 
166     __gshared MimeType TEXT_JSON_8859_1;
167     __gshared MimeType TEXT_JSON_UTF_8;
168 
169     __gshared MimeType MULTIPART_MIXED;
170     __gshared MimeType MULTIPART_ALTERNATIVE;
171     __gshared MimeType MULTIPART_DIGEST;
172     __gshared MimeType MULTIPART_PARALLEL;
173     __gshared MimeType MULTIPART_FORM;
174 
175     __gshared Array!MimeType values;
176 
177     shared static this() {
178 
179         ALL = new MimeType(ALL_VALUE);
180         
181         APPLICATION_JSON = new MimeType(APPLICATION_JSON_VALUE, StandardCharsets.UTF_8);
182         APPLICATION_JSON_8859_1 = new MimeType("application/json;charset=iso-8859-1", APPLICATION_JSON);
183         APPLICATION_JSON_UTF_8 = new MimeType("application/json;charset=utf-8", APPLICATION_JSON);
184         APPLICATION_OCTET_STREAM = new MimeType(APPLICATION_OCTET_STREAM_VALUE);
185         APPLICATION_XML = new MimeType(APPLICATION_XML_VALUE, StandardCharsets.UTF_8);
186         APPLICATION_X_WWW_FORM = new MimeType(APPLICATION_X_WWW_FORM_VALUE);
187 
188         IMAGE_GIF = new MimeType(IMAGE_GIF_VALUE);
189         IMAGE_JPEG = new MimeType(IMAGE_JPEG_VALUE);
190         IMAGE_PNG = new MimeType(IMAGE_PNG_VALUE);
191 
192         MESSAGE_HTTP = new MimeType("message/http");
193         MULTIPART_BYTERANGES = new MimeType("multipart/byteranges");
194 
195         TEXT_HTML = new MimeType(TEXT_HTML_VALUE);
196         TEXT_PLAIN = new MimeType(TEXT_PLAIN_VALUE);
197         TEXT_XML = new MimeType(TEXT_XML_VALUE);
198         TEXT_JSON = new MimeType(TEXT_JSON_VALUE, StandardCharsets.UTF_8);
199 
200         TEXT_HTML_8859_1 = new MimeType("text/html;charset=iso-8859-1", TEXT_HTML);
201         TEXT_HTML_UTF_8 = new MimeType("text/html;charset=utf-8", TEXT_HTML);
202 
203         TEXT_PLAIN_8859_1 = new MimeType("text/plain;charset=iso-8859-1", TEXT_PLAIN);
204         TEXT_PLAIN_UTF_8 = new MimeType("text/plain;charset=utf-8", TEXT_PLAIN);
205 
206         TEXT_XML_8859_1 = new MimeType("text/xml;charset=iso-8859-1", TEXT_XML);
207         TEXT_XML_UTF_8 = new MimeType("text/xml;charset=utf-8", TEXT_XML);
208 
209         TEXT_JSON_8859_1 = new MimeType("text/json;charset=iso-8859-1", TEXT_JSON);
210         TEXT_JSON_UTF_8 = new MimeType("text/json;charset=utf-8", TEXT_JSON);
211 
212         MULTIPART_MIXED = new MimeType(MULTIPART_MIXED_VALUE);
213         MULTIPART_ALTERNATIVE = new MimeType(MULTIPART_ALTERNATIVE_VALUE);
214         MULTIPART_DIGEST = new MimeType(MULTIPART_DIGEST_VALUE);
215         MULTIPART_PARALLEL = new MimeType(MULTIPART_PARALLEL_VALUE);
216         MULTIPART_FORM = new MimeType(MULTIPART_FORM_VALUE);
217 
218         values.insertBack(ALL);
219         values.insertBack(APPLICATION_JSON);
220         values.insertBack(APPLICATION_XML);
221         values.insertBack(APPLICATION_JSON_8859_1);
222         values.insertBack(APPLICATION_JSON_UTF_8);
223         values.insertBack(APPLICATION_OCTET_STREAM);
224         values.insertBack(APPLICATION_X_WWW_FORM);
225         
226         values.insertBack(IMAGE_GIF);
227         values.insertBack(IMAGE_JPEG);
228         values.insertBack(IMAGE_PNG);
229 
230         values.insertBack(MESSAGE_HTTP);
231         values.insertBack(MULTIPART_BYTERANGES);
232         
233         values.insertBack(TEXT_HTML);
234         values.insertBack(TEXT_PLAIN);
235         values.insertBack(TEXT_XML);
236         values.insertBack(TEXT_JSON);
237         values.insertBack(TEXT_HTML_8859_1);
238         values.insertBack(TEXT_HTML_UTF_8);
239         values.insertBack(TEXT_PLAIN_8859_1);
240         values.insertBack(TEXT_PLAIN_UTF_8);
241         values.insertBack(TEXT_XML_8859_1);
242         values.insertBack(TEXT_XML_UTF_8);
243         values.insertBack(TEXT_JSON_8859_1);
244         values.insertBack(TEXT_JSON_UTF_8);
245         
246         values.insertBack(MULTIPART_MIXED);
247         values.insertBack(MULTIPART_ALTERNATIVE);
248         values.insertBack(MULTIPART_DIGEST);
249         values.insertBack(MULTIPART_PARALLEL);
250         values.insertBack(MULTIPART_FORM);
251     }
252 
253 
254     private string _string;
255     private MimeType _base;
256     private ByteBuffer _buffer;
257     private Charset _charset;
258     private string _charsetString;
259     private bool _assumedCharset;
260 
261     this(string s) {
262         _string = s;
263         _buffer = BufferUtils.toBuffer(s);
264         _base = this;
265         
266         ptrdiff_t i = s.indexOf(";charset=");
267         // _charset = Charset.forName(s.substring(i + 9));
268         if(i == -1)
269             i = s.indexOf("; charset=");
270 
271         if(i == -1) {
272             _charsetString = null;
273             _assumedCharset = true;
274         } else {
275             _charsetString = s[i + 9 .. $].toLower();
276             _assumedCharset = false;
277         }
278         _charset = _charsetString;
279     }
280 
281     this(string s, MimeType base) {
282         this(s);
283         _base = base;
284     }
285 
286     this(string s, string charset) {
287         _string = s;
288         _base = this;
289         _buffer = BufferUtils.toBuffer(s);
290         _charset = charset;
291         _charsetString = charset.toLower();
292         _assumedCharset = false;
293     }
294 
295     // ByteBuffer asBuffer() {
296     //     return _buffer.asReadOnlyBuffer();
297     // }
298 
299     Charset getCharset() {
300         return _charset;
301     }
302 
303     string getCharsetString() {
304         return _charsetString;
305     }
306 
307     bool isSame(string s) {
308         return _string.equalsIgnoreCase(s);
309     }
310 
311     string asString() {
312         return _string;
313     }
314 
315     override
316     string toString() {
317         return _string;
318     }
319 
320     bool isCharsetAssumed() {
321         return _assumedCharset;
322     }
323 
324     MimeType getBaseType() {
325         return _base;
326     }
327 }
328