| 1 |
-------------------------------------------------------------------------------- |
|---|
| 2 |
-- Title: MIME.lua |
|---|
| 3 |
-- Description: Like a square peg in a round hole |
|---|
| 4 |
-- Author: Raphaël Szwarc http://alt.textdrive.com/lua/ |
|---|
| 5 |
-- Creation Date: January 30, 2007 |
|---|
| 6 |
-- Legal: Copyright (C) 2007 Raphaël Szwarc |
|---|
| 7 |
-- Under the terms of the MIT License |
|---|
| 8 |
-- http://www.opensource.org/licenses/mit-license.html |
|---|
| 9 |
-------------------------------------------------------------------------------- |
|---|
| 10 |
|
|---|
| 11 |
-- import dependencies |
|---|
| 12 |
local table = require( 'table' ) |
|---|
| 13 |
|
|---|
| 14 |
local getmetatable = getmetatable |
|---|
| 15 |
local ipairs = ipairs |
|---|
| 16 |
local module = module |
|---|
| 17 |
local pcall = pcall |
|---|
| 18 |
local require = require |
|---|
| 19 |
local setmetatable = setmetatable |
|---|
| 20 |
local tostring = tostring |
|---|
| 21 |
local type = type |
|---|
| 22 |
local unpack = unpack |
|---|
| 23 |
|
|---|
| 24 |
-------------------------------------------------------------------------------- |
|---|
| 25 |
-- MIMEType |
|---|
| 26 |
-------------------------------------------------------------------------------- |
|---|
| 27 |
|
|---|
| 28 |
module( 'MIMEType' ) |
|---|
| 29 |
_VERSION = '1.0' |
|---|
| 30 |
|
|---|
| 31 |
a = 'application/x-archive' |
|---|
| 32 |
ag = 'application/x-applixgraphics' |
|---|
| 33 |
aiff = 'audio/x-aiff' |
|---|
| 34 |
arj = 'application/x-arj' |
|---|
| 35 |
arts = 'application/x-artsbuilder' |
|---|
| 36 |
as = 'application/x-applixspread' |
|---|
| 37 |
au = 'audio/basic' |
|---|
| 38 |
avi = 'video/x-msvideo' |
|---|
| 39 |
aw = 'application/x-applixword' |
|---|
| 40 |
bak = 'application/x-trash' |
|---|
| 41 |
bib = 'text/x-bibtex' |
|---|
| 42 |
bmp = 'image/x-bmp' |
|---|
| 43 |
bz = 'application/x-bzip' |
|---|
| 44 |
bz2 = 'application/x-bzip2' |
|---|
| 45 |
c = 'text/x-csrc' |
|---|
| 46 |
cc = 'text/x-c++src' |
|---|
| 47 |
cgm = 'image/cgm' |
|---|
| 48 |
class = 'application/x-java' |
|---|
| 49 |
cls = 'text/x-tex' |
|---|
| 50 |
cpio = 'application/x-cpio' |
|---|
| 51 |
cpp = 'text/x-c++src' |
|---|
| 52 |
csh = 'application/x-shellscript' |
|---|
| 53 |
css = 'text/css' |
|---|
| 54 |
cssl = 'text/css' |
|---|
| 55 |
cxx = 'text/x-c++src' |
|---|
| 56 |
deb = 'application/x-debian-package' |
|---|
| 57 |
desktop = 'application/x-desktop' |
|---|
| 58 |
diff = 'text/x-diff' |
|---|
| 59 |
dvi = 'application/x-dvi' |
|---|
| 60 |
eps = 'image/x-eps' |
|---|
| 61 |
epsf = 'image/x-eps' |
|---|
| 62 |
epsi = 'image/x-eps' |
|---|
| 63 |
exe = 'application/x-executable' |
|---|
| 64 |
flc = 'video/x-flic' |
|---|
| 65 |
fli = 'video/x-flic' |
|---|
| 66 |
g3 = 'image/fax-g3' |
|---|
| 67 |
gif = 'image/gif' |
|---|
| 68 |
gsf = 'application/x-font' |
|---|
| 69 |
gz = 'application/x-gzip' |
|---|
| 70 |
h = 'text/x-chdr' |
|---|
| 71 |
hh = 'text/x-c++hdr' |
|---|
| 72 |
htm = 'text/html' |
|---|
| 73 |
html = 'text/html' |
|---|
| 74 |
ico = 'image/x-ico' |
|---|
| 75 |
ics = 'text/calendar' |
|---|
| 76 |
it = 'audio/x-mod' |
|---|
| 77 |
jar = 'application/x-jar' |
|---|
| 78 |
java = 'text/x-java' |
|---|
| 79 |
jng = 'image/x-jng' |
|---|
| 80 |
jpg = 'image/jpeg' |
|---|
| 81 |
kar = 'audio/x-karaoke' |
|---|
| 82 |
kdelnk = 'application/x-desktop' |
|---|
| 83 |
ksysv = 'application/x-ksysv' |
|---|
| 84 |
ksysv_log = 'text/x-ksysv-log' |
|---|
| 85 |
ktheme = 'application/x-ktheme' |
|---|
| 86 |
lha = 'application/x-lha' |
|---|
| 87 |
log = 'text/x-log' |
|---|
| 88 |
ltx = 'text/x-tex' |
|---|
| 89 |
lua = 'text/plain' |
|---|
| 90 |
lyx = 'text/x-lyx' |
|---|
| 91 |
lzh = 'application/x-lha' |
|---|
| 92 |
lzo = 'application/x-lzop' |
|---|
| 93 |
m15 = 'audio/x-mod' |
|---|
| 94 |
m3u = 'audio/x-mpegurl' |
|---|
| 95 |
man = 'application/x-troff-man' |
|---|
| 96 |
mid = 'audio/x-midi' |
|---|
| 97 |
mng = 'video/x-mng' |
|---|
| 98 |
moc = 'text/x-moc' |
|---|
| 99 |
mod = 'audio/x-mod' |
|---|
| 100 |
moov = 'video/quicktime' |
|---|
| 101 |
mov = 'video/quicktime' |
|---|
| 102 |
mp3 = 'audio/x-mp3' |
|---|
| 103 |
mpeg = 'video/mpeg' |
|---|
| 104 |
mpg = 'video/mpeg' |
|---|
| 105 |
mtm = 'audio/x-mod' |
|---|
| 106 |
o = 'application/x-object' |
|---|
| 107 |
ogg = 'application/x-ogg' |
|---|
| 108 |
old = 'application/x-trash' |
|---|
| 109 |
p = 'text/x-pascal' |
|---|
| 110 |
pas = 'text/x-pascal' |
|---|
| 111 |
patch = 'text/x-diff' |
|---|
| 112 |
pcd = 'image/x-photo-cd' |
|---|
| 113 |
pdf = 'application/pdf' |
|---|
| 114 |
perl = 'application/x-perl' |
|---|
| 115 |
pfa = 'application/x-font' |
|---|
| 116 |
pfb = 'application/x-font' |
|---|
| 117 |
php = 'text/x-php' |
|---|
| 118 |
php3 = 'text/x-php' |
|---|
| 119 |
pl = 'text/x-perl' |
|---|
| 120 |
pls = 'audio/x-scpls' |
|---|
| 121 |
pm = 'text/x-perl' |
|---|
| 122 |
png = 'image/png' |
|---|
| 123 |
po = 'application/x-gettext' |
|---|
| 124 |
pot = 'application/x-gettext' |
|---|
| 125 |
ppt = 'application/mspowerpoint' |
|---|
| 126 |
ppz = 'application/mspowerpoint' |
|---|
| 127 |
ps = 'application/postscript' |
|---|
| 128 |
py = 'application/x-python' |
|---|
| 129 |
pyc = 'application/x-python-bytecode' |
|---|
| 130 |
qt = 'video/quicktime' |
|---|
| 131 |
qtvr = 'video/quicktime' |
|---|
| 132 |
ra = 'audio/x-pn-realaudio' |
|---|
| 133 |
ram = 'audio/x-pn-realaudio' |
|---|
| 134 |
rar = 'application/x-rar' |
|---|
| 135 |
rdf = 'text/rdf' |
|---|
| 136 |
rm = 'audio/x-pn-realaudio' |
|---|
| 137 |
roff = 'application/x-troff' |
|---|
| 138 |
rpm = 'application/x-rpm' |
|---|
| 139 |
rss = 'text/rss' |
|---|
| 140 |
rtf = 'text/rtf' |
|---|
| 141 |
s3m = 'audio/x-mod' |
|---|
| 142 |
sgml = 'text/sgml' |
|---|
| 143 |
sgrd = 'application/x-ksysguard' |
|---|
| 144 |
sh = 'application/x-shellscript' |
|---|
| 145 |
shell = 'application/x-konsole' |
|---|
| 146 |
shtml = 'text/x-ssi-html' |
|---|
| 147 |
sik = 'application/x-trash' |
|---|
| 148 |
smi = 'audio/x-pn-realaudio' |
|---|
| 149 |
smil = 'application/smil' |
|---|
| 150 |
snd = 'audio/basic' |
|---|
| 151 |
stm = 'audio/x-mod' |
|---|
| 152 |
sty = 'text/x-tex' |
|---|
| 153 |
swf = 'application/x-shockwave-flash' |
|---|
| 154 |
tar = 'application/x-tar' |
|---|
| 155 |
tcl = 'text/x-tcl' |
|---|
| 156 |
tex = 'text/x-tex' |
|---|
| 157 |
tgz = 'application/x-tgz' |
|---|
| 158 |
tif = 'image/tiff' |
|---|
| 159 |
tiff = 'image/tiff' |
|---|
| 160 |
tk = 'text/x-tcl' |
|---|
| 161 |
tr = 'application/x-troff' |
|---|
| 162 |
ts = 'application/x-linguist' |
|---|
| 163 |
ttf = 'application/x-truetype-font' |
|---|
| 164 |
txt = 'text/plain' |
|---|
| 165 |
tzo = 'application/x-tzo' |
|---|
| 166 |
ui = 'application/x-designer' |
|---|
| 167 |
ult = 'audio/x-mod' |
|---|
| 168 |
uni = 'audio/x-mod' |
|---|
| 169 |
vcs = 'text/x-vcalendar' |
|---|
| 170 |
vct = 'text/x-vcard' |
|---|
| 171 |
war = 'application/x-webarchive' |
|---|
| 172 |
wav = 'audio/x-wav' |
|---|
| 173 |
wpd = 'application/wordperfect' |
|---|
| 174 |
xbm = 'image/x-xbm' |
|---|
| 175 |
xcf = 'image/x-xcf-gimp' |
|---|
| 176 |
xlc = 'application/msexcel' |
|---|
| 177 |
xll = 'application/msexcel' |
|---|
| 178 |
xls = 'application/msexcel' |
|---|
| 179 |
xlw = 'application/msexcel' |
|---|
| 180 |
xm = 'audio/x-mod' |
|---|
| 181 |
xml = 'text/xml' |
|---|
| 182 |
xpm = 'image/x-xpm' |
|---|
| 183 |
z = 'application/x-compress' |
|---|
| 184 |
zip = 'application/x-zip' |
|---|
| 185 |
zoo = 'application/x-zoo' |
|---|
| 186 |
|
|---|
| 187 |
-------------------------------------------------------------------------------- |
|---|
| 188 |
-- MIMEMultipartFormData |
|---|
| 189 |
-------------------------------------------------------------------------------- |
|---|
| 190 |
|
|---|
| 191 |
module( 'MIMEMultipartFormData' ) |
|---|
| 192 |
_VERSION = '1.0' |
|---|
| 193 |
|
|---|
| 194 |
local self = setmetatable( _M, {} ) |
|---|
| 195 |
local meta = getmetatable( self ) |
|---|
| 196 |
|
|---|
| 197 |
local function ReadFormData( aMultipart ) |
|---|
| 198 |
local aFormData = {} |
|---|
| 199 |
|
|---|
| 200 |
aFormData.boundary = aMultipart.boundary |
|---|
| 201 |
|
|---|
| 202 |
for anIndex, aPart in ipairs( aMultipart ) do |
|---|
| 203 |
local aHeader = aPart.header[ 'content-disposition' ] or {} |
|---|
| 204 |
local aDisposition = ( aHeader.value or '' ):lower() |
|---|
| 205 |
|
|---|
| 206 |
if aDisposition == 'form-data' then |
|---|
| 207 |
local aParameter = aHeader.parameter or {} |
|---|
| 208 |
local aKey = aParameter[ 'name' ] |
|---|
| 209 |
|
|---|
| 210 |
if aKey then |
|---|
| 211 |
local aKey = aKey:lower() |
|---|
| 212 |
local aValue = aPart.content |
|---|
| 213 |
local aFileName = aParameter[ 'filename' ] |
|---|
| 214 |
local aForm = { key = aKey, value = aValue, filename = aFileName } |
|---|
| 215 |
|
|---|
| 216 |
aFormData[ #aFormData + 1 ] = aForm |
|---|
| 217 |
end |
|---|
| 218 |
end |
|---|
| 219 |
end |
|---|
| 220 |
|
|---|
| 221 |
return aFormData |
|---|
| 222 |
end |
|---|
| 223 |
|
|---|
| 224 |
local function NewFormData( aValue, aHeader ) |
|---|
| 225 |
local MIMEMultipart = require( 'MIMEMultipart' ) |
|---|
| 226 |
local aFormData = nil |
|---|
| 227 |
|
|---|
| 228 |
if type( aValue ) == 'table' then |
|---|
| 229 |
aFormData = ReadFormData( MIMEMultipart( WriteFormData( aValue ), aHeader ) ) |
|---|
| 230 |
else |
|---|
| 231 |
aFormData = ReadFormData( MIMEMultipart( aValue, aHeader ) ) |
|---|
| 232 |
end |
|---|
| 233 |
|
|---|
| 234 |
setmetatable( aFormData, self ) |
|---|
| 235 |
|
|---|
| 236 |
return aFormData |
|---|
| 237 |
end |
|---|
| 238 |
|
|---|
| 239 |
function meta:__call( aValue, aHeader ) |
|---|
| 240 |
return NewFormData( aValue, aHeader ) |
|---|
| 241 |
end |
|---|
| 242 |
|
|---|
| 243 |
function self:__index( aKey ) |
|---|
| 244 |
if aKey then |
|---|
| 245 |
local someForms = {} |
|---|
| 246 |
|
|---|
| 247 |
aKey = aKey:lower() |
|---|
| 248 |
|
|---|
| 249 |
for anIndex, aForm in ipairs( self ) do |
|---|
| 250 |
if aKey == aForm.key then |
|---|
| 251 |
someForms[ #someForms + 1 ] = aForm |
|---|
| 252 |
end |
|---|
| 253 |
end |
|---|
| 254 |
|
|---|
| 255 |
return unpack( someForms ) |
|---|
| 256 |
end |
|---|
| 257 |
|
|---|
| 258 |
return nil |
|---|
| 259 |
end |
|---|
| 260 |
|
|---|
| 261 |
function self:__concat( aValue ) |
|---|
| 262 |
return tostring( self ) .. tostring( aValue ) |
|---|
| 263 |
end |
|---|
| 264 |
|
|---|
| 265 |
function self:__tostring() |
|---|
| 266 |
return 'WriteFormData' --WriteFormData( self ) |
|---|
| 267 |
end |
|---|
| 268 |
|
|---|
| 269 |
-------------------------------------------------------------------------------- |
|---|
| 270 |
-- MIMEMultipart |
|---|
| 271 |
-------------------------------------------------------------------------------- |
|---|
| 272 |
|
|---|
| 273 |
module( 'MIMEMultipart' ) |
|---|
| 274 |
_VERSION = '1.0' |
|---|
| 275 |
|
|---|
| 276 |
local self = setmetatable( _M, {} ) |
|---|
| 277 |
local meta = getmetatable( self ) |
|---|
| 278 |
|
|---|
| 279 |
local function ReadBoundary( aHeader ) |
|---|
| 280 |
local aType = aHeader[ 'content-type' ] or {} |
|---|
| 281 |
local aParameter = aType.parameter or {} |
|---|
| 282 |
local aBoundary = aParameter[ 'boundary' ] |
|---|
| 283 |
|
|---|
| 284 |
return aBoundary |
|---|
| 285 |
end |
|---|
| 286 |
|
|---|
| 287 |
local function ReadMultipart( aValue, aBoundary ) |
|---|
| 288 |
local MIME = require( 'MIME' ) |
|---|
| 289 |
local aMultipart = { boundary = aBoundary } |
|---|
| 290 |
local aBoundary = '--' .. aBoundary |
|---|
| 291 |
local aLength = aBoundary:len() |
|---|
| 292 |
local aStart = 1 |
|---|
| 293 |
local anEnd = nil |
|---|
| 294 |
|
|---|
| 295 |
while true do |
|---|
| 296 |
aStart = aValue:find( aBoundary, aStart, true ) |
|---|
| 297 |
|
|---|
| 298 |
if aStart then |
|---|
| 299 |
aStart = aStart + aLength |
|---|
| 300 |
anEnd = aValue:find( aBoundary, aStart, true ) |
|---|
| 301 |
|
|---|
| 302 |
if anEnd then |
|---|
| 303 |
aStart = aValue:find( '\r\n', aStart, true ) + 2 |
|---|
| 304 |
|
|---|
| 305 |
aMultipart[ #aMultipart + 1 ] = MIME( aValue:sub( aStart, anEnd - 3 ) ) |
|---|
| 306 |
else |
|---|
| 307 |
break |
|---|
| 308 |
end |
|---|
| 309 |
else |
|---|
| 310 |
break |
|---|
| 311 |
end |
|---|
| 312 |
end |
|---|
| 313 |
|
|---|
| 314 |
return aMultipart |
|---|
| 315 |
end |
|---|
| 316 |
|
|---|
| 317 |
local function NewMultipart( aValue, aHeader ) |
|---|
| 318 |
local aMultipart = nil |
|---|
| 319 |
|
|---|
| 320 |
if type( aValue ) == 'table' then |
|---|
| 321 |
aMultipart = ReadMultipart( WriteMultipart( aValue ), aValue.boundary ) |
|---|
| 322 |
else |
|---|
| 323 |
aMultipart = ReadMultipart( tostring( aValue or '' ), ReadBoundary( aHeader ) ) |
|---|
| 324 |
end |
|---|
| 325 |
|
|---|
| 326 |
setmetatable( aMultipart, self ) |
|---|
| 327 |
|
|---|
| 328 |
return aMultipart |
|---|
| 329 |
end |
|---|
| 330 |
|
|---|
| 331 |
function meta:__call( aValue, aHeader ) |
|---|
| 332 |
return NewMultipart( aValue, aHeader ) |
|---|
| 333 |
end |
|---|
| 334 |
|
|---|
| 335 |
function self:__concat( aValue ) |
|---|
| 336 |
return tostring( self ) .. tostring( aValue ) |
|---|
| 337 |
end |
|---|
| 338 |
|
|---|
| 339 |
function self:__tostring() |
|---|
| 340 |
return 'WriteMultipart' --WriteMultipart( self ) |
|---|
| 341 |
end |
|---|
| 342 |
|
|---|
| 343 |
-------------------------------------------------------------------------------- |
|---|
| 344 |
-- MIMEHeader |
|---|
| 345 |
-------------------------------------------------------------------------------- |
|---|
| 346 |
|
|---|
| 347 |
module( 'MIMEHeader' ) |
|---|
| 348 |
_VERSION = '1.0' |
|---|
| 349 |
|
|---|
| 350 |
local self = setmetatable( _M, {} ) |
|---|
| 351 |
local meta = getmetatable( self ) |
|---|
| 352 |
|
|---|
| 353 |
local function Trim( aString ) |
|---|
| 354 |
if aString ~= nil then |
|---|
| 355 |
aString = aString:gsub( '^[%c%s]*', '' ) |
|---|
| 356 |
aString = aString:gsub( '[%s%c]*$', '' ) |
|---|
| 357 |
end |
|---|
| 358 |
|
|---|
| 359 |
return aString |
|---|
| 360 |
end |
|---|
| 361 |
|
|---|
| 362 |
local function ReadKey( aValue ) |
|---|
| 363 |
local anIndex = aValue:find( ':', 1, true ) or ( aValue:len() + 1 ) |
|---|
| 364 |
local aKey = aValue:sub( 1, anIndex - 1 ):lower() |
|---|
| 365 |
|
|---|
| 366 |
return Trim( aKey ) |
|---|
| 367 |
end |
|---|
| 368 |
|
|---|
| 369 |
local function ReadValue( aValue ) |
|---|
| 370 |
local aValue = aValue .. ';' |
|---|
| 371 |
local anIndex = aValue:find( ':', 1, true ) or 1 |
|---|
| 372 |
local anotherIndex = aValue:find( ';%s*([^%s=]+)%s*=(.-);' ) or aValue:len() |
|---|
| 373 |
local aValue = aValue:sub( anIndex + 1, anotherIndex - 1 ) |
|---|
| 374 |
|
|---|
| 375 |
return Trim( aValue ) |
|---|
| 376 |
end |
|---|
| 377 |
|
|---|
| 378 |
local function ReadParameter( aValue ) |
|---|
| 379 |
local aValue = aValue .. ';' |
|---|
| 380 |
local aParameter = {} |
|---|
| 381 |
|
|---|
| 382 |
for aKey, aValue in aValue:gmatch( '%s*([^%s=]+)%s*=(.-);' ) do |
|---|
| 383 |
if aValue:sub( 1, 1 ) == '"' then |
|---|
| 384 |
aValue = aValue:sub( 2, aValue:len() - 1 ) |
|---|
| 385 |
end |
|---|
| 386 |
|
|---|
| 387 |
aParameter[ Trim( aKey ):lower() ] = Trim( aValue ) |
|---|
| 388 |
end |
|---|
| 389 |
|
|---|
| 390 |
return aParameter |
|---|
| 391 |
end |
|---|
| 392 |
|
|---|
| 393 |
local function ReadHeader( aValue ) |
|---|
| 394 |
local aHeaderKey = ReadKey( aValue ) |
|---|
| 395 |
local aHeaderValue = ReadValue( aValue ) |
|---|
| 396 |
local aHeaderParameter = ReadParameter( aValue ) |
|---|
| 397 |
local aHeader = { key = aHeaderKey, value = aHeaderValue, parameter = aHeaderParameter } |
|---|
| 398 |
|
|---|
| 399 |
return aHeader |
|---|
| 400 |
end |
|---|
| 401 |
|
|---|
| 402 |
local function NewHeader( aValue ) |
|---|
| 403 |
local aHeader = nil |
|---|
| 404 |
|
|---|
| 405 |
if type( aValue ) == 'table' then |
|---|
| 406 |
aHeader = ReadHeader( WriteHeader( aValue ) ) |
|---|
| 407 |
else |
|---|
| 408 |
aHeader = ReadHeader( tostring( aValue or '' ) ) |
|---|
| 409 |
end |
|---|
| 410 |
|
|---|
| 411 |
setmetatable( aHeader, self ) |
|---|
| 412 |
|
|---|
| 413 |
return aHeader |
|---|
| 414 |
end |
|---|
| 415 |
|
|---|
| 416 |
function meta:__call( aValue ) |
|---|
| 417 |
return NewHeader( aValue ) |
|---|
| 418 |
end |
|---|
| 419 |
|
|---|
| 420 |
function self:__concat( aValue ) |
|---|
| 421 |
return tostring( self ) .. tostring( aValue ) |
|---|
| 422 |
end |
|---|
| 423 |
|
|---|
| 424 |
function self:__eq( aValue ) |
|---|
| 425 |
return tostring( self ) == tostring( aValue ) |
|---|
| 426 |
end |
|---|
| 427 |
|
|---|
| 428 |
function self:__lt( aValue ) |
|---|
| 429 |
return tostring( self ) < tostring( aValue ) |
|---|
| 430 |
end |
|---|
| 431 |
|
|---|
| 432 |
function self:__tostring() |
|---|
| 433 |
return 'WriteHeader' --WriteHeader( self ) |
|---|
| 434 |
end |
|---|
| 435 |
|
|---|
| 436 |
-------------------------------------------------------------------------------- |
|---|
| 437 |
-- MIMEHeaders |
|---|
| 438 |
-------------------------------------------------------------------------------- |
|---|
| 439 |
|
|---|
| 440 |
module( 'MIMEHeaders' ) |
|---|
| 441 |
_VERSION = '1.0' |
|---|
| 442 |
|
|---|
| 443 |
local self = setmetatable( _M, {} ) |
|---|
| 444 |
local meta = getmetatable( self ) |
|---|
| 445 |
|
|---|
| 446 |
local function ReadHeaders( aValue ) |
|---|
| 447 |
local MIMEHeader = require( 'MIMEHeader' ) |
|---|
| 448 |
local aHeader = {} |
|---|
| 449 |
local aBuffer = nil |
|---|
| 450 |
local aStart = 1 |
|---|
| 451 |
local anEnd = nil |
|---|
| 452 |
|
|---|
| 453 |
while true do |
|---|
| 454 |
anEnd = aValue:find( '\r\n', aStart, true ) |
|---|
| 455 |
|
|---|
| 456 |
if anEnd then |
|---|
| 457 |
local aLine = aValue:sub( aStart, anEnd - 1 ) |
|---|
| 458 |
|
|---|
| 459 |
anEnd = anEnd + 2 |
|---|
| 460 |
aStart = anEnd |
|---|
| 461 |
|
|---|
| 462 |
if aLine ~= '' then |
|---|
| 463 |
local aChar = aLine:sub( 1, 1 ) |
|---|
| 464 |
|
|---|
| 465 |
if aChar ~= ' ' and aChar ~= '\t' then |
|---|
| 466 |
if aBuffer then |
|---|
| 467 |
aHeader[ #aHeader + 1 ] = MIMEHeader( table.concat( aBuffer, ' ' ) ) |
|---|
| 468 |
end |
|---|
| 469 |
|
|---|
| 470 |
aBuffer = {} |
|---|
| 471 |
end |
|---|
| 472 |
|
|---|
| 473 |
aBuffer[ #aBuffer + 1 ] = aLine |
|---|
| 474 |
else |
|---|
| 475 |
break |
|---|
| 476 |
end |
|---|
| 477 |
else |
|---|
| 478 |
break |
|---|
| 479 |
end |
|---|
| 480 |
end |
|---|
| 481 |
|
|---|
| 482 |
if aBuffer and #aBuffer > 0 then |
|---|
| 483 |
aHeader[ #aHeader + 1 ] = MIMEHeader( table.concat( aBuffer, ' ' ) ) |
|---|
| 484 |
end |
|---|
| 485 |
|
|---|
| 486 |
return aHeader, ( anEnd or aStart ) |
|---|
| 487 |
end |
|---|
| 488 |
|
|---|
| 489 |
local function NewHeaders( aValue ) |
|---|
| 490 |
local someHeaders = nil |
|---|
| 491 |
local anEnd = nil |
|---|
| 492 |
|
|---|
| 493 |
if type( aValue ) == 'table' then |
|---|
| 494 |
someHeaders, anEnd = ReadHeaders( WriteHeaders( aValue ) ) |
|---|
| 495 |
else |
|---|
| 496 |
someHeaders, anEnd = ReadHeaders( tostring( aValue or '' ) ) |
|---|
| 497 |
end |
|---|
| 498 |
|
|---|
| 499 |
setmetatable( someHeaders, self ) |
|---|
| 500 |
|
|---|
| 501 |
return someHeaders, anEnd |
|---|
| 502 |
end |
|---|
| 503 |
|
|---|
| 504 |
function meta:__call( aValue ) |
|---|
| 505 |
return NewHeaders( aValue ) |
|---|
| 506 |
end |
|---|
| 507 |
|
|---|
| 508 |
function self:__index( aKey ) |
|---|
| 509 |
if aKey then |
|---|
| 510 |
local someHeaders = {} |
|---|
| 511 |
|
|---|
| 512 |
aKey = aKey:lower() |
|---|
| 513 |
|
|---|
| 514 |
for anIndex, aHeader in ipairs( self ) do |
|---|
| 515 |
if aKey == aHeader.key then |
|---|
| 516 |
someHeaders[ #someHeaders + 1 ] = aHeader |
|---|
| 517 |
end |
|---|
| 518 |
end |
|---|
| 519 |
|
|---|
| 520 |
return unpack( someHeaders ) |
|---|
| 521 |
end |
|---|
| 522 |
|
|---|
| 523 |
return nil |
|---|
| 524 |
end |
|---|
| 525 |
|
|---|
| 526 |
function self:__concat( aValue ) |
|---|
| 527 |
return tostring( self ) .. tostring( aValue ) |
|---|
| 528 |
end |
|---|
| 529 |
|
|---|
| 530 |
function self:__eq( aValue ) |
|---|
| 531 |
return tostring( self ) == tostring( aValue ) |
|---|
| 532 |
end |
|---|
| 533 |
|
|---|
| 534 |
function self:__tostring() |
|---|
| 535 |
return 'WriteHeaders' |
|---|
| 536 |
end |
|---|
| 537 |
|
|---|
| 538 |
-------------------------------------------------------------------------------- |
|---|
| 539 |
-- MIME |
|---|
| 540 |
-------------------------------------------------------------------------------- |
|---|
| 541 |
|
|---|
| 542 |
module( 'MIME' ) |
|---|
| 543 |
_VERSION = '1.0' |
|---|
| 544 |
|
|---|
| 545 |
local self = setmetatable( _M, {} ) |
|---|
| 546 |
local meta = getmetatable( self ) |
|---|
| 547 |
|
|---|
| 548 |
local function Capitalize( aValue ) |
|---|
| 549 |
return ( aValue:lower():gsub( '(%l)([%w_\']*)', function( first, rest ) return first:upper() .. rest end ) ) |
|---|
| 550 |
end |
|---|
| 551 |
|
|---|
| 552 |
local function ReadType( aHeader ) |
|---|
| 553 |
local aHeader = aHeader or {} |
|---|
| 554 |
local aTypeHeader = aHeader[ 'content-type' ] or {} |
|---|
| 555 |
local aType = ( aTypeHeader.value or 'text/plain' ):lower() |
|---|
| 556 |
|
|---|
| 557 |
return aType |
|---|
| 558 |
end |
|---|
| 559 |
|
|---|
| 560 |
local function ContentModule( aType ) |
|---|
| 561 |
local aName = 'MIME' .. Capitalize( aType ):gsub( '[^%w]', '' ) |
|---|
| 562 |
local ok, aModule = pcall( require, aName ) |
|---|
| 563 |
|
|---|
| 564 |
if not ok then |
|---|
| 565 |
local anIndex = aType:find( '/', 1, true ) |
|---|
| 566 |
|
|---|
| 567 |
if anIndex then |
|---|
| 568 |
aModule = ContentModule( aType:sub( 1, anIndex - 1 ) ) |
|---|
| 569 |
else |
|---|
| 570 |
aModule = nil |
|---|
| 571 |
end |
|---|
| 572 |
end |
|---|
| 573 |
|
|---|
| 574 |
return aModule |
|---|
| 575 |
end |
|---|
| 576 |
|
|---|
| 577 |
local function ReadContent( aValue, aType, aHeader ) |
|---|
| 578 |
local aModule = ContentModule( aType ) |
|---|
| 579 |
|
|---|
| 580 |
if aModule then |
|---|
| 581 |
return aModule( aValue, aHeader ) |
|---|
| 582 |
end |
|---|
| 583 |
|
|---|
| 584 |
return aValue |
|---|
| 585 |
end |
|---|
| 586 |
|
|---|
| 587 |
local function ReadMIME( aValue ) |
|---|
| 588 |
local MIMEHeaders = require( 'MIMEHeaders' ) |
|---|
| 589 |
local aHeader, anEnd = MIMEHeaders( aValue ) |
|---|
| 590 |
local aType = ReadType( aHeader ) |
|---|
| 591 |
local aContent = ReadContent( aValue:sub( anEnd ), aType, aHeader ) |
|---|
| 592 |
local aMIME = { header = aHeader, type = aType, content = aContent } |
|---|
| 593 |
|
|---|
| 594 |
return aMIME |
|---|
| 595 |
end |
|---|
| 596 |
|
|---|
| 597 |
local function NewMIME( aValue ) |
|---|
| 598 |
local aMIME = nil |
|---|
| 599 |
|
|---|
| 600 |
if type( aValue ) == 'table' then |
|---|
| 601 |
aMIME = ReadMIME( WriteMIME( aValue ) ) |
|---|
| 602 |
else |
|---|
| 603 |
aMIME = ReadMIME( tostring( aValue or '' ) ) |
|---|
| 604 |
end |
|---|
| 605 |
|
|---|
| 606 |
setmetatable( aMIME, self ) |
|---|
| 607 |
|
|---|
| 608 |
return aMIME |
|---|
| 609 |
end |
|---|
| 610 |
|
|---|
| 611 |
function meta:__call( aValue ) |
|---|
| 612 |
return NewMIME( aValue ) |
|---|
| 613 |
end |
|---|
| 614 |
|
|---|
| 615 |
function self:__concat( aValue ) |
|---|
| 616 |
return tostring( self ) .. tostring( aValue ) |
|---|
| 617 |
end |
|---|
| 618 |
|
|---|
| 619 |
function self:__eq( aValue ) |
|---|
| 620 |
return tostring( self ) == tostring( aValue ) |
|---|
| 621 |
end |
|---|
| 622 |
|
|---|
| 623 |
function self:__tostring() |
|---|
| 624 |
return 'WriteMIME' --WriteMIME( self ) |
|---|
| 625 |
end |
|---|