Annotation of parser3/tests/459.html, revision 1.2

1.1       moko        1: # file:// disk paths, and schemes allowed per call site (feature #941)
                      2: # No absolute path is reported: it is machine dependent, and outside windows ':' gets escaped on untaint.
1.2     ! moko        3: @main[][root;uri;dir;text;windows]
1.1       moko        4: $root[$request:document-root]
                      5: $uri[^file_uri[$root/tests/459.html]]
                      6: $dir[^file_uri[$root/tests]]
                      7: 
                      8: $report[^hash::create[]]
                      9: 
                     10: # these do not depend on document-root
                     11: $report.schemes[
                     12:        $.[load parser://][ ^outcome{ $f[^file::load[text;parser://method]] $f.text }]
                     13:        $.[load http:// is allowed][ ^allowed{ $f[^file::load[text;http://127.0.0.1:1/x]] }]
                     14:        $.[table::load http:// is allowed][ ^allowed{ $t[^table::load[http://127.0.0.1:1/x]] }]
                     15:        $.[table::load file://][ ^outcome{ $t[^table::load[nameless;$uri]] ^if(^t.count[]){loaded}{EMPTY} }]
                     16:        $.[fullpath http://][ ^outcome{ ^file:fullpath[http://example.com/some/long/path.gif] }]
                     17:        $.[a built uri keeps the scheme][ ^outcome{ ^file:fullpath[http://$root/path.gif] }]
                     18:        $.[scheme only at the start][ ^outcome{ ^file:fullpath[x/file:///etc/passwd] }]
                     19:        $.[empty file:// rejected][ ^outcome{ ^file:fullpath[file://] }]
                     20:        $.[use file://][ ^outcome{ ^use[^file_uri[$root/tests/366.p]] used }]
                     21:        $.[use http://][ ^outcome{ ^use[http://127.0.0.1:1/x.p] }]
                     22:        $.[windows-only file://C:/ form][ ^if(^root.left(1) eq '/'){ok}{ ^eq[ ^outcome{ ^file:fullpath[file://$root/tests/459.html] }; /tests/459.html ] }]
                     23: ]
                     24: 
                     25: # where a uri is an error, and where it is just no file
1.2     ! moko       26: # file://evilhost is invalid everywhere; with a path it would be a UNC path under windows, see below
1.1       moko       27: $report.throwing[
                     28:        $.[save refuses a uri][ ^outcome{ $s[text] ^s.save[http://example.com/459.txt] }]
1.2     ! moko       29:        $.[save refuses an invalid file://][ ^outcome{ $s[text] ^s.save[file://evilhost] }]
1.1       moko       30:        $.[delete refuses a uri][ ^outcome{ ^file:delete[http://example.com/459.txt] }]
                     31:        $.[delete with exception(false) ignores a uri][ ^outcome{ ^file:delete[http://example.com/459.txt][ $.exception(false) ] silent }]
1.2     ! moko       32:        $.[delete with exception(false) ignores an invalid file://][ ^outcome{ ^file:delete[file://evilhost][ $.exception(false) ] silent }]
1.1       moko       33:        $.[find never finds a uri][ ^outcome{ ^file:find[http://example.com/Makefile]{not found} }]
1.2     ! moko       34:        $.[find does not throw on an invalid file://][ ^outcome{ ^file:find[file://evilhost]{not found} }]
        !            35:        $.[-f and -d do not throw on a uri or an invalid file://][ ^outcome{ ^if(-f 'http://example.com/x' || -d 'parser://x' || -f 'file://evilhost'){YES}{no} }]
1.1       moko       36:        $.[-f and -d accept file://][ ^outcome{ ^if(-f $uri && -d $dir){yes}{NO} }]
                     37: ]
                     38: 
1.2     ! moko       39: # '\' is a path separator on all platforms (feature #1300): paths are '/'-normalized, strings are kept as given
        !            40: $report.backslash[
        !            41:        $.[save creates the directories][ ^outcome{ $s[text] ^s.save[459_tmp\b\c.txt] ^if(-f '459_tmp/b/c.txt'){459_tmp/b/c.txt}{NO FILE} }]
        !            42:        $.[-f][ ^if(-f '459_tmp\b\c.txt'){yes}{NO}]
        !            43:        $.[load][ ^outcome{ $f[^file::load[text;459_tmp\b\c.txt]] $f.text }]
        !            44:        $.[list][ ^outcome{ $l[^file:list[459_tmp\]] ^l.menu{$l.name}[,] }]
        !            45:        $.[delete removes the directories][ ^outcome{ ^file:delete[459_tmp\b\c.txt] ^if(-d '459_tmp'){LEFT}{removed} }]
        !            46:        $.[fullpath of a relative name][ ^file:fullpath[a\x.gif]]
        !            47:        $.[fullpath of a web path][ ^file:fullpath[/tests\459.html]]
        !            48:        $.[a leading backslash is a web path][ ^file:fullpath[\tests\459.html]]
        !            49:        $.[find relative to the request uri][ ^file:find[366_dir\test.p]{NOT FOUND}]
        !            50:        $.[find climbs up][ ^file:find[\tests\zz\Makefile]{NOT FOUND}]
        !            51:        $.[-f file://][ ^if(-f ^file_uri[$root/tests\459.html]){yes}{NO}]
        !            52:        $.[find file://][ ^file:find[^file_uri[$root/tests/366_dir\test.p]]{NOT FOUND}]
        !            53:        $.[delete file://][ ^outcome{ $s[text] ^s.save[459_tmp\d.txt] ^file:delete[^file_uri[$root/tests/459_tmp\d.txt]] deleted }]
        !            54:        $.[use][ ^outcome{ ^use[366_dir\test-duplicate.p] used }]
        !            55:        $.[dirname keeps the string][ ^file:dirname[x\y\z.txt]]
        !            56:        $.[basename][ ^file:basename[x\y\z.txt]]
        !            57: ]
        !            58: 
1.1       moko       59: # the same checks against three flavours of document-root
                     60: $report.[document-root][
                     61:        $.plain[ ^cycle[$root;$root] ]
                     62:        $.[with a trailing slash][ ^cycle[$root/;$root] ]
1.2     ! moko       63:        ^rem{ empty root = file system root: the web path /x is the disk path /x; a relative name is still resolved against the document }
1.1       moko       64:        $.empty[ ^cycle[;$root] ]
                     65: ]
                     66: 
1.2     ! moko       67: # the last ones, as they change document-root too
        !            68: 
        !            69: # /root must not match /rootbeer
1.1       moko       70: $request:document-root[$root/tes]
                     71: $report.[segment boundary][
                     72:        $.[disk path][ ^outcome{ ^file:fullpath[$uri] }]
                     73:        $.[relative name][ ^outcome{ ^file:fullpath[x.gif] }]
                     74: ]
                     75: 
1.2     ! moko       76: # under windows file://server/share/path is the UNC path \\server\share\path, elsewhere the authority is refused
        !            77: $windows(^root.left(1) ne '/')
        !            78: $request:document-root[//server/share]
        !            79: $report.unc[
        !            80:        $.[file://server/share][ ^eq[ ^outcome{ ^file:fullpath[file://server/share/x.gif] }; ^if($windows){/x.gif}{Exception: must be file:///path or file://localhost/path} ]]
        !            81:        $.[file:////server/share][ ^outcome{ ^file:fullpath[file:////server/share/x.gif] }]
        !            82:        $.[file:///\\server\share][ ^eq[ ^outcome{ ^file:fullpath[file:///\\server\share\x.gif] }; ^if($windows){/x.gif}{Exception: is outside of ^$request:document-root [//server/share]} ]]
        !            83: ]
        !            84: 
        !            85: # the document root is machine dependent, and windows lists one more file uri form
1.1       moko       86: $text[^print[$report]]
1.2     ! moko       87: $text[^text.replace[, file://localhost/path or file://server/share/path; or file://localhost/path]]
1.1       moko       88: ^taint[as-is][^text.replace[$root;<root>]]
                     89: 
                     90: 
                     91: @cycle[root;root0][web;prefix;uri;luri;found;deep]
                     92: $request:document-root[$root]
                     93: # with no root a disk path is its own web path, but only one starting with '/', not so under windows:
                     94: # hence the comparisons below instead of just the result
                     95: $web(def $root || ^root0.left(1) eq '/')
                     96: $prefix[^if(def $root){}{$root0}]
                     97: $uri[^file_uri[$root0/tests/459.html]]
                     98: $luri[^file_uri[$root0/tests/459.html;localhost]]
                     99: # test.p has no namesake up the tree, so a mangled path would not be found by climbing up by chance
                    100: $found[^file_uri[$root0/tests/366_dir/test.p]]
                    101: $deep[^file_uri[$root0/tests/366_dir/zz/test.p]]
                    102: $result[
1.2     ! moko      103:        $.[document-root is returned as given][ $request:document-root ]
1.1       moko      104:        $.[file:// loads the same file][ ^outcome{ $a[^file::load[text;$uri]] ^if(^a.text.length[]){loaded}{EMPTY} }]
                    105:        $.[fullpath of a relative name][ ^eq[ ^outcome{ ^file:fullpath[x.gif] }; ^if($web){$prefix/tests/x.gif}{Exception: is outside of ^$request:document-root []} ]]
                    106:        $.[fullpath maps file:// to web space][ ^eq[ ^outcome{ ^file:fullpath[$uri] }; ^if($web){$prefix/tests/459.html}{Exception: is outside of ^$request:document-root []} ]]
                    107:        $.[fullpath maps file://localhost/ to web space][ ^eq[ ^outcome{ ^file:fullpath[$luri] }; ^if($web){$prefix/tests/459.html}{Exception: is outside of ^$request:document-root []} ]]
                    108:        $.[find maps file:// to web space][ ^eq[ ^file:find[$found]{NOT FOUND}; ^if($web){$prefix/tests/366_dir/test.p}{NOT FOUND} ]]
                    109:        $.[find climbs up from a disk path][ ^eq[ ^file:find[$deep]{NOT FOUND}; ^if($web){$prefix/tests/366_dir/test.p}{NOT FOUND} ]]
                    110:        $.[find climbs up from a web path][ ^file:find[/tests/zz/Makefile]{NOT FOUND}]
                    111:        $.[find relative to the request uri][ ^file:find[Makefile]{NOT FOUND}]
                    112:        $.[localhost authority allowed][ ^outcome{ ^file:fullpath[file://localhost/nonexistent-459] }]
                    113:        $.[fullpath outside the root][ ^outcome{ ^file:fullpath[file:///nonexistent-459] }]
                    114:        $.[find outside the root][ ^file:find[file:///nonexistent-459]{NOT FOUND}]
                    115: ]
                    116: 
                    117: @print[h;indent][k;v]
                    118: ^h.foreach[k;v]{${indent}${k}:^if($v is 'hash'){^#0A^print[$v;$indent^#09]}{ ^v.trim[]^#0A}}
                    119: 
                    120: @outcome[code]
                    121: ^try{
                    122:        $result[$code]
                    123:        $result[^result.trim[]]
                    124: }{
                    125:        $exception.handled(true)
                    126:        $result[Exception: $exception.comment]
                    127: }
                    128: 
                    129: # a scheme is allowed when the attempt fails anyhow, but not as an unsupported one
                    130: @allowed[code][r]
                    131: $r[^outcome{$code}]
                    132: $result[^if(^r.pos[unsupported path scheme]>=0){REJECTED}{allowed}]
                    133: 
                    134: # a standard file uri: file:///C:/path or file://localhost/C:/path under windows
                    135: @file_uri[path;host]
                    136: $result[file://$host^if(^path.left(1) ne '/'){/}$path]
                    137: 
                    138: @eq[got;want]
                    139: $result[^if(^got.trim[] eq ^want.trim[]){ok}{WRONG [$got] want [$want]}]

E-mail: