Upload limits
One upload endpoint limited by files, by bytes and by both: 100 files lets in anywhere from under a megabyte to hundreds, and a byte limit bounds the most any upload gets in.
Every screen below was recorded under CPython. When this page was built, the EML interpreter replayed each session from the same input and printed the same bytes.
About
One upload endpoint limited three ways - by files, by bytes and by both - and the most each lets in.
main.eml- the menu, the uploads, the uploads under each limit, and an upload of your ownlimits.eml- the two limits, the uploads and the sizes of their files, and what a limit lets in
How each part works:
- Four uploads: 150 thumbnails of about 8 kB, 60 receipts of about 120 kB, 100 photos of about 3.5 MB and 40 scans of about 9 MB.
- As in the corpus case
cost-model-mismatch, a limit of 100 files is written in the unit that is easy to count, and what runs out is memory and bytes on the wire. Under it an upload gets anywhere from 0.9 MB to 432.0 MB in. - A limit is judged by the most it lets in, not by making uploads alike: at 20.0 MB the byte limit lets the small uploads through whole and stops every upload at 20.0 MB, 19.6 MB at most here. Both limits together never let in more than either alone.
What is checked: menu choices 1 to 4; for an upload of your own, 1 to 999 files of about 1 to 99999 kB each. An empty answer cancels.
Sessions: sessions/basic.in gives: - the uploads and the limits; - 300 files of about 9000 kB, and 20 files of about 5 kB.
sessions/bad-input.in gives: - menu choices 0 and x; - files: a cancel, 0, 1000 and x; then 10 files with a cancel, 0, 100000 and x for the size; - 150 files of about 8 kB, where the file limit lets in less than the byte limit.
Built on the verified corpus case cost-model-mismatch (the same workloads through a count limit, a size limit and both, judged by the maximum each admits).
Recorded sessions
What the screen shows while someone uses the program. Each typed line appears after its prompt, the way a terminal shows it.
bad-input
interpreter: byte-equal== Upload limits ==
One upload endpoint limited by files, by bytes and by both, and what each lets in.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 0
Pick a number from 1 to 4.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> x
Pick a number from 1 to 4.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 3
how many files (1 to 999)>
Cancelled.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 3
how many files (1 to 999)> 0
Type a whole number from 1 to 999.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 3
how many files (1 to 999)> 1000
Type a whole number from 1 to 999.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 3
how many files (1 to 999)> x
Type a whole number from 1 to 999.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 3
how many files (1 to 999)> 10
about how many kB each (1 to 99999)>
Cancelled.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 3
how many files (1 to 999)> 10
about how many kB each (1 to 99999)> 0
Type a whole number from 1 to 99999.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 3
how many files (1 to 999)> 10
about how many kB each (1 to 99999)> 100000
Type a whole number from 1 to 99999.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 3
how many files (1 to 999)> 10
about how many kB each (1 to 99999)> x
Type a whole number from 1 to 99999.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 3
how many files (1 to 999)> 150
about how many kB each (1 to 99999)> 8
upload 100 files 20.0 MB both
yours 100 files, 0.9 MB 150 files, 1.4 MB 100 files, 0.9 MB
The file limit lets in 0.9 MB of it, the byte limit 1.4 MB, both 0.9 MB.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 4
Bye.
What was typed (26 lines)
0
x
3
3
0
3
1000
3
x
3
10
3
10
0
3
10
100000
3
10
x
3
150
8
4
basic
interpreter: byte-equal== Upload limits ==
One upload endpoint limited by files, by bytes and by both, and what each lets in.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 1
The uploads, as their files come in:
thumbnails 150 files of about 8 kB, 1.4 MB in all
receipts 60 files of about 120 kB, 8.6 MB in all
photos 100 files of about 3500 kB, 420.0 MB in all
scans 40 files of about 9000 kB, 432.0 MB in all
The limits: at most 100 files; at most 20.0 MB; or both.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 2
upload 100 files 20.0 MB both
thumbnails 100 files, 0.9 MB 150 files, 1.4 MB 100 files, 0.9 MB
receipts 60 files, 8.6 MB 60 files, 8.6 MB 60 files, 8.6 MB
photos 100 files, 420.0 MB 5 files, 19.6 MB 5 files, 19.6 MB
scans 40 files, 432.0 MB 2 files, 18.9 MB 2 files, 18.9 MB
The most let in: 432.0 MB under the file limit, 19.6 MB under the byte limit, 19.6 MB under both.
Under the 100-file limit an upload gets anywhere from 0.9 MB to 432.0 MB in: the limit counts what is easy to count, not what runs out.
The byte limit lets small uploads through whole and stops every upload at 20.0 MB: a limit bounds the most, it does not make uploads alike.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 3
how many files (1 to 999)> 300
about how many kB each (1 to 99999)> 9000
upload 100 files 20.0 MB both
yours 100 files, 1080.0 MB 2 files, 18.9 MB 2 files, 18.9 MB
The file limit lets in 1080.0 MB of it, the byte limit 18.9 MB, both 18.9 MB.
Counted in files, the limit does not hold back the bytes that run out.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 3
how many files (1 to 999)> 20
about how many kB each (1 to 99999)> 5
upload 100 files 20.0 MB both
yours 20 files, 0.1 MB 20 files, 0.1 MB 20 files, 0.1 MB
The file limit lets in 0.1 MB of it, the byte limit 0.1 MB, both 0.1 MB.
1) the uploads 2) the limits 3) an upload of your own 4) quit
choice> 4
Bye.
What was typed (9 lines)
1
2
3
300
9000
3
20
5
4
Modules
The program as written, entry module first. Each module transpiles to its own Python file, which is what eml project run executes.
main.eml(entry)
eml# P160 upload limits: the uploads, each one under a limit on files, on
# bytes and on both, and an upload of your own.
import limits
def plain(s):
0 => i
len(s) => j
while i < j and s[i] == " ":
i + 1 => i
while j > i and s[j - 1] == " ":
j - 1 => j
return s[i:j]
def pad(s, n):
s => out
while len(out) < n:
out + " " => out
return out
def lpad(s, n):
s => out
while len(out) < n:
" " + out => out
return out
def mb(kb):
# kilobytes as megabytes to one place, rounded half up
int((kb + 50) / 100) => t
t % 10 => d
return str(int((t - d) / 10)) + "." + str(d) + " MB"
def total(sizes):
0 => t
for s in sizes:
t + s => t
return t
def show_uploads():
"The uploads, as their files come in:" ^0
for u in limits.uploads():
limits.files(u) => fs
(" " + pad(u[0], 12) + lpad(str(len(fs)), 4) + " files of about " + lpad(str(u[2]), 4) + " kB, " + lpad(mb(total(fs)), 9) + " in all") ^0
("The limits: at most " + str(limits.count_limit()) + " files; at most " + mb(limits.byte_limit()) + "; or both.") ^0
def cell(r):
return str(r[0]) + " files, " + mb(r[1])
def compare(us):
(" " + pad("upload", 12) + pad("100 files", 22) + pad("20.0 MB", 22) + "both") ^0
[0, 0, 0] => most
[0, 0, 0] => least
0 => first
for u in us:
limits.files(u) => fs
[limits.admit(fs, "count"), limits.admit(fs, "bytes"), limits.admit(fs, "both")] => rs
(" " + pad(u[0], 12) + pad(cell(rs[0]), 22) + pad(cell(rs[1]), 22) + cell(rs[2])) ^0
0 => k
while k < 3:
if rs[k][1] > most[k]:
rs[k][1] => most[k]
if first == 0 or rs[k][1] < least[k]:
rs[k][1] => least[k]
k + 1 => k
1 => first
if len(us) == 1:
("The file limit lets in " + mb(most[0]) + " of it, the byte limit " + mb(most[1]) + ", both " + mb(most[2]) + ".") ^0
if most[0] > limits.byte_limit():
"Counted in files, the limit does not hold back the bytes that run out." ^0
else:
("The most let in: " + mb(most[0]) + " under the file limit, " + mb(most[1]) + " under the byte limit, " + mb(most[2]) + " under both.") ^0
if most[0] > limits.byte_limit():
("Under the 100-file limit an upload gets anywhere from " + mb(least[0]) + " to " + mb(most[0]) + " in: the limit counts what is easy to count, not what runs out.") ^0
"The byte limit lets small uploads through whole and stops every upload at 20.0 MB: a limit bounds the most, it does not make uploads alike." ^0
def own():
plain(input("how many files (1 to 999)> ")) => t
if t == "":
"Cancelled." ^0
return
if len(t) > 3 or not digits(t) or int(t) < 1:
"Type a whole number from 1 to 999." ^0
return
plain(input("about how many kB each (1 to 99999)> ")) => k
if k == "":
"Cancelled." ^0
return
if len(k) > 5 or not digits(k) or int(k) < 1:
"Type a whole number from 1 to 99999." ^0
return
["yours", int(t), int(k)] => u
compare([u])
def digits(t):
for c in t:
if c < "0" or c > "9":
return False
return len(t) > 0
"== Upload limits ==" ^0
"One upload endpoint limited by files, by bytes and by both, and what each lets in." ^0
True => running
while running:
"" ^0
"1) the uploads 2) the limits 3) an upload of your own 4) quit" ^0
plain(input("choice> ")) => choice
if choice == "1":
show_uploads()
elif choice == "2":
compare(limits.uploads())
elif choice == "3":
own()
elif choice == "4":
False => running
else:
"Pick a number from 1 to 4." ^0
"Bye." ^0
Python projection (main.py)
import limits
def plain(s):
i = 0
j = len(s)
while i < j and s[i] == " ":
i = i + 1
while j > i and s[j - 1] == " ":
j = j - 1
return s[i:j]
def pad(s, n):
out = s
while len(out) < n:
out = out + " "
return out
def lpad(s, n):
out = s
while len(out) < n:
out = " " + out
return out
def mb(kb):
t = int((kb + 50) / 100)
d = t % 10
return str(int((t - d) / 10)) + "." + str(d) + " MB"
def total(sizes):
t = 0
for s in sizes:
t = t + s
return t
def show_uploads():
print("The uploads, as their files come in:")
for u in limits.uploads():
fs = limits.files(u)
print(" " + pad(u[0], 12) + lpad(str(len(fs)), 4) + " files of about " + lpad(str(u[2]), 4) + " kB, " + lpad(mb(total(fs)), 9) + " in all")
print("The limits: at most " + str(limits.count_limit()) + " files; at most " + mb(limits.byte_limit()) + "; or both.")
def cell(r):
return str(r[0]) + " files, " + mb(r[1])
def compare(us):
print(" " + pad("upload", 12) + pad("100 files", 22) + pad("20.0 MB", 22) + "both")
most = [0, 0, 0]
least = [0, 0, 0]
first = 0
for u in us:
fs = limits.files(u)
rs = [limits.admit(fs, "count"), limits.admit(fs, "bytes"), limits.admit(fs, "both")]
print(" " + pad(u[0], 12) + pad(cell(rs[0]), 22) + pad(cell(rs[1]), 22) + cell(rs[2]))
k = 0
while k < 3:
if rs[k][1] > most[k]:
most[k] = rs[k][1]
if first == 0 or rs[k][1] < least[k]:
least[k] = rs[k][1]
k = k + 1
first = 1
if len(us) == 1:
print("The file limit lets in " + mb(most[0]) + " of it, the byte limit " + mb(most[1]) + ", both " + mb(most[2]) + ".")
if most[0] > limits.byte_limit():
print("Counted in files, the limit does not hold back the bytes that run out.")
else:
print("The most let in: " + mb(most[0]) + " under the file limit, " + mb(most[1]) + " under the byte limit, " + mb(most[2]) + " under both.")
if most[0] > limits.byte_limit():
print("Under the 100-file limit an upload gets anywhere from " + mb(least[0]) + " to " + mb(most[0]) + " in: the limit counts what is easy to count, not what runs out.")
print("The byte limit lets small uploads through whole and stops every upload at 20.0 MB: a limit bounds the most, it does not make uploads alike.")
def own():
t = plain(input("how many files (1 to 999)> "))
if t == "":
print("Cancelled.")
return
if len(t) > 3 or not digits(t) or int(t) < 1:
print("Type a whole number from 1 to 999.")
return
k = plain(input("about how many kB each (1 to 99999)> "))
if k == "":
print("Cancelled.")
return
if len(k) > 5 or not digits(k) or int(k) < 1:
print("Type a whole number from 1 to 99999.")
return
u = ["yours", int(t), int(k)]
compare([u])
def digits(t):
for c in t:
if c < "0" or c > "9":
return False
return len(t) > 0
print("== Upload limits ==")
print("One upload endpoint limited by files, by bytes and by both, and what each lets in.")
running = True
while running:
print("")
print("1) the uploads 2) the limits 3) an upload of your own 4) quit")
choice = plain(input("choice> "))
if choice == "1":
show_uploads()
elif choice == "2":
compare(limits.uploads())
elif choice == "3":
own()
elif choice == "4":
running = False
else:
print("Pick a number from 1 to 4.")
print("Bye.")
limits.eml
eml# P160 upload limits - one upload endpoint, limited three ways. As in the
# corpus case cost-model-mismatch, a limit of 100 files is written in the
# unit that is easy to count, and what runs out is memory and bytes on the
# wire: 100 files is anywhere from a few kilobytes to many megabytes,
# depending on who is uploading. A limit's job is to bound the most it lets
# in, not to make every upload the same size, so each limit is judged by the
# largest upload it admits. Sizes are in kilobytes.
def count_limit():
return 100
def byte_limit():
# 20 megabytes, in kilobytes
return 20000
def uploads():
# [name, the sizes of its files in kilobytes, in the order they come]
return [["thumbnails", 150, 8], ["receipts", 60, 120], ["photos", 100, 3500], ["scans", 40, 9000]]
def files(u):
# the sizes of upload u's files: u[1] of them, sizes around u[2]
[] => out
0 => i
while i < u[1]:
out + [u[2] + int((i % 5) * u[2] / 10)] => out
i + 1 => i
return out
def admit(sizes, mode):
# [files let in, kilobytes let in, files refused]
0 => n
0 => kb
0 => refused
for s in sizes:
True => ok
if mode == "count" or mode == "both":
if n >= count_limit():
False => ok
if mode == "bytes" or mode == "both":
if kb + s > byte_limit():
False => ok
if ok:
n + 1 => n
kb + s => kb
else:
refused + 1 => refused
return [n, kb, refused]
Python projection (limits.py)
def count_limit():
return 100
def byte_limit():
return 20000
def uploads():
return [["thumbnails", 150, 8], ["receipts", 60, 120], ["photos", 100, 3500], ["scans", 40, 9000]]
def files(u):
out = []
i = 0
while i < u[1]:
out = out + [u[2] + int(i % 5 * u[2] / 10)]
i = i + 1
return out
def admit(sizes, mode):
n = 0
kb = 0
refused = 0
for s in sizes:
ok = True
if mode == "count" or mode == "both":
if n >= count_limit():
ok = False
if mode == "bytes" or mode == "both":
if kb + s > byte_limit():
ok = False
if ok:
n = n + 1
kb = kb + s
else:
refused = refused + 1
return [n, kb, refused]