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