Browse Source

Added support of asynchonous IO mode for the internal file server

master
Artyom Beilis 8 years ago
parent
commit
142ffce91d
5 changed files with 100 additions and 24 deletions
  1. +22
    -0
      CMakeLists.txt
  2. +2
    -1
      private/internal_file_server.h
  3. +2
    -1
      private/service_impl.h
  4. +65
    -21
      src/internal_file_server.cpp
  5. +9
    -1
      src/service.cpp

+ 22
- 0
CMakeLists.txt View File

@@ -825,6 +825,7 @@ add_test(http_timeouts_test_write
"--test-write=true"
"--test-exec=${PYTHON} ${CNF}/http_timeouts_test.py write")


add_test(file_server_test
file_server_test "-c" "${CNF}/file_server_test.js"
"--test-exec=${PYTHON} ${CNF}/file_server_test.py"
@@ -844,6 +845,27 @@ add_test(file_server_with_listing_test
"-U" "${CNF}"
)



add_test(file_server_test_async
file_server_test "-c" "${CNF}/file_server_test.js" "--file_server-async=true"
"--test-exec=${PYTHON} ${CNF}/file_server_test.py"
"-U" "${CNF}"
)

add_test(file_server_test_no_links_async
file_server_test "-c" "${CNF}/file_server_test.js" "--file_server-check_symlink=false" "--file_server-async=true"
"--test-exec=${PYTHON} ${CNF}/file_server_test.py no_links"
"-U" "${CNF}"
)

add_test(file_server_with_listing_test_async
file_server_test "-c" "${CNF}/file_server_test.js" "--file_server-async=true"
"--file_server-listing=true"
"--test-exec=${PYTHON} ${CNF}/file_server_test.py listing"
"-U" "${CNF}"
)

add_test(disco_test_http
disco_test "-c" "${CNF}/proto_test.js"
"--service-api=http" "--service-port=8080" "--service-ip=127.0.0.1"


+ 2
- 1
private/internal_file_server.h View File

@@ -18,7 +18,7 @@ namespace impl {
public:
static void normalize_path(std::string &path);
file_server(cppcms::service &srv);
file_server(cppcms::service &srv,bool async=false);
~file_server();
virtual void main(std::string file_name);

@@ -38,6 +38,7 @@ namespace impl {
mime_type mime_;
bool list_directories_;
bool check_symlinks_;
bool async_;
std::string index_file_;
};



+ 2
- 1
private/service_impl.h View File

@@ -19,6 +19,7 @@
namespace cppcms {
class service;
class applications_pool;
class application;
class thread_pool;
class session_pool;

@@ -67,7 +68,7 @@ namespace impl {
std::vector<std::string> args_;

booster::intrusive_ptr<cppcms::application> async_file_server_;
};




+ 65
- 21
src/internal_file_server.cpp View File

@@ -15,9 +15,11 @@

#include <stdlib.h>

#include <booster/callback.h>
#include <cppcms/application.h>
#include <cppcms/service.h>
#include <cppcms/http_response.h>
#include <cppcms/http_context.h>
#include "internal_file_server.h"
#include <cppcms/cppcms_error.h>
#include <cppcms/json.h>
@@ -41,7 +43,7 @@
namespace cppcms {
namespace impl {

file_server::file_server(cppcms::service &srv) : application(srv)
file_server::file_server(cppcms::service &srv,bool async) : application(srv), async_(async)
{
if(!canonical(settings().get("file_server.document_root","."),document_root_))
throw cppcms_error("Invalid document root");
@@ -406,16 +408,63 @@ void file_server::list_dir(std::string const &url,std::string const &path)
out <<"</body>\n";
}

namespace file_server_detail {

class async_file_handler : public booster::callable<void(cppcms::http::context::completion_type)>
{
public:
async_file_handler(std::string const &path,booster::shared_ptr<cppcms::http::context> c) :
f(path.c_str(),std::ios_base::binary),
ctx(c)
{
}
typedef booster::intrusive_ptr<async_file_handler> pointer_type;
void go()
{
if(!f) {
ctx->response().set_html_header();
ctx->response().make_error_response(404);
ctx->async_complete_response();
}
else {
ctx->response();
(*this)(cppcms::http::context::operation_completed);
}
}
void operator()(cppcms::http::context::completion_type c)
{
if(c!=cppcms::http::context::operation_completed)
return;
char buf[4096];
size_t total = 0;
while(!f.eof() && total < 65536) {
f.read(buf,sizeof(buf));
size_t n = f.gcount();
total += n;
ctx->response().out().write(buf,n);
}
if(f.eof())
ctx->async_complete_response();
else
ctx->async_flush_output(pointer_type(this));
}
private:
booster::nowide::ifstream f;
booster::shared_ptr<cppcms::http::context> ctx;
};

} // file_server_detail

void file_server::main(std::string file_name)
{
std::string path;


if(!check_in_document_root(file_name,path)) {
show404();
return;
}
int s=file_mode(path);
if((s & S_IFDIR)) {
@@ -467,33 +516,28 @@ void file_server::main(std::string file_name)
else
response().content_type("application/octet-stream");

if(!allow_deflate_) {
if(!allow_deflate_ && !async_) {
response().io_mode(http::response::nogzip);
}

booster::nowide::ifstream file(path.c_str(),std::ios_base::binary);
if(!file) {
show404();
return;
if(async_) {
file_server_detail::async_file_handler::pointer_type p=new file_server_detail::async_file_handler(path,release_context());
p->go();
}
else {
booster::nowide::ifstream file(path.c_str(),std::ios_base::binary);
if(!file) {
show404();
return;
}
response().out()<<file.rdbuf(); // write stream to stream
}
response().out()<<file.rdbuf(); // write stream to stream
}

void file_server::show404()
{
response().status(http::response::not_found);
response().set_html_header();
response().out() <<
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n"
" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
"<html>\n"
" <head>\n"
" <title>404 Not Found</title>\n"
" </head>\n"
" <body>\n"
" <h1>404 Not Found</h1>\n"
" </body>\n"
"</html>\n"<<std::flush;
response().make_error_response(404);
}




+ 9
- 1
src/service.cpp View File

@@ -26,6 +26,7 @@
#include <cppcms/service.h>
#include "service_impl.h"
#include <cppcms/applications_pool.h>
#include <cppcms/application.h>
#include <cppcms/thread_pool.h>
#include <cppcms/cppcms_error.h>
#include <cppcms/mount_point.h>
@@ -235,7 +236,13 @@ void service::setup()
impl_->cache_pool_.reset(new cppcms::cache_pool(settings()));
impl_->session_pool_.reset(new cppcms::session_pool(*this));
if(settings().get("file_server.enable",false)) {
applications_pool().mount(applications_factory<cppcms::impl::file_server>(),mount_point(""));
if(settings().get("file_server.async",false)) {
impl_->async_file_server_ = new cppcms::impl::file_server(*this,true);
applications_pool().mount(impl_->async_file_server_,mount_point(""));
}
else {
applications_pool().mount(applications_factory<cppcms::impl::file_server>(),mount_point(""));
}
}
}

@@ -977,6 +984,7 @@ namespace impl {
}
service::~service()
{
async_file_server_ = 0;
acceptors_.clear();
thread_pool_.reset();
sig_.reset();


Loading…
Cancel
Save