upload with PUT allows streaming
This commit is contained in:
79
code/app.py
79
code/app.py
@@ -27,7 +27,7 @@ from utils.files import (
|
||||
db_maintenance,
|
||||
)
|
||||
|
||||
__VERSION__ = "20230819.0"
|
||||
__VERSION__ = "20230820.0"
|
||||
app = Flask(__name__)
|
||||
app.config.from_object(__name__)
|
||||
app.config.from_prefixed_env()
|
||||
@@ -42,7 +42,7 @@ def index():
|
||||
return "", 200
|
||||
|
||||
|
||||
@app.route("/upload", methods=["POST"])
|
||||
@app.route("/upload", methods=["PUT","POST"])
|
||||
def upload():
|
||||
"""
|
||||
Upload a file, example CURL:
|
||||
@@ -58,45 +58,64 @@ def upload():
|
||||
- Additionally, "Expires-Hours" can be used.
|
||||
- Max-Dowloads: -1 means no upper limit
|
||||
|
||||
IF using GET, you can upload larger files with pipes
|
||||
|
||||
cat largefile | \
|
||||
curl -fL -w "\n" --upload-file - \
|
||||
-H "Name: my.file.ext" \
|
||||
-H "Max-Downloads: 4000" \
|
||||
-H "Expires-Days: 14" \
|
||||
-H "Secret: dff789f0bbe8183d32542" \
|
||||
"$FLASK_PUBLIC_URL"/upload
|
||||
|
||||
Returns the file download URL
|
||||
"""
|
||||
|
||||
name = request.headers.get("Name", None)
|
||||
if name is None:
|
||||
return "Name required", 500
|
||||
safe_filename = secure_filename(name)
|
||||
secret = request.headers.get("Secret", "")
|
||||
if secret != app.config["ACCESS_TOKEN"]:
|
||||
return "Error", 401
|
||||
max_dl = request.headers.get("Max-Downloads", app.config["DEFAULT_MAX_DL"])
|
||||
expires = int(time.time()) + int(app.config["DEFAULT_EXPIRE"])
|
||||
if "Expires-days" in request.headers:
|
||||
expires = int(time.time()) + 24 * 3600 * int(
|
||||
request.headers.get("Expires-days")
|
||||
)
|
||||
if "Expires-hours" in request.headers:
|
||||
expires = int(time.time()) + 3600 * int(
|
||||
request.headers.get("Expires-hours")
|
||||
)
|
||||
|
||||
while True:
|
||||
token = random_token()
|
||||
folder = os.path.join(app.config["DATAFOLDER"], token)
|
||||
if not os.path.exists(folder):
|
||||
break
|
||||
filename = file_full_path(token, safe_filename)
|
||||
os.mkdir(folder)
|
||||
|
||||
if request.method == "POST":
|
||||
file = request.files.get("file")
|
||||
name = request.headers.get("Name", None)
|
||||
if name is None:
|
||||
return "Name required", 500
|
||||
secret = request.headers.get("Secret", "")
|
||||
if secret != app.config["ACCESS_TOKEN"]:
|
||||
return "Error", 401
|
||||
max_dl = request.headers.get("Max-Downloads", app.config["DEFAULT_MAX_DL"])
|
||||
expires = int(time.time()) + int(app.config["DEFAULT_EXPIRE"])
|
||||
if "Expires-days" in request.headers:
|
||||
expires = int(time.time()) + 24 * 3600 * int(
|
||||
request.headers.get("Expires-days")
|
||||
)
|
||||
if "Expires-hours" in request.headers:
|
||||
expires = int(time.time()) + 3600 * int(
|
||||
request.headers.get("Expires-hours")
|
||||
)
|
||||
|
||||
if file:
|
||||
safe_filename = secure_filename(name)
|
||||
while True:
|
||||
token = random_token()
|
||||
folder = os.path.join(app.config["DATAFOLDER"], token)
|
||||
if not os.path.exists(folder):
|
||||
break
|
||||
os.mkdir(folder)
|
||||
filename = file_full_path(token, safe_filename)
|
||||
file.save(filename)
|
||||
db_store_file(token, safe_filename, expires, max_dl)
|
||||
download_url = file_full_url(token, safe_filename)
|
||||
return "File uploaded\n%s\n" % (download_url,), 200
|
||||
else:
|
||||
return "Use the 'file' variable to upload\n", 400
|
||||
|
||||
if request.method == "PUT":
|
||||
chunk_size = 1024 * 1024 * 64 # 64Mb
|
||||
with open(filename, 'wb') as f:
|
||||
while True:
|
||||
chunk = request.stream.read(chunk_size)
|
||||
if not chunk:
|
||||
break
|
||||
f.write(chunk)
|
||||
|
||||
db_store_file(token, safe_filename, expires, max_dl)
|
||||
download_url = file_full_url(token, safe_filename)
|
||||
return "File uploaded\n%s\n" % (download_url,), 200
|
||||
|
||||
@app.route("/details/<token>/<name>", methods=["GET"])
|
||||
def details(token, name):
|
||||
|
||||
@@ -8,6 +8,7 @@ export FLASK_CONF="/data/config.json"
|
||||
export SERVER=gunicorn
|
||||
export PID="flees.pid"
|
||||
export WORKERS
|
||||
export TIMEOUT
|
||||
|
||||
if [[ $( stat -c %u /data ) -ne $( id -u ) ]]; then
|
||||
echo User id and /data folder owner do not match
|
||||
@@ -19,4 +20,4 @@ set -eu
|
||||
. /opt/venv/bin/activate
|
||||
sh ./init_db.sh "$FLASK_DB"
|
||||
|
||||
exec "$SERVER" -w $WORKERS 'app:app' --pid="$PID" -b 0.0.0.0:5000
|
||||
exec "$SERVER" -w $WORKERS --timeout $TIMEOUT 'app:app' --pid="$PID" -b 0.0.0.0:5000
|
||||
|
||||
@@ -104,8 +104,7 @@ _write() {
|
||||
|
||||
_write_folder() { # name, file
|
||||
tar c "$2" | \
|
||||
curl -fL -w "\n" -F file="@-" -X POST \
|
||||
--progress-bar \
|
||||
curl -fL -w "\n" -g --upload-file - \
|
||||
-H "Name: $1" \
|
||||
-H "Max-Downloads: $MAXDL" \
|
||||
-H "Expires-Days: $MAXDAYS" \
|
||||
@@ -113,8 +112,7 @@ _write_folder() { # name, file
|
||||
"$MFL_ROOTURL"/upload | cat
|
||||
}
|
||||
_write_file() { # name, file
|
||||
curl -fL -w "\n" -F file="@$2" -X POST \
|
||||
--progress-bar \
|
||||
curl -fL -w "\n" -g --upload-file "$2" \
|
||||
-H "Name: $1" \
|
||||
-H "Max-Downloads: $MAXDL" \
|
||||
-H "Expires-Days: $MAXDAYS" \
|
||||
@@ -123,8 +121,7 @@ _write_file() { # name, file
|
||||
}
|
||||
_write_stdin() { # name
|
||||
cat - | \
|
||||
curl -fL -w "\n" -F file="@-" -X POST \
|
||||
--progress-bar \
|
||||
curl -fL -w "\n" -g --upload-file - \
|
||||
-H "Name: $1" \
|
||||
-H "Max-Downloads: $MAXDL" \
|
||||
-H "Expires-Days: $MAXDAYS" \
|
||||
@@ -211,7 +208,7 @@ for (( i=2; i<=$#; i++ )); do
|
||||
done
|
||||
if [[ -z "$NAME" ]]; then
|
||||
if [[ -n "$FILE" ]]; then
|
||||
NAME="$( basename ${FILE} )"
|
||||
NAME="$( basename "${FILE}" )"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user