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