Implemented chunked file downloads. For some reason if a file is too big and has to be sent in more that 43 chunks it crashes, it might be a bug in brynet (it always crashes at the 43th chunk, with every file and chunk size setting.), will figure out the problem later.

This commit is contained in:
Relintai 2021-01-08 02:55:41 +01:00
parent 8e429cee7d
commit 4b64bf5864
3 changed files with 78 additions and 23 deletions

View File

@ -59,6 +59,28 @@ void Request::send() {
RequestPool::return_request(this);
}
void Request::send_file(const std::string &p_file_path) {
file_path = p_file_path;
FILE *f = fopen(file_path.c_str(), "rb");
if (!f) {
printf("send_file: Error: Download: file doesn't exists! %s\n", file_path.c_str());
return;
}
fseek(f, 0, SEEK_END);
file_size = ftell(f);
fclose(f);
response->addHeadValue("Connection", "Close");
std::string result = "HTTP/1.1 200 OK\r\nConnection: Close\r\n\r\n";
const HttpSession::Ptr lsession = (*session);
(*session)->send(result.c_str(), result.size(), [this]() { this->_progress_send_file(); });
}
void Request::reset() {
http_parser = nullptr;
session = nullptr;
@ -66,6 +88,8 @@ void Request::reset() {
middleware_stack = nullptr;
_path_stack.clear();
_path_stack_pointer = 0;
file_size = 0;
current_file_progress = 0;
head.clear();
body.clear();
@ -151,6 +175,8 @@ void Request::push_path() {
Request::Request() {
response = nullptr;
//file_chunk_size = 1 << 20; //1MB
file_chunk_size = 1 << 23;
reset();
}
@ -159,6 +185,48 @@ Request::~Request() {
delete response;
}
void Request::_progress_send_file() {
const HttpSession::Ptr lsession = (*session);
if (current_file_progress >= file_size) {
lsession->postShutdown();
RequestPool::return_request(this);
return;
}
FILE *f = fopen(file_path.c_str(), "rb");
if (!f) {
printf("Error: Download: In progress file doesn't exists anymore! %s\n", file_path.c_str());
lsession->postShutdown();
RequestPool::return_request(this);
return;
}
fseek(f, current_file_progress, SEEK_SET);
long nfp = current_file_progress + file_chunk_size;
long csize = file_chunk_size;
if (nfp >= file_size) {
csize = (file_size - current_file_progress);
}
body.resize(csize);
fread(&body[0], 1, csize, f);
fclose(f);
current_file_progress = nfp;
(*session)->send(body.c_str(), body.size(), [this]() { this->_progress_send_file(); });
}
Request *RequestPool::get_request() {
_mutex.lock();

View File

@ -28,10 +28,17 @@ public:
std::string footer;
std::string compiled_body;
std::string file_path;
long file_size;
long current_file_progress;
long file_chunk_size;
bool file_next;
void compile_body();
void compile_and_send_body();
void next_stage();
void send();
void send_file(const std::string &p_file_path);
void reset();
void setup_url_stack();
@ -49,6 +56,8 @@ public:
~Request();
protected:
void _progress_send_file();
std::vector<std::string> _path_stack;
uint32_t _path_stack_pointer;
};

View File

@ -30,29 +30,7 @@ void PagedArticle::index(Request *request) {
if (s->file_cache->wwwroot_has_file(file_name)) {
std::string fp = s->file_cache->wwwroot + file_name;
FILE *f = fopen(fp.c_str(), "rb");
if (!f) {
printf("Error: Registered file doesn't exists anymore! %s\n", fp.c_str());
Application::get_instance()->send_error(404, request);
return;
}
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
std::string body;
body.resize(fsize);
fread(&body[0], 1, fsize, f);
fclose(f);
//TODO set mimetype?
request->response->setBody(body);
request->send();
request->send_file(fp);
return;
}
}