2009-01-19 19:01:13 -05:00
|
|
|
! Copyright (C) 2009 Doug Coleman.
|
2008-11-21 23:10:58 -05:00
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2009-01-19 19:01:13 -05:00
|
|
|
USING: multiline kernel sequences io splitting fry namespaces
|
|
|
|
http.parsers hashtables assocs combinators ascii io.files.unique
|
|
|
|
accessors io.encodings.binary io.files byte-arrays math
|
2009-03-21 01:47:33 -04:00
|
|
|
io.streams.string combinators.short-circuit strings math.order ;
|
2008-11-21 23:10:58 -05:00
|
|
|
IN: mime.multipart
|
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
CONSTANT: buffer-size 65536
|
|
|
|
CONSTANT: separator-prefix "\r\n--"
|
2008-11-21 23:10:58 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
TUPLE: multipart
|
|
|
|
end-of-stream?
|
|
|
|
current-separator mime-separator
|
|
|
|
header
|
|
|
|
content-disposition bytes
|
|
|
|
filename temp-file
|
|
|
|
name name-content
|
2009-01-26 16:23:49 -05:00
|
|
|
mime-parts ;
|
2008-11-21 23:10:58 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
TUPLE: mime-file headers filename temporary-path ;
|
|
|
|
TUPLE: mime-variable headers key value ;
|
2008-11-21 23:10:58 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
: <multipart> ( mime-separator -- multipart )
|
|
|
|
multipart new
|
|
|
|
swap >>mime-separator
|
2009-01-26 16:23:49 -05:00
|
|
|
H{ } clone >>mime-parts ;
|
2008-11-21 23:10:58 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
ERROR: bad-header bytes ;
|
2008-11-21 23:10:58 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
: mime-write ( sequence -- )
|
|
|
|
>byte-array write ;
|
2008-11-21 23:10:58 -05:00
|
|
|
|
2009-01-20 16:45:00 -05:00
|
|
|
: parse-headers ( string -- hashtable )
|
|
|
|
string-lines harvest [ parse-header-line ] map >hashtable ;
|
2008-11-22 01:12:44 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
ERROR: end-of-stream multipart ;
|
2008-11-22 01:12:44 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
: fill-bytes ( multipart -- multipart )
|
|
|
|
buffer-size read
|
|
|
|
[ '[ _ append ] change-bytes ]
|
|
|
|
[ t >>end-of-stream? ] if* ;
|
2008-11-21 23:10:58 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
: maybe-fill-bytes ( multipart -- multipart )
|
2009-02-06 23:56:46 -05:00
|
|
|
dup bytes>> length 256 < [ fill-bytes ] when ;
|
2008-11-21 23:56:40 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
: split-bytes ( bytes separator -- leftover-bytes safe-to-dump )
|
2009-01-26 18:23:31 -05:00
|
|
|
dupd [ length ] bi@ 1- - short cut-slice swap ;
|
2008-11-29 03:38:27 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
: dump-until-separator ( multipart -- multipart )
|
2009-01-23 19:20:47 -05:00
|
|
|
dup
|
|
|
|
[ current-separator>> ] [ bytes>> ] bi
|
|
|
|
[ nip ] [ start ] 2bi [
|
2009-01-19 19:01:13 -05:00
|
|
|
cut-slice
|
|
|
|
[ mime-write ]
|
2009-01-26 18:23:31 -05:00
|
|
|
[ over current-separator>> length short tail-slice >>bytes ] bi*
|
2009-01-19 19:01:13 -05:00
|
|
|
] [
|
|
|
|
drop
|
2009-01-26 18:23:31 -05:00
|
|
|
dup [ bytes>> ] [ current-separator>> ] bi split-bytes mime-write
|
2009-01-19 19:01:13 -05:00
|
|
|
>>bytes fill-bytes dup end-of-stream?>> [ dump-until-separator ] unless
|
|
|
|
] if* ;
|
|
|
|
|
|
|
|
: dump-string ( multipart separator -- multipart string )
|
|
|
|
>>current-separator
|
|
|
|
[ dump-until-separator ] with-string-writer ;
|
|
|
|
|
|
|
|
: read-header ( multipart -- multipart )
|
2009-02-06 23:56:46 -05:00
|
|
|
maybe-fill-bytes
|
2009-01-26 18:23:31 -05:00
|
|
|
dup bytes>> "--\r\n" sequence= [
|
|
|
|
t >>end-of-stream?
|
2009-01-19 19:01:13 -05:00
|
|
|
] [
|
2009-01-26 18:23:31 -05:00
|
|
|
"\r\n\r\n" dump-string parse-headers >>header
|
2009-01-19 19:01:13 -05:00
|
|
|
] if ;
|
2008-11-29 03:38:27 -05:00
|
|
|
|
2009-01-20 16:45:00 -05:00
|
|
|
: empty-name? ( string -- ? )
|
|
|
|
{ "''" "\"\"" "" f } member? ;
|
|
|
|
|
2009-03-20 20:43:06 -04:00
|
|
|
: quote? ( ch -- ? ) "'\"" member? ;
|
|
|
|
|
|
|
|
: quoted? ( str -- ? )
|
|
|
|
{
|
|
|
|
[ length 1 > ]
|
|
|
|
[ first quote? ]
|
|
|
|
[ [ first ] [ peek ] bi = ]
|
|
|
|
} 1&& ;
|
|
|
|
|
|
|
|
: unquote ( str -- newstr )
|
|
|
|
dup quoted? [ but-last-slice rest-slice >string ] when ;
|
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
: save-uploaded-file ( multipart -- )
|
2009-01-20 16:45:00 -05:00
|
|
|
dup filename>> empty-name? [
|
2009-01-19 19:01:13 -05:00
|
|
|
drop
|
|
|
|
] [
|
|
|
|
[ [ header>> ] [ filename>> ] [ temp-file>> ] tri mime-file boa ]
|
2009-01-26 18:29:50 -05:00
|
|
|
[ content-disposition>> "name" swap at unquote ]
|
2009-01-26 16:23:49 -05:00
|
|
|
[ mime-parts>> set-at ] tri
|
2009-01-19 19:01:13 -05:00
|
|
|
] if ;
|
2008-11-29 03:38:27 -05:00
|
|
|
|
2009-01-26 16:23:49 -05:00
|
|
|
: save-mime-part ( multipart -- )
|
2009-01-20 16:45:00 -05:00
|
|
|
dup name>> empty-name? [
|
|
|
|
drop
|
|
|
|
] [
|
2009-02-06 00:59:36 -05:00
|
|
|
[ name-content>> ]
|
2009-01-26 18:29:50 -05:00
|
|
|
[ name>> unquote ]
|
2009-01-26 16:23:49 -05:00
|
|
|
[ mime-parts>> set-at ] tri
|
2009-01-20 16:45:00 -05:00
|
|
|
] if ;
|
2008-11-29 03:38:27 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
: dump-mime-file ( multipart filename -- multipart )
|
|
|
|
binary <file-writer> [
|
|
|
|
dup mime-separator>> >>current-separator dump-until-separator
|
|
|
|
] with-output-stream ;
|
2008-11-29 03:38:27 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
: dump-file ( multipart -- multipart )
|
|
|
|
"factor-" "-upload" make-unique-file
|
|
|
|
[ >>temp-file ] [ dump-mime-file ] bi ;
|
2008-11-29 03:38:27 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
: parse-content-disposition-form-data ( string -- hashtable )
|
|
|
|
";" split
|
|
|
|
[ "=" split1 [ [ blank? ] trim ] bi@ ] H{ } map>assoc ;
|
2008-11-29 03:39:41 -05:00
|
|
|
|
2009-01-19 19:01:13 -05:00
|
|
|
: lookup-disposition ( multipart string -- multipart value/f )
|
|
|
|
over content-disposition>> at ;
|
|
|
|
|
|
|
|
ERROR: unknown-content-disposition multipart ;
|
|
|
|
|
|
|
|
: parse-form-data ( multipart -- multipart )
|
|
|
|
"filename" lookup-disposition [
|
2009-01-26 18:29:50 -05:00
|
|
|
unquote
|
2009-01-19 19:01:13 -05:00
|
|
|
>>filename
|
|
|
|
[ dump-file ] [ save-uploaded-file ] bi
|
|
|
|
] [
|
|
|
|
"name" lookup-disposition [
|
|
|
|
[ dup mime-separator>> dump-string >>name-content ] dip
|
2009-01-26 16:23:49 -05:00
|
|
|
>>name dup save-mime-part
|
2009-01-19 19:01:13 -05:00
|
|
|
] [
|
|
|
|
unknown-content-disposition
|
|
|
|
] if*
|
|
|
|
] if* ;
|
|
|
|
|
|
|
|
ERROR: no-content-disposition multipart ;
|
|
|
|
|
|
|
|
: process-header ( multipart -- multipart )
|
|
|
|
"content-disposition" over header>> at ";" split1 swap {
|
|
|
|
{ "form-data" [
|
|
|
|
parse-content-disposition-form-data >>content-disposition
|
|
|
|
parse-form-data
|
|
|
|
] }
|
|
|
|
[ no-content-disposition ]
|
|
|
|
} case ;
|
|
|
|
|
2009-01-20 17:35:09 -05:00
|
|
|
: assert-sequence= ( a b -- )
|
|
|
|
2dup sequence= [ 2drop ] [ assert ] if ;
|
|
|
|
|
|
|
|
: read-assert-sequence= ( sequence -- )
|
|
|
|
[ length read ] keep assert-sequence= ;
|
2009-01-19 19:01:13 -05:00
|
|
|
|
|
|
|
: parse-beginning ( multipart -- multipart )
|
2009-01-20 17:35:09 -05:00
|
|
|
"--" read-assert-sequence=
|
2009-01-19 19:01:13 -05:00
|
|
|
dup mime-separator>>
|
2009-01-20 17:35:09 -05:00
|
|
|
[ read-assert-sequence= ]
|
2009-01-19 19:01:13 -05:00
|
|
|
[ separator-prefix prepend >>mime-separator ] bi ;
|
|
|
|
|
|
|
|
: parse-multipart-loop ( multipart -- multipart )
|
|
|
|
read-header
|
|
|
|
dup end-of-stream?>> [ process-header parse-multipart-loop ] unless ;
|
|
|
|
|
2009-01-26 16:23:49 -05:00
|
|
|
: parse-multipart ( separator -- mime-parts )
|
2009-01-26 18:23:31 -05:00
|
|
|
<multipart> parse-beginning fill-bytes parse-multipart-loop
|
2009-01-26 16:23:49 -05:00
|
|
|
mime-parts>> ;
|