mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 09:02:15 -06:00
accept file POSTs without specifying the act field;
primarily to support uploading from Igloo IRC but also generally useful (not actually tested with Igloo IRC yet because it's a paid feature so just gonna wait for spiky to wake up and tell me it didn't work)
This commit is contained in:
parent
dc8e621d7c
commit
9bc09ce949
|
@ -1569,10 +1569,12 @@ interact with copyparty using non-browser clients
|
||||||
* `var xhr = new XMLHttpRequest(); xhr.open('POST', '//127.0.0.1:3923/msgs?raw'); xhr.send('foo');`
|
* `var xhr = new XMLHttpRequest(); xhr.open('POST', '//127.0.0.1:3923/msgs?raw'); xhr.send('foo');`
|
||||||
|
|
||||||
* curl/wget: upload some files (post=file, chunk=stdin)
|
* curl/wget: upload some files (post=file, chunk=stdin)
|
||||||
* `post(){ curl -F act=bput -F f=@"$1" http://127.0.0.1:3923/?pw=wark;}`
|
* `post(){ curl -F f=@"$1" http://127.0.0.1:3923/?pw=wark;}`
|
||||||
`post movie.mkv`
|
`post movie.mkv` (gives HTML in return)
|
||||||
|
* `post(){ curl -F f=@"$1" 'http://127.0.0.1:3923/?want=url&pw=wark';}`
|
||||||
|
`post movie.mkv` (gives hotlink in return)
|
||||||
* `post(){ curl -H pw:wark -H rand:8 -T "$1" http://127.0.0.1:3923/;}`
|
* `post(){ curl -H pw:wark -H rand:8 -T "$1" http://127.0.0.1:3923/;}`
|
||||||
`post movie.mkv`
|
`post movie.mkv` (randomized filename)
|
||||||
* `post(){ wget --header='pw: wark' --post-file="$1" -O- http://127.0.0.1:3923/?raw;}`
|
* `post(){ wget --header='pw: wark' --post-file="$1" -O- http://127.0.0.1:3923/?raw;}`
|
||||||
`post movie.mkv`
|
`post movie.mkv`
|
||||||
* `chunk(){ curl -H pw:wark -T- http://127.0.0.1:3923/;}`
|
* `chunk(){ curl -H pw:wark -T- http://127.0.0.1:3923/;}`
|
||||||
|
|
|
@ -45,6 +45,7 @@ from .util import (
|
||||||
ODict,
|
ODict,
|
||||||
Pebkac,
|
Pebkac,
|
||||||
UnrecvEOF,
|
UnrecvEOF,
|
||||||
|
WrongPostKey,
|
||||||
absreal,
|
absreal,
|
||||||
alltrace,
|
alltrace,
|
||||||
atomic_move,
|
atomic_move,
|
||||||
|
@ -1862,7 +1863,16 @@ class HttpCli(object):
|
||||||
self.parser = MultipartParser(self.log, self.sr, self.headers)
|
self.parser = MultipartParser(self.log, self.sr, self.headers)
|
||||||
self.parser.parse()
|
self.parser.parse()
|
||||||
|
|
||||||
act = self.parser.require("act", 64)
|
file0: list[tuple[str, Optional[str], Generator[bytes, None, None]]] = []
|
||||||
|
try:
|
||||||
|
act = self.parser.require("act", 64)
|
||||||
|
except WrongPostKey as ex:
|
||||||
|
if ex.got == "f" and ex.fname:
|
||||||
|
self.log("missing 'act', but looks like an upload so assuming that")
|
||||||
|
file0 = [(ex.got, ex.fname, ex.datagen)]
|
||||||
|
act = "bput"
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
if act == "login":
|
if act == "login":
|
||||||
return self.handle_login()
|
return self.handle_login()
|
||||||
|
@ -1875,7 +1885,7 @@ class HttpCli(object):
|
||||||
return self.handle_new_md()
|
return self.handle_new_md()
|
||||||
|
|
||||||
if act == "bput":
|
if act == "bput":
|
||||||
return self.handle_plain_upload()
|
return self.handle_plain_upload(file0)
|
||||||
|
|
||||||
if act == "tput":
|
if act == "tput":
|
||||||
return self.handle_text_upload()
|
return self.handle_text_upload()
|
||||||
|
@ -2314,7 +2324,9 @@ class HttpCli(object):
|
||||||
vfs.flags.get("xau") or [],
|
vfs.flags.get("xau") or [],
|
||||||
)
|
)
|
||||||
|
|
||||||
def handle_plain_upload(self) -> bool:
|
def handle_plain_upload(
|
||||||
|
self, file0: list[tuple[str, Optional[str], Generator[bytes, None, None]]]
|
||||||
|
) -> bool:
|
||||||
assert self.parser
|
assert self.parser
|
||||||
nullwrite = self.args.nw
|
nullwrite = self.args.nw
|
||||||
vfs, rem = self.asrv.vfs.get(self.vpath, self.uname, False, True)
|
vfs, rem = self.asrv.vfs.get(self.vpath, self.uname, False, True)
|
||||||
|
@ -2340,7 +2352,8 @@ class HttpCli(object):
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
try:
|
try:
|
||||||
assert self.parser.gen
|
assert self.parser.gen
|
||||||
for nfile, (p_field, p_file, p_data) in enumerate(self.parser.gen):
|
gens = itertools.chain(file0, self.parser.gen)
|
||||||
|
for nfile, (p_field, p_file, p_data) in enumerate(gens):
|
||||||
if not p_file:
|
if not p_file:
|
||||||
self.log("discarding incoming file without filename")
|
self.log("discarding incoming file without filename")
|
||||||
# fallthrough
|
# fallthrough
|
||||||
|
|
|
@ -1537,11 +1537,9 @@ class MultipartParser(object):
|
||||||
raises if the field name is not as expected
|
raises if the field name is not as expected
|
||||||
"""
|
"""
|
||||||
assert self.gen
|
assert self.gen
|
||||||
p_field, _, p_data = next(self.gen)
|
p_field, p_fname, p_data = next(self.gen)
|
||||||
if p_field != field_name:
|
if p_field != field_name:
|
||||||
raise Pebkac(
|
raise WrongPostKey(field_name, p_field, p_fname, p_data)
|
||||||
422, 'expected field "{}", got "{}"'.format(field_name, p_field)
|
|
||||||
)
|
|
||||||
|
|
||||||
return self._read_value(p_data, max_len).decode("utf-8", "surrogateescape")
|
return self._read_value(p_data, max_len).decode("utf-8", "surrogateescape")
|
||||||
|
|
||||||
|
@ -3058,3 +3056,20 @@ class Pebkac(Exception):
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return "Pebkac({}, {})".format(self.code, repr(self.args))
|
return "Pebkac({}, {})".format(self.code, repr(self.args))
|
||||||
|
|
||||||
|
|
||||||
|
class WrongPostKey(Pebkac):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
expected: str,
|
||||||
|
got: str,
|
||||||
|
fname: Optional[str],
|
||||||
|
datagen: Generator[bytes, None, None],
|
||||||
|
) -> None:
|
||||||
|
msg = 'expected field "{}", got "{}"'.format(expected, got)
|
||||||
|
super(WrongPostKey, self).__init__(422, msg)
|
||||||
|
|
||||||
|
self.expected = expected
|
||||||
|
self.got = got
|
||||||
|
self.fname = fname
|
||||||
|
self.datagen = datagen
|
||||||
|
|
|
@ -162,8 +162,8 @@ authenticate using header `Cookie: cppwd=foo` or url param `&pw=foo`
|
||||||
| PUT | | (binary data) | upload into file at URL |
|
| PUT | | (binary data) | upload into file at URL |
|
||||||
| PUT | `?gz` | (binary data) | compress with gzip and write into file at URL |
|
| PUT | `?gz` | (binary data) | compress with gzip and write into file at URL |
|
||||||
| PUT | `?xz` | (binary data) | compress with xz and write into file at URL |
|
| PUT | `?xz` | (binary data) | compress with xz and write into file at URL |
|
||||||
| mPOST | | `act=bput`, `f=FILE` | upload `FILE` into the folder at URL |
|
| mPOST | | `f=FILE` | upload `FILE` into the folder at URL |
|
||||||
| mPOST | `?j` | `act=bput`, `f=FILE` | ...and reply with json |
|
| mPOST | `?j` | `f=FILE` | ...and reply with json |
|
||||||
| mPOST | | `act=mkdir`, `name=foo` | create directory `foo` at URL |
|
| mPOST | | `act=mkdir`, `name=foo` | create directory `foo` at URL |
|
||||||
| POST | `?delete` | | delete URL recursively |
|
| POST | `?delete` | | delete URL recursively |
|
||||||
| jPOST | `?delete` | `["/foo","/bar"]` | delete `/foo` and `/bar` recursively |
|
| jPOST | `?delete` | `["/foo","/bar"]` | delete `/foo` and `/bar` recursively |
|
||||||
|
|
Loading…
Reference in a new issue