You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lua_mime.lua 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. --[[
  2. Copyright (c) 2019, Vsevolod Stakhov <vsevolod@highsecure.ru>
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ]]--
  13. --[[[
  14. -- @module lua_mime
  15. -- This module contains helper functions to modify mime parts
  16. --]]
  17. local rspamd_util = require "rspamd_util"
  18. local exports = {}
  19. local function newline(task)
  20. local t = task:get_newlines_type()
  21. if t == 'cr' then
  22. return '\r'
  23. elseif t == 'lf' then
  24. return '\n'
  25. end
  26. return '\r\n'
  27. end
  28. --[[[
  29. -- @function lua_mime.add_text_footer(task, html_footer, text_footer)
  30. -- Adds a footer to all text parts in a message. It returns a table with the following
  31. -- fields:
  32. -- * out: new content (body only)
  33. -- * need_rewrite_ct: boolean field that means if we must rewrite content type
  34. -- * new_ct: new content type (type => string, subtype => string)
  35. --]]
  36. exports.add_text_footer = function(task, html_footer, text_footer)
  37. local newline_s = newline(task)
  38. local res = {}
  39. local out = {}
  40. local text_parts = task:get_text_parts()
  41. if not (html_footer or text_footer) or not (text_parts and #text_parts > 0) then
  42. return false
  43. end
  44. local function do_append_footer(part, footer, is_multipart)
  45. local tp = part:get_text()
  46. local ct = 'text/plain'
  47. local cte = 'quoted-printable'
  48. if tp:is_html() then
  49. ct = 'text/html'
  50. end
  51. if part:get_cte() == '7bit' then
  52. cte = '7bit'
  53. end
  54. if is_multipart then
  55. out[#out + 1] = string.format('Content-Type: %s; charset=utf-8%s'..
  56. 'Content-Transfer-Encoding: %s',
  57. ct, newline_s, cte)
  58. out[#out + 1] = ''
  59. end
  60. local content = tostring(tp:get_content('raw_utf') or '')
  61. local double_nline = newline_s .. newline_s
  62. local nlen = #double_nline
  63. -- Hack, if part ends with 2 newline, then we append it after footer
  64. if content:sub(-(nlen), nlen + 1) == double_nline then
  65. content = string.format('%s%s',
  66. content:sub(-(#newline_s), #newline_s + 1), -- content without last newline
  67. footer)
  68. out[#out + 1] = {rspamd_util.encode_qp(content,
  69. 80, task:get_newlines_type()), true}
  70. out[#out + 1] = ''
  71. else
  72. content = content .. footer
  73. out[#out + 1] = {rspamd_util.encode_qp(content,
  74. 80, task:get_newlines_type()), true}
  75. out[#out + 1] = ''
  76. end
  77. end
  78. if html_footer or text_footer then
  79. -- We need to take extra care about content-type and cte
  80. local ct = task:get_header('Content-Type')
  81. if ct then
  82. ct = rspamd_util.parse_content_type(ct, task:get_mempool())
  83. end
  84. if ct then
  85. if ct.type and ct.type == 'text' then
  86. if ct.subtype then
  87. if html_footer and (ct.subtype == 'html' or ct.subtype == 'htm') then
  88. res.need_rewrite_ct = true
  89. elseif text_footer and ct.subtype == 'plain' then
  90. res.need_rewrite_ct = true
  91. end
  92. else
  93. if text_footer then
  94. res.need_rewrite_ct = true
  95. end
  96. end
  97. res.new_ct = ct
  98. end
  99. else
  100. if text_parts then
  101. if #text_parts == 1 then
  102. res.need_rewrite_ct = true
  103. res.new_ct = {
  104. type = 'text',
  105. subtype = 'plain'
  106. }
  107. elseif #text_parts > 1 then
  108. -- XXX: in fact, it cannot be
  109. res.new_ct = {
  110. type = 'multipart',
  111. subtype = 'mixed'
  112. }
  113. end
  114. end
  115. end
  116. end
  117. local boundaries = {}
  118. local cur_boundary
  119. for _,part in ipairs(task:get_parts()) do
  120. local boundary = part:get_boundary()
  121. if part:is_multipart() then
  122. if cur_boundary then
  123. out[#out + 1] = string.format('--%s',
  124. boundaries[#boundaries])
  125. end
  126. boundaries[#boundaries + 1] = boundary or '--XXX'
  127. cur_boundary = boundary
  128. local rh = part:get_raw_headers()
  129. if #rh > 0 then
  130. out[#out + 1] = {rh, true}
  131. end
  132. elseif part:is_message() then
  133. if boundary then
  134. if cur_boundary and boundary ~= cur_boundary then
  135. -- Need to close boundary
  136. out[#out + 1] = string.format('--%s--%s',
  137. boundaries[#boundaries], newline_s)
  138. table.remove(boundaries)
  139. cur_boundary = nil
  140. end
  141. out[#out + 1] = string.format('--%s',
  142. boundary)
  143. end
  144. out[#out + 1] = {part:get_raw_headers(), true}
  145. else
  146. local append_footer = false
  147. local skip_footer = part:is_attachment()
  148. local parent = part:get_parent()
  149. if parent then
  150. local t,st = parent:get_type()
  151. if t == 'multipart' and st == 'signed' then
  152. -- Do not modify signed parts
  153. skip_footer = true
  154. end
  155. end
  156. if text_footer and part:is_text() then
  157. local tp = part:get_text()
  158. if not tp:is_html() then
  159. append_footer = text_footer
  160. end
  161. end
  162. if html_footer and part:is_text() then
  163. local tp = part:get_text()
  164. if tp:is_html() then
  165. append_footer = html_footer
  166. end
  167. end
  168. if boundary then
  169. if cur_boundary and boundary ~= cur_boundary then
  170. -- Need to close boundary
  171. out[#out + 1] = string.format('--%s--%s',
  172. boundaries[#boundaries], newline_s)
  173. table.remove(boundaries)
  174. cur_boundary = boundary
  175. end
  176. out[#out + 1] = string.format('--%s',
  177. boundary)
  178. end
  179. if append_footer and not skip_footer then
  180. do_append_footer(part, append_footer,
  181. parent and parent:is_multipart())
  182. else
  183. out[#out + 1] = {part:get_raw_headers(), true}
  184. out[#out + 1] = {part:get_raw_content(), false}
  185. end
  186. end
  187. end
  188. -- Close remaining
  189. local b = table.remove(boundaries)
  190. while b do
  191. out[#out + 1] = string.format('--%s--', b)
  192. if #boundaries > 0 then
  193. out[#out + 1] = ''
  194. end
  195. b = table.remove(boundaries)
  196. end
  197. res.out = out
  198. return res
  199. end
  200. -- All mime extensions with corresponding content types
  201. exports.full_extensions_map = {
  202. {"323", "text/h323"},
  203. {"3g2", "video/3gpp2"},
  204. {"3gp", "video/3gpp"},
  205. {"3gp2", "video/3gpp2"},
  206. {"3gpp", "video/3gpp"},
  207. {"7z", "application/x-7z-compressed"},
  208. {"aa", "audio/audible"},
  209. {"AAC", "audio/aac"},
  210. {"aaf", "application/octet-stream"},
  211. {"aax", "audio/vnd.audible.aax"},
  212. {"ac3", "audio/ac3"},
  213. {"aca", "application/octet-stream"},
  214. {"accda", "application/msaccess.addin"},
  215. {"accdb", "application/msaccess"},
  216. {"accdc", "application/msaccess.cab"},
  217. {"accde", "application/msaccess"},
  218. {"accdr", "application/msaccess.runtime"},
  219. {"accdt", "application/msaccess"},
  220. {"accdw", "application/msaccess.webapplication"},
  221. {"accft", "application/msaccess.ftemplate"},
  222. {"acx", "application/internet-property-stream"},
  223. {"AddIn", "text/xml"},
  224. {"ade", "application/msaccess"},
  225. {"adobebridge", "application/x-bridge-url"},
  226. {"adp", "application/msaccess"},
  227. {"ADT", "audio/vnd.dlna.adts"},
  228. {"ADTS", "audio/aac"},
  229. {"afm", "application/octet-stream"},
  230. {"ai", "application/postscript"},
  231. {"aif", "audio/aiff"},
  232. {"aifc", "audio/aiff"},
  233. {"aiff", "audio/aiff"},
  234. {"air", "application/vnd.adobe.air-application-installer-package+zip"},
  235. {"amc", "application/mpeg"},
  236. {"anx", "application/annodex"},
  237. {"apk", "application/vnd.android.package-archive" },
  238. {"application", "application/x-ms-application"},
  239. {"art", "image/x-jg"},
  240. {"asa", "application/xml"},
  241. {"asax", "application/xml"},
  242. {"ascx", "application/xml"},
  243. {"asd", "application/octet-stream"},
  244. {"asf", "video/x-ms-asf"},
  245. {"ashx", "application/xml"},
  246. {"asi", "application/octet-stream"},
  247. {"asm", "text/plain"},
  248. {"asmx", "application/xml"},
  249. {"aspx", "application/xml"},
  250. {"asr", "video/x-ms-asf"},
  251. {"asx", "video/x-ms-asf"},
  252. {"atom", "application/atom+xml"},
  253. {"au", "audio/basic"},
  254. {"avi", "video/x-msvideo"},
  255. {"axa", "audio/annodex"},
  256. {"axs", "application/olescript"},
  257. {"axv", "video/annodex"},
  258. {"bas", "text/plain"},
  259. {"bcpio", "application/x-bcpio"},
  260. {"bin", "application/octet-stream"},
  261. {"bmp", "image/bmp"},
  262. {"c", "text/plain"},
  263. {"cab", "application/octet-stream"},
  264. {"caf", "audio/x-caf"},
  265. {"calx", "application/vnd.ms-office.calx"},
  266. {"cat", "application/vnd.ms-pki.seccat"},
  267. {"cc", "text/plain"},
  268. {"cd", "text/plain"},
  269. {"cdda", "audio/aiff"},
  270. {"cdf", "application/x-cdf"},
  271. {"cer", "application/x-x509-ca-cert"},
  272. {"cfg", "text/plain"},
  273. {"chm", "application/octet-stream"},
  274. {"class", "application/x-java-applet"},
  275. {"clp", "application/x-msclip"},
  276. {"cmd", "text/plain"},
  277. {"cmx", "image/x-cmx"},
  278. {"cnf", "text/plain"},
  279. {"cod", "image/cis-cod"},
  280. {"config", "application/xml"},
  281. {"contact", "text/x-ms-contact"},
  282. {"coverage", "application/xml"},
  283. {"cpio", "application/x-cpio"},
  284. {"cpp", "text/plain"},
  285. {"crd", "application/x-mscardfile"},
  286. {"crl", "application/pkix-crl"},
  287. {"crt", "application/x-x509-ca-cert"},
  288. {"cs", "text/plain"},
  289. {"csdproj", "text/plain"},
  290. {"csh", "application/x-csh"},
  291. {"csproj", "text/plain"},
  292. {"css", "text/css"},
  293. {"csv", {"application/vnd.ms-excel", "text/csv", "text/plain"}},
  294. {"cur", "application/octet-stream"},
  295. {"cxx", "text/plain"},
  296. {"dat", {"application/octet-stream", "application/ms-tnef"}},
  297. {"datasource", "application/xml"},
  298. {"dbproj", "text/plain"},
  299. {"dcr", "application/x-director"},
  300. {"def", "text/plain"},
  301. {"deploy", "application/octet-stream"},
  302. {"der", "application/x-x509-ca-cert"},
  303. {"dgml", "application/xml"},
  304. {"dib", "image/bmp"},
  305. {"dif", "video/x-dv"},
  306. {"dir", "application/x-director"},
  307. {"disco", "text/xml"},
  308. {"divx", "video/divx"},
  309. {"dll", "application/x-msdownload"},
  310. {"dll.config", "text/xml"},
  311. {"dlm", "text/dlm"},
  312. {"doc", "application/msword"},
  313. {"docm", "application/vnd.ms-word.document.macroEnabled.12"},
  314. {"docx", {
  315. "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  316. "application/msword",
  317. "application/vnd.ms-word.document.12",
  318. "application/octet-stream",
  319. }},
  320. {"dot", "application/msword"},
  321. {"dotm", "application/vnd.ms-word.template.macroEnabled.12"},
  322. {"dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template"},
  323. {"dsp", "application/octet-stream"},
  324. {"dsw", "text/plain"},
  325. {"dtd", "text/xml"},
  326. {"dtsConfig", "text/xml"},
  327. {"dv", "video/x-dv"},
  328. {"dvi", "application/x-dvi"},
  329. {"dwf", "drawing/x-dwf"},
  330. {"dwg", {"application/acad", "image/vnd.dwg"}},
  331. {"dwp", "application/octet-stream"},
  332. {"dxf", "application/x-dxf" },
  333. {"dxr", "application/x-director"},
  334. {"eml", "message/rfc822"},
  335. {"emz", "application/octet-stream"},
  336. {"eot", "application/vnd.ms-fontobject"},
  337. {"eps", "application/postscript"},
  338. {"etl", "application/etl"},
  339. {"etx", "text/x-setext"},
  340. {"evy", "application/envoy"},
  341. {"exe", {
  342. "application/x-dosexec",
  343. "application/x-msdownload",
  344. "application/x-executable",
  345. }},
  346. {"exe.config", "text/xml"},
  347. {"fdf", "application/vnd.fdf"},
  348. {"fif", "application/fractals"},
  349. {"filters", "application/xml"},
  350. {"fla", "application/octet-stream"},
  351. {"flac", "audio/flac"},
  352. {"flr", "x-world/x-vrml"},
  353. {"flv", "video/x-flv"},
  354. {"fsscript", "application/fsharp-script"},
  355. {"fsx", "application/fsharp-script"},
  356. {"generictest", "application/xml"},
  357. {"gif", "image/gif"},
  358. {"gpx", "application/gpx+xml"},
  359. {"group", "text/x-ms-group"},
  360. {"gsm", "audio/x-gsm"},
  361. {"gtar", "application/x-gtar"},
  362. {"gz", {"application/gzip", "application/x-gzip"}},
  363. {"h", "text/plain"},
  364. {"hdf", "application/x-hdf"},
  365. {"hdml", "text/x-hdml"},
  366. {"hhc", "application/x-oleobject"},
  367. {"hhk", "application/octet-stream"},
  368. {"hhp", "application/octet-stream"},
  369. {"hlp", "application/winhlp"},
  370. {"hpp", "text/plain"},
  371. {"hqx", "application/mac-binhex40"},
  372. {"hta", "application/hta"},
  373. {"htc", "text/x-component"},
  374. {"htm", "text/html"},
  375. {"html", "text/html"},
  376. {"htt", "text/webviewhtml"},
  377. {"hxa", "application/xml"},
  378. {"hxc", "application/xml"},
  379. {"hxd", "application/octet-stream"},
  380. {"hxe", "application/xml"},
  381. {"hxf", "application/xml"},
  382. {"hxh", "application/octet-stream"},
  383. {"hxi", "application/octet-stream"},
  384. {"hxk", "application/xml"},
  385. {"hxq", "application/octet-stream"},
  386. {"hxr", "application/octet-stream"},
  387. {"hxs", "application/octet-stream"},
  388. {"hxt", "text/html"},
  389. {"hxv", "application/xml"},
  390. {"hxw", "application/octet-stream"},
  391. {"hxx", "text/plain"},
  392. {"i", "text/plain"},
  393. {"ico", "image/x-icon"},
  394. {"ics", {"text/calendar", "application/octet-stream"}},
  395. {"idl", "text/plain"},
  396. {"ief", "image/ief"},
  397. {"iii", "application/x-iphone"},
  398. {"inc", "text/plain"},
  399. {"inf", "application/octet-stream"},
  400. {"ini", "text/plain"},
  401. {"inl", "text/plain"},
  402. {"ins", "application/x-internet-signup"},
  403. {"ipa", "application/x-itunes-ipa"},
  404. {"ipg", "application/x-itunes-ipg"},
  405. {"ipproj", "text/plain"},
  406. {"ipsw", "application/x-itunes-ipsw"},
  407. {"iqy", "text/x-ms-iqy"},
  408. {"isp", "application/x-internet-signup"},
  409. {"ite", "application/x-itunes-ite"},
  410. {"itlp", "application/x-itunes-itlp"},
  411. {"itms", "application/x-itunes-itms"},
  412. {"itpc", "application/x-itunes-itpc"},
  413. {"IVF", "video/x-ivf"},
  414. {"jar", "application/java-archive"},
  415. {"java", "application/octet-stream"},
  416. {"jck", "application/liquidmotion"},
  417. {"jcz", "application/liquidmotion"},
  418. {"jfif", "image/pjpeg"},
  419. {"jnlp", "application/x-java-jnlp-file"},
  420. {"jpb", "application/octet-stream"},
  421. {"jpe", {"image/jpeg", "image/pjpeg"}},
  422. {"jpeg", {"image/jpeg", "image/pjpeg"}},
  423. {"jpg", {"image/jpeg", "image/pjpeg"}},
  424. {"js", "application/javascript"},
  425. {"json", "application/json"},
  426. {"jsx", "text/jscript"},
  427. {"jsxbin", "text/plain"},
  428. {"latex", "application/x-latex"},
  429. {"library-ms", "application/windows-library+xml"},
  430. {"lit", "application/x-ms-reader"},
  431. {"loadtest", "application/xml"},
  432. {"lpk", "application/octet-stream"},
  433. {"lsf", "video/x-la-asf"},
  434. {"lst", "text/plain"},
  435. {"lsx", "video/x-la-asf"},
  436. {"lzh", "application/octet-stream"},
  437. {"m13", "application/x-msmediaview"},
  438. {"m14", "application/x-msmediaview"},
  439. {"m1v", "video/mpeg"},
  440. {"m2t", "video/vnd.dlna.mpeg-tts"},
  441. {"m2ts", "video/vnd.dlna.mpeg-tts"},
  442. {"m2v", "video/mpeg"},
  443. {"m3u", "audio/x-mpegurl"},
  444. {"m3u8", "audio/x-mpegurl"},
  445. {"m4a", {"audio/m4a", "audio/x-m4a"}},
  446. {"m4b", "audio/m4b"},
  447. {"m4p", "audio/m4p"},
  448. {"m4r", "audio/x-m4r"},
  449. {"m4v", "video/x-m4v"},
  450. {"mac", "image/x-macpaint"},
  451. {"mak", "text/plain"},
  452. {"man", "application/x-troff-man"},
  453. {"manifest", "application/x-ms-manifest"},
  454. {"map", "text/plain"},
  455. {"master", "application/xml"},
  456. {"mbox", "application/mbox"},
  457. {"mda", "application/msaccess"},
  458. {"mdb", "application/x-msaccess"},
  459. {"mde", "application/msaccess"},
  460. {"mdp", "application/octet-stream"},
  461. {"me", "application/x-troff-me"},
  462. {"mfp", "application/x-shockwave-flash"},
  463. {"mht", "message/rfc822"},
  464. {"mhtml", "message/rfc822"},
  465. {"mid", "audio/mid"},
  466. {"midi", "audio/mid"},
  467. {"mix", "application/octet-stream"},
  468. {"mk", "text/plain"},
  469. {"mmf", "application/x-smaf"},
  470. {"mno", "text/xml"},
  471. {"mny", "application/x-msmoney"},
  472. {"mod", "video/mpeg"},
  473. {"mov", "video/quicktime"},
  474. {"movie", "video/x-sgi-movie"},
  475. {"mp2", "video/mpeg"},
  476. {"mp2v", "video/mpeg"},
  477. {"mp3", "audio/mpeg"},
  478. {"mp4", "video/mp4"},
  479. {"mp4v", "video/mp4"},
  480. {"mpa", "video/mpeg"},
  481. {"mpe", "video/mpeg"},
  482. {"mpeg", "video/mpeg"},
  483. {"mpf", "application/vnd.ms-mediapackage"},
  484. {"mpg", "video/mpeg"},
  485. {"mpp", "application/vnd.ms-project"},
  486. {"mpv2", "video/mpeg"},
  487. {"mqv", "video/quicktime"},
  488. {"ms", "application/x-troff-ms"},
  489. {"msg", "application/vnd.ms-outlook"},
  490. {"msi", {"application/x-msi", "application/octet-stream"}},
  491. {"mso", "application/octet-stream"},
  492. {"mts", "video/vnd.dlna.mpeg-tts"},
  493. {"mtx", "application/xml"},
  494. {"mvb", "application/x-msmediaview"},
  495. {"mvc", "application/x-miva-compiled"},
  496. {"mxp", "application/x-mmxp"},
  497. {"nc", "application/x-netcdf"},
  498. {"nsc", "video/x-ms-asf"},
  499. {"nws", "message/rfc822"},
  500. {"ocx", "application/octet-stream"},
  501. {"oda", "application/oda"},
  502. {"odb", "application/vnd.oasis.opendocument.database"},
  503. {"odc", "application/vnd.oasis.opendocument.chart"},
  504. {"odf", "application/vnd.oasis.opendocument.formula"},
  505. {"odg", "application/vnd.oasis.opendocument.graphics"},
  506. {"odh", "text/plain"},
  507. {"odi", "application/vnd.oasis.opendocument.image"},
  508. {"odl", "text/plain"},
  509. {"odm", "application/vnd.oasis.opendocument.text-master"},
  510. {"odp", "application/vnd.oasis.opendocument.presentation"},
  511. {"ods", "application/vnd.oasis.opendocument.spreadsheet"},
  512. {"odt", "application/vnd.oasis.opendocument.text"},
  513. {"oga", "audio/ogg"},
  514. {"ogg", "audio/ogg"},
  515. {"ogv", "video/ogg"},
  516. {"ogx", "application/ogg"},
  517. {"one", "application/onenote"},
  518. {"onea", "application/onenote"},
  519. {"onepkg", "application/onenote"},
  520. {"onetmp", "application/onenote"},
  521. {"onetoc", "application/onenote"},
  522. {"onetoc2", "application/onenote"},
  523. {"opus", "audio/ogg"},
  524. {"orderedtest", "application/xml"},
  525. {"osdx", "application/opensearchdescription+xml"},
  526. {"otf", "application/font-sfnt"},
  527. {"otg", "application/vnd.oasis.opendocument.graphics-template"},
  528. {"oth", "application/vnd.oasis.opendocument.text-web"},
  529. {"otp", "application/vnd.oasis.opendocument.presentation-template"},
  530. {"ots", "application/vnd.oasis.opendocument.spreadsheet-template"},
  531. {"ott", "application/vnd.oasis.opendocument.text-template"},
  532. {"oxt", "application/vnd.openofficeorg.extension"},
  533. {"p10", "application/pkcs10"},
  534. {"p12", "application/x-pkcs12"},
  535. {"p7b", "application/x-pkcs7-certificates"},
  536. {"p7c", "application/pkcs7-mime"},
  537. {"p7m", "application/pkcs7-mime"},
  538. {"p7r", "application/x-pkcs7-certreqresp"},
  539. {"p7s", {"application/pkcs7-signature", "text/plain"}},
  540. {"pbm", "image/x-portable-bitmap"},
  541. {"pcast", "application/x-podcast"},
  542. {"pct", "image/pict"},
  543. {"pcx", "application/octet-stream"},
  544. {"pcz", "application/octet-stream"},
  545. {"pdf", "application/pdf"},
  546. {"pfb", "application/octet-stream"},
  547. {"pfm", "application/octet-stream"},
  548. {"pfx", "application/x-pkcs12"},
  549. {"pgm", "image/x-portable-graymap"},
  550. {"pic", "image/pict"},
  551. {"pict", "image/pict"},
  552. {"pkgdef", "text/plain"},
  553. {"pkgundef", "text/plain"},
  554. {"pko", "application/vnd.ms-pki.pko"},
  555. {"pls", "audio/scpls"},
  556. {"pma", "application/x-perfmon"},
  557. {"pmc", "application/x-perfmon"},
  558. {"pml", "application/x-perfmon"},
  559. {"pmr", "application/x-perfmon"},
  560. {"pmw", "application/x-perfmon"},
  561. {"png", "image/png"},
  562. {"pnm", "image/x-portable-anymap"},
  563. {"pnt", "image/x-macpaint"},
  564. {"pntg", "image/x-macpaint"},
  565. {"pnz", "image/png"},
  566. {"pot", "application/vnd.ms-powerpoint"},
  567. {"potm", "application/vnd.ms-powerpoint.template.macroEnabled.12"},
  568. {"potx", "application/vnd.openxmlformats-officedocument.presentationml.template"},
  569. {"ppa", "application/vnd.ms-powerpoint"},
  570. {"ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12"},
  571. {"ppm", "image/x-portable-pixmap"},
  572. {"pps", "application/vnd.ms-powerpoint"},
  573. {"ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12"},
  574. {"ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow"},
  575. {"ppt", "application/vnd.ms-powerpoint"},
  576. {"pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12"},
  577. {"pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
  578. {"prf", "application/pics-rules"},
  579. {"prm", "application/octet-stream"},
  580. {"prx", "application/octet-stream"},
  581. {"ps", "application/postscript"},
  582. {"psc1", "application/PowerShell"},
  583. {"psd", "application/octet-stream"},
  584. {"psess", "application/xml"},
  585. {"psm", "application/octet-stream"},
  586. {"psp", "application/octet-stream"},
  587. {"pst", "application/vnd.ms-outlook"},
  588. {"pub", "application/x-mspublisher"},
  589. {"pwz", "application/vnd.ms-powerpoint"},
  590. {"qht", "text/x-html-insertion"},
  591. {"qhtm", "text/x-html-insertion"},
  592. {"qt", "video/quicktime"},
  593. {"qti", "image/x-quicktime"},
  594. {"qtif", "image/x-quicktime"},
  595. {"qtl", "application/x-quicktimeplayer"},
  596. {"qxd", "application/octet-stream"},
  597. {"ra", "audio/x-pn-realaudio"},
  598. {"ram", "audio/x-pn-realaudio"},
  599. {"rar", {"application/x-rar-compressed", "application/x-rar", "application/octet-stream"}},
  600. {"ras", "image/x-cmu-raster"},
  601. {"rat", "application/rat-file"},
  602. {"rc", "text/plain"},
  603. {"rc2", "text/plain"},
  604. {"rct", "text/plain"},
  605. {"rdlc", "application/xml"},
  606. {"reg", "text/plain"},
  607. {"resx", "application/xml"},
  608. {"rf", "image/vnd.rn-realflash"},
  609. {"rgb", "image/x-rgb"},
  610. {"rgs", "text/plain"},
  611. {"rm", "application/vnd.rn-realmedia"},
  612. {"rmi", "audio/mid"},
  613. {"rmp", "application/vnd.rn-rn_music_package"},
  614. {"roff", "application/x-troff"},
  615. {"rpm", "audio/x-pn-realaudio-plugin"},
  616. {"rqy", "text/x-ms-rqy"},
  617. {"rtf", {"application/rtf","application/msword", "text/richtext", "text/rtf"}},
  618. {"rtx", "text/richtext"},
  619. {"rvt", "application/octet-stream" },
  620. {"ruleset", "application/xml"},
  621. {"s", "text/plain"},
  622. {"safariextz", "application/x-safari-safariextz"},
  623. {"scd", "application/x-msschedule"},
  624. {"scr", "text/plain"},
  625. {"sct", "text/scriptlet"},
  626. {"sd2", "audio/x-sd2"},
  627. {"sdp", "application/sdp"},
  628. {"sea", "application/octet-stream"},
  629. {"searchConnector-ms", "application/windows-search-connector+xml"},
  630. {"setpay", "application/set-payment-initiation"},
  631. {"setreg", "application/set-registration-initiation"},
  632. {"settings", "application/xml"},
  633. {"sgimb", "application/x-sgimb"},
  634. {"sgml", "text/sgml"},
  635. {"sh", "application/x-sh"},
  636. {"shar", "application/x-shar"},
  637. {"shtml", "text/html"},
  638. {"sit", "application/x-stuffit"},
  639. {"sitemap", "application/xml"},
  640. {"skin", "application/xml"},
  641. {"skp", "application/x-koan" },
  642. {"sldm", "application/vnd.ms-powerpoint.slide.macroEnabled.12"},
  643. {"sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide"},
  644. {"slk", "application/vnd.ms-excel"},
  645. {"sln", "text/plain"},
  646. {"slupkg-ms", "application/x-ms-license"},
  647. {"smd", "audio/x-smd"},
  648. {"smi", "application/octet-stream"},
  649. {"smx", "audio/x-smd"},
  650. {"smz", "audio/x-smd"},
  651. {"snd", "audio/basic"},
  652. {"snippet", "application/xml"},
  653. {"snp", "application/octet-stream"},
  654. {"sol", "text/plain"},
  655. {"sor", "text/plain"},
  656. {"spc", "application/x-pkcs7-certificates"},
  657. {"spl", "application/futuresplash"},
  658. {"spx", "audio/ogg"},
  659. {"src", "application/x-wais-source"},
  660. {"srf", "text/plain"},
  661. {"SSISDeploymentManifest", "text/xml"},
  662. {"ssm", "application/streamingmedia"},
  663. {"sst", "application/vnd.ms-pki.certstore"},
  664. {"stl", "application/vnd.ms-pki.stl"},
  665. {"sv4cpio", "application/x-sv4cpio"},
  666. {"sv4crc", "application/x-sv4crc"},
  667. {"svc", "application/xml"},
  668. {"svg", "image/svg+xml"},
  669. {"swf", "application/x-shockwave-flash"},
  670. {"step", "application/step"},
  671. {"stp", "application/step"},
  672. {"t", "application/x-troff"},
  673. {"tar", "application/x-tar"},
  674. {"tcl", "application/x-tcl"},
  675. {"testrunconfig", "application/xml"},
  676. {"testsettings", "application/xml"},
  677. {"tex", "application/x-tex"},
  678. {"texi", "application/x-texinfo"},
  679. {"texinfo", "application/x-texinfo"},
  680. {"tgz", "application/x-compressed"},
  681. {"thmx", "application/vnd.ms-officetheme"},
  682. {"thn", "application/octet-stream"},
  683. {"tif", {"image/tiff", "application/octet-stream"}},
  684. {"tiff", "image/tiff"},
  685. {"tlh", "text/plain"},
  686. {"tli", "text/plain"},
  687. {"toc", "application/octet-stream"},
  688. {"tr", "application/x-troff"},
  689. {"trm", "application/x-msterminal"},
  690. {"trx", "application/xml"},
  691. {"ts", "video/vnd.dlna.mpeg-tts"},
  692. {"tsv", "text/tab-separated-values"},
  693. {"ttf", "application/font-sfnt"},
  694. {"tts", "video/vnd.dlna.mpeg-tts"},
  695. {"txt", "text/plain"},
  696. {"u32", "application/octet-stream"},
  697. {"uls", "text/iuls"},
  698. {"user", "text/plain"},
  699. {"ustar", "application/x-ustar"},
  700. {"vb", "text/plain"},
  701. {"vbdproj", "text/plain"},
  702. {"vbk", "video/mpeg"},
  703. {"vbproj", "text/plain"},
  704. {"vbs", "text/vbscript"},
  705. {"vcf", {"text/x-vcard", "text/vcard"}},
  706. {"vcproj", "application/xml"},
  707. {"vcs", "text/plain"},
  708. {"vcxproj", "application/xml"},
  709. {"vddproj", "text/plain"},
  710. {"vdp", "text/plain"},
  711. {"vdproj", "text/plain"},
  712. {"vdx", "application/vnd.ms-visio.viewer"},
  713. {"vml", "text/xml"},
  714. {"vscontent", "application/xml"},
  715. {"vsct", "text/xml"},
  716. {"vsd", "application/vnd.visio"},
  717. {"vsi", "application/ms-vsi"},
  718. {"vsix", "application/vsix"},
  719. {"vsixlangpack", "text/xml"},
  720. {"vsixmanifest", "text/xml"},
  721. {"vsmdi", "application/xml"},
  722. {"vspscc", "text/plain"},
  723. {"vss", "application/vnd.visio"},
  724. {"vsscc", "text/plain"},
  725. {"vssettings", "text/xml"},
  726. {"vssscc", "text/plain"},
  727. {"vst", "application/vnd.visio"},
  728. {"vstemplate", "text/xml"},
  729. {"vsto", "application/x-ms-vsto"},
  730. {"vsw", "application/vnd.visio"},
  731. {"vsx", "application/vnd.visio"},
  732. {"vtx", "application/vnd.visio"},
  733. {"wav", "audio/wav"},
  734. {"wave", "audio/wav"},
  735. {"wax", "audio/x-ms-wax"},
  736. {"wbk", "application/msword"},
  737. {"wbmp", "image/vnd.wap.wbmp"},
  738. {"wcm", "application/vnd.ms-works"},
  739. {"wdb", "application/vnd.ms-works"},
  740. {"wdp", "image/vnd.ms-photo"},
  741. {"webarchive", "application/x-safari-webarchive"},
  742. {"webm", "video/webm"},
  743. {"webp", "image/webp"},
  744. {"webtest", "application/xml"},
  745. {"wiq", "application/xml"},
  746. {"wiz", "application/msword"},
  747. {"wks", "application/vnd.ms-works"},
  748. {"WLMP", "application/wlmoviemaker"},
  749. {"wlpginstall", "application/x-wlpg-detect"},
  750. {"wlpginstall3", "application/x-wlpg3-detect"},
  751. {"wm", "video/x-ms-wm"},
  752. {"wma", "audio/x-ms-wma"},
  753. {"wmd", "application/x-ms-wmd"},
  754. {"wmf", "application/x-msmetafile"},
  755. {"wml", "text/vnd.wap.wml"},
  756. {"wmlc", "application/vnd.wap.wmlc"},
  757. {"wmls", "text/vnd.wap.wmlscript"},
  758. {"wmlsc", "application/vnd.wap.wmlscriptc"},
  759. {"wmp", "video/x-ms-wmp"},
  760. {"wmv", "video/x-ms-wmv"},
  761. {"wmx", "video/x-ms-wmx"},
  762. {"wmz", "application/x-ms-wmz"},
  763. {"woff", "application/font-woff"},
  764. {"wpl", "application/vnd.ms-wpl"},
  765. {"wps", "application/vnd.ms-works"},
  766. {"wri", "application/x-mswrite"},
  767. {"wrl", "x-world/x-vrml"},
  768. {"wrz", "x-world/x-vrml"},
  769. {"wsc", "text/scriptlet"},
  770. {"wsdl", "text/xml"},
  771. {"wvx", "video/x-ms-wvx"},
  772. {"x", "application/directx"},
  773. {"xaf", "x-world/x-vrml"},
  774. {"xaml", "application/xaml+xml"},
  775. {"xap", "application/x-silverlight-app"},
  776. {"xbap", "application/x-ms-xbap"},
  777. {"xbm", "image/x-xbitmap"},
  778. {"xdr", "text/plain"},
  779. {"xht", "application/xhtml+xml"},
  780. {"xhtml", "application/xhtml+xml"},
  781. {"xla", "application/vnd.ms-excel"},
  782. {"xlam", "application/vnd.ms-excel.addin.macroEnabled.12"},
  783. {"xlc", "application/vnd.ms-excel"},
  784. {"xld", "application/vnd.ms-excel"},
  785. {"xlk", "application/vnd.ms-excel"},
  786. {"xll", "application/vnd.ms-excel"},
  787. {"xlm", "application/vnd.ms-excel"},
  788. {"xls", {
  789. "application/excel",
  790. "application/vnd.ms-excel",
  791. "application/vnd.ms-office",
  792. "application/x-excel",
  793. "application/octet-stream"
  794. }},
  795. {"xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12"},
  796. {"xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12"},
  797. {"xlsx", {
  798. "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  799. "application/vnd.ms-excel.12",
  800. "application/octet-stream"
  801. }},
  802. {"xlt", "application/vnd.ms-excel"},
  803. {"xltm", "application/vnd.ms-excel.template.macroEnabled.12"},
  804. {"xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"},
  805. {"xlw", "application/vnd.ms-excel"},
  806. {"xml", {"application/xml", "text/xml", "application/octet-stream"}},
  807. {"xmp", "application/octet-stream" },
  808. {"xmta", "application/xml"},
  809. {"xof", "x-world/x-vrml"},
  810. {"XOML", "text/plain"},
  811. {"xpm", "image/x-xpixmap"},
  812. {"xps", "application/vnd.ms-xpsdocument"},
  813. {"xrm-ms", "text/xml"},
  814. {"xsc", "application/xml"},
  815. {"xsd", "text/xml"},
  816. {"xsf", "text/xml"},
  817. {"xsl", "text/xml"},
  818. {"xslt", "text/xml"},
  819. {"xsn", "application/octet-stream"},
  820. {"xss", "application/xml"},
  821. {"xspf", "application/xspf+xml"},
  822. {"xtp", "application/octet-stream"},
  823. {"xwd", "image/x-xwindowdump"},
  824. {"z", "application/x-compress"},
  825. {"zip", {
  826. "application/zip",
  827. "application/x-zip-compressed",
  828. "application/octet-stream"
  829. }},
  830. {"zlib", "application/zlib"},
  831. }
  832. -- Used to match extension by content type
  833. exports.reversed_extensions_map = {}
  834. if #exports.reversed_extensions_map == 0 then
  835. -- Fill reversed extensions map
  836. for _,pair in ipairs(exports.full_extensions_map) do
  837. local ext, ct = pair[1], pair[2]
  838. if type(ct) == 'table' then
  839. for _,rct in ipairs(ct) do
  840. exports.reversed_extensions_map[rct] = ext
  841. end
  842. else
  843. exports.reversed_extensions_map[ct] = ext
  844. end
  845. end
  846. end
  847. return exports