carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package runs
2
3import (
4 "errors"
5 "strings"
6 "time"
7 "unicode"
8 "unicode/utf8"
9)
10
11var (
12 ErrBadApp = errors.New("runs: not an account and app")
13 ErrBadID = errors.New("runs: not a run id")
14 ErrNoArgs = errors.New("runs: no arguments")
15 ErrTooManyArgs = errors.New("runs: more than 256 arguments")
16 ErrArgvTooLarge = errors.New("runs: arguments over 64 KB")
17 ErrArgNUL = errors.New("runs: an argument holds a NUL byte")
18 ErrTimeout = errors.New("runs: timeout outside 1s to 6h")
19 ErrFilesTooLarge = errors.New("runs: files over 64 MB")
20 ErrFileName = errors.New("runs: not a plain file name")
21 ErrFileTwice = errors.New("runs: two files share a name")
22)
23
24// FileNameError names the file a refusal is about.
25type FileNameError struct {
26 Name string
27 Twice bool
28}
29
30func (e *FileNameError) Error() string {
31 if e.Twice {
32 return ErrFileTwice.Error() + ": " + e.Name
33 }
34 return ErrFileName.Error() + ": " + e.Name
35}
36
37func (e *FileNameError) Is(target error) bool {
38 return (e.Twice && target == ErrFileTwice) || (!e.Twice && target == ErrFileName)
39}
40
41// CheckArgv is spec §5.1's argv rule.
42func CheckArgv(argv []string) error {
43 switch {
44 case len(argv) == 0:
45 return ErrNoArgs
46 case len(argv) > MaxArgs:
47 return ErrTooManyArgs
48 }
49 total := 0
50 for _, a := range argv {
51 if strings.IndexByte(a, 0) >= 0 {
52 return ErrArgNUL
53 }
54 total += len(a)
55 }
56 if total > MaxArgvBytes {
57 return ErrArgvTooLarge
58 }
59 return nil
60}
61
62// CheckTimeout is spec §5.1's timeout rule.
63func CheckTimeout(d time.Duration) error {
64 if d < MinTimeout || d > MaxTimeout {
65 return ErrTimeout
66 }
67 return nil
68}
69
70// PlainName reports whether name is a plain base name: not empty, at most
71// 255 bytes, valid UTF-8, no slash, backslash or control character, and
72// not "." or "..". The console checks it, and the box again (spec §7).
73func PlainName(name string) bool {
74 if name == "" || name == "." || name == ".." || len(name) > 255 || !utf8.ValidString(name) {
75 return false
76 }
77 for _, r := range name {
78 if r == '/' || r == '\\' || unicode.IsControl(r) {
79 return false
80 }
81 }
82 return true
83}
84
85// CheckFiles is spec §5.1's file rule: plain names, each once, sizes not
86// negative, 64 MB in total.
87func CheckFiles(files []MetaFile) error {
88 seen := map[string]bool{}
89 var total int64
90 for _, f := range files {
91 if !PlainName(f.Name) {
92 return &FileNameError{Name: f.Name}
93 }
94 if seen[f.Name] {
95 return &FileNameError{Name: f.Name, Twice: true}
96 }
97 seen[f.Name] = true
98 if f.Size < 0 {
99 return ErrFilesTooLarge
100 }
101 total += f.Size
102 if total > MaxFileBytes {
103 return ErrFilesTooLarge
104 }
105 }
106 return nil
107}
108