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); 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() { void Request::reset() {
http_parser = nullptr; http_parser = nullptr;
session = nullptr; session = nullptr;
@ -66,6 +88,8 @@ void Request::reset() {
middleware_stack = nullptr; middleware_stack = nullptr;
_path_stack.clear(); _path_stack.clear();
_path_stack_pointer = 0; _path_stack_pointer = 0;
file_size = 0;
current_file_progress = 0;
head.clear(); head.clear();
body.clear(); body.clear();
@ -151,6 +175,8 @@ void Request::push_path() {
Request::Request() { Request::Request() {
response = nullptr; response = nullptr;
//file_chunk_size = 1 << 20; //1MB
file_chunk_size = 1 << 23;
reset(); reset();
} }
@ -159,6 +185,48 @@ Request::~Request() {
delete response; 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() { Request *RequestPool::get_request() {
_mutex.lock(); _mutex.lock();

View File

@ -28,10 +28,17 @@ public:
std::string footer; std::string footer;
std::string compiled_body; 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_body();
void compile_and_send_body(); void compile_and_send_body();
void next_stage(); void next_stage();
void send(); void send();
void send_file(const std::string &p_file_path);
void reset(); void reset();
void setup_url_stack(); void setup_url_stack();
@ -49,6 +56,8 @@ public:
~Request(); ~Request();
protected: protected:
void _progress_send_file();
std::vector<std::string> _path_stack; std::vector<std::string> _path_stack;
uint32_t _path_stack_pointer; 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)) { if (s->file_cache->wwwroot_has_file(file_name)) {
std::string fp = s->file_cache->wwwroot + file_name; std::string fp = s->file_cache->wwwroot + file_name;
FILE *f = fopen(fp.c_str(), "rb"); request->send_file(fp);
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();
return; return;
} }
} }