feat: base64-режим загрузки (обход DDOS-Guard), v1.0.3
Deploy loadtest / validate (push) Waiting to run

This commit is contained in:
2026-07-10 09:00:02 +04:00
parent 25c0b17f91
commit 699a73d48d
2 changed files with 60 additions and 33 deletions
+12 -1
View File
@@ -1,9 +1,10 @@
import time import time
import base64
from flask import Flask, render_template, request from flask import Flask, render_template, request
app = Flask(__name__) app = Flask(__name__)
VERSION = '1.0.2' VERSION = '1.0.3'
@app.route('/') @app.route('/')
@@ -20,6 +21,16 @@ def health():
def upload(): def upload():
t0 = time.time() t0 = time.time()
total = 0 total = 0
# base64-режим: клиент отправляет поле "data"
data = request.form.get('data', '')
if data:
# убрать префикс data:...;base64,
if ',' in data:
data = data.split(',', 1)[1]
raw = base64.b64decode(data)
elapsed = round((time.time() - t0) * 1000)
return {'ok': True, 'bytes': len(raw), 'elapsed_ms': elapsed}
# старый режим: файл напрямую (может не работать через DDOS-Guard)
for f in request.files.values(): for f in request.files.values():
while True: while True:
chunk = f.read(8192) chunk = f.read(8192)
+48 -32
View File
@@ -180,48 +180,64 @@ async function uploadAll() {
fileSummary.textContent = summary; fileSummary.textContent = summary;
} }
/** uploadOne(fileEntry, idx) — XHR одного файла, возвращает {bytes, elapsed_ms} */ /** uploadOne(fileEntry, idx) — читает файл в base64, отправляет как поле формы */
function uploadOne(f, idx) { function uploadOne(f, idx) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest(); // Шаг 1: прочитать файл в base64
var fd = new FormData(); f.status = 'uploading';
fd.append('file', f.file, f.name); f.progress = 0;
renderTable();
var t0 = Date.now(); var reader = new FileReader();
reader.onload = function () {
// base64-строка готова, теперь отправляем
var t0 = Date.now();
var xhr = new XMLHttpRequest();
var fd = new FormData();
fd.append('data', reader.result);
fd.append('name', f.name);
fd.append('orig_size', f.size);
xhr.open('POST', '/upload'); xhr.open('POST', '/upload');
xhr.upload.onprogress = function (e) { xhr.upload.onprogress = function (e) {
if (e.lengthComputable) { if (e.lengthComputable) {
f.progress = Math.round(e.loaded / e.total * 100); f.progress = Math.round(e.loaded / e.total * 100);
renderTable(); renderTable();
}
};
xhr.onload = function () {
try {
var r = JSON.parse(xhr.responseText);
if (r.ok) {
resolve({ bytes: r.bytes, elapsed_ms: r.elapsed_ms });
} else {
reject(new Error(r.error || 'Ошибка сервера'));
} }
} catch (e) { };
reject(new Error('Некорректный ответ'));
} xhr.onload = function () {
try {
var r = JSON.parse(xhr.responseText);
if (r.ok) {
resolve({ bytes: r.bytes, elapsed_ms: r.elapsed_ms });
} else {
reject(new Error(r.error || 'Ошибка сервера'));
}
} catch (e) {
reject(new Error('Некорректный ответ'));
}
};
xhr.onerror = function () {
var elapsed = Date.now() - t0;
reject(new Error('Сеть (' + (elapsed / 1000).toFixed(0) + 'с)'));
};
xhr.ontimeout = function () {
reject(new Error('Таймаут (' + (xhr.timeout / 1000) + 'с)'));
};
xhr.timeout = 600000; // 10 минут (base64 +33%)
xhr.send(fd);
}; };
xhr.onerror = function () { reader.onerror = function () {
var elapsed = Date.now() - t0; reject(new Error('Ошибка чтения файла'));
reject(new Error('Сеть (' + (elapsed / 1000).toFixed(0) + 'с)'));
}; };
xhr.ontimeout = function () { reader.readAsDataURL(f.file);
reject(new Error('Таймаут (' + (xhr.timeout / 1000) + 'с)'));
};
xhr.timeout = 300000; // 5 минут на файл
xhr.send(fd);
}); });
} }