Browse Source

Moved all content parsing code to http::request for both:

- easier filter integration
- putting right responsibility
master
Artyom Beilis 8 years ago
parent
commit
df2ac1736b
10 changed files with 339 additions and 283 deletions
  1. +4
    -4
      cppcms/http_content_filter.h
  2. +2
    -3
      cppcms/http_context.h
  3. +8
    -4
      cppcms/http_request.h
  4. +2
    -6
      private/cgi_api.h
  5. +15
    -2
      private/multipart_parser.h
  6. +59
    -175
      src/cgi_api.cpp
  7. +3
    -3
      src/http_content_filter.cpp
  8. +29
    -60
      src/http_context.cpp
  9. +216
    -26
      src/http_request.cpp
  10. +1
    -0
      tests/multipart_parser_test.cpp

+ 4
- 4
cppcms/http_content_filter.h View File

@@ -55,8 +55,8 @@ namespace http {
content_limits();
~content_limits();

size_t content_length_limit() const;
void content_length_limit(size_t size);
long long content_length_limit() const;
void content_length_limit(long long size);

long long multipart_form_data_limit() const;
void multipart_form_data_limit(long long size);
@@ -69,7 +69,7 @@ namespace http {

private:
size_t content_length_limit_;
long long content_length_limit_;
size_t file_in_memory_limit_;
long long multipart_form_data_limit_;
std::string uploads_path_;
@@ -92,7 +92,7 @@ namespace http {
booster::hold_ptr<_data> d;
};

class CPPCMS_API raw_content_filter : basic_content_filter {
class CPPCMS_API raw_content_filter : public basic_content_filter {
public:
virtual void on_data_chunk(void const *data,size_t data_size) = 0;
virtual ~raw_content_filter();


+ 2
- 3
cppcms/http_context.h View File

@@ -192,9 +192,8 @@ namespace cppcms {
void submit_to_asynchronous_application(booster::intrusive_ptr<application> app,std::string const &matched_url);
private:
friend class impl::cgi::connection;
bool has_file_filter();
int send_to_file_filter(file &f,int stage);
int on_headers_ready(bool has_content);
int on_content_progress(size_t n);
int on_headers_ready();
int translate_exception();
void make_error_message(std::exception const &e);
void on_request_ready(bool error);


+ 8
- 4
cppcms/http_request.h View File

@@ -318,14 +318,18 @@ namespace http {
~request();
/// \endcond
private:
void set_ready();
friend class context;
friend class impl::cgi::connection;

void set_post_data(std::vector<char> &post_data);
void set_post_data(std::vector<booster::shared_ptr<file> > const &multipart);
bool prepare();
int on_content_start();
void on_error();
int on_content_progress(size_t n);
std::pair<char *,size_t > get_buffer();
bool size_ok(file &f,long long size);

std::pair<char *,size_t> get_content_buffer();
bool prepare();
bool parse_cookies();
std::string urlencoded_decode(char const *,char const *);
bool parse_form_urlencoded(char const *begin,char const *end,form_type &out);


+ 2
- 6
private/cgi_api.h View File

@@ -162,20 +162,16 @@ namespace cgi {

void set_error(ehandler const &h,std::string s);
void on_headers_read(booster::system::error_code const &e,http::context *,ehandler const &h);
void load_content(booster::system::error_code const &e,http::context *,ehandler const &h);
void on_post_data_loaded(booster::system::error_code const &e,size_t ,http::context *,ehandler const &h);
void on_some_multipart_read(booster::system::error_code const &e,size_t n,http::context *,ehandler const &h);
void load_content(http::context *,ehandler const &h);
void on_some_content_read(booster::system::error_code const &e,size_t n,http::context *,ehandler const &h);
void handle_eof(callback const &on_eof);
void handle_http_error(int code,http::context *context,ehandler const &h);
void handle_http_error_eof(booster::system::error_code const &e,int code,ehandler const &h);

std::vector<char> content_;
cppcms::service *service_;
std::string async_chunk_;
std::string error_;
bool request_in_progress_;
long long read_size_;
std::auto_ptr<multipart_parser> multipart_parser_;

std::map<std::string,std::string> map_env_;



+ 15
- 2
private/multipart_parser.h View File

@@ -65,7 +65,7 @@ namespace cppcms {
~multipart_parser()
{
}
typedef enum {
parsing_error,
meta_ready,
@@ -75,6 +75,17 @@ namespace cppcms {
eof,
no_room_left
} parsing_result_type;
static bool is_ok(parsing_result_type r) {
switch(r) {
case meta_ready:
case content_partial:
case content_ready:
case continue_input:
return true;
default:
return false;
}
}

bool has_file() { return file_is_ready_; }
http::file &get_file()
@@ -132,8 +143,10 @@ namespace cppcms {
case expecting_eof_lf:
if(*buffer!='\n')
return parsing_error;
if(buffer + 1 == buffer_end)
if(buffer + 1 == buffer_end) {
buffer++;
return eof;
}
else
return parsing_error;
case expecting_lf:


+ 59
- 175
src/cgi_api.cpp View File

@@ -18,7 +18,6 @@
#include "cached_settings.h"
#include <cppcms/json.h>
#include "cgi_api.h"
#include "multipart_parser.h"
#include <cppcms/util.h>
#include <scgi_header.h>
#include <stdlib.h>
@@ -199,8 +198,7 @@ void connection::on_headers_read(booster::system::error_code const &e,http::cont
h(http::context::operation_aborted);
return;
}
context->request().prepare();
load_content(e,context,h);
load_content(context,h);
}

void connection::aync_wait_for_close_by_peer(booster::callback<void()> const &on_eof)
@@ -224,39 +222,41 @@ void connection::set_error(ehandler const &h,std::string s)
void connection::handle_http_error(int code,http::context *context,ehandler const &h)
{
async_chunk_.clear();
async_chunk_.reserve(256);
std::string status;
status.reserve(128);
status += char('0' + code/100);
status += char('0' + code/10 % 10);
status += char('0' + code % 10);
status += ' ';
status += http::response::status_to_string(code);
if(context->service().cached_settings().service.generate_http_headers) {
async_chunk_ += "HTTP/1.0 ";
async_chunk_ += status;
async_chunk_ += "\r\n"
"Connection: close\r\n"
"Content-Type: text/html\r\n"
"\r\n";
}
else {
async_chunk_ += "Content-Type: text/html\r\n"
"Status: ";
async_chunk_ += status;
async_chunk_ += "\r\n"
"\r\n";
}
if(!context->response().some_output_was_written()) {
async_chunk_.reserve(256);
std::string status;
status.reserve(128);
status += char('0' + code/100);
status += char('0' + code/10 % 10);
status += char('0' + code % 10);
status += ' ';
status += http::response::status_to_string(code);
if(context->service().cached_settings().service.generate_http_headers) {
async_chunk_ += "HTTP/1.0 ";
async_chunk_ += status;
async_chunk_ += "\r\n"
"Connection: close\r\n"
"Content-Type: text/html\r\n"
"\r\n";
}
else {
async_chunk_ += "Content-Type: text/html\r\n"
"Status: ";
async_chunk_ += status;
async_chunk_ += "\r\n"
"\r\n";
}


async_chunk_ +=
"<html>\r\n"
"<body>\r\n"
"<h1>";
async_chunk_ += status;
async_chunk_ += "</h1>\r\n"
"</body>\r\n"
"</html>\r\n";
async_chunk_ +=
"<html>\r\n"
"<body>\r\n"
"<h1>";
async_chunk_ += status;
async_chunk_ += "</h1>\r\n"
"</body>\r\n"
"</html>\r\n";
}
async_write(booster::aio::buffer(async_chunk_),true,
mfunc_to_event_handler(
&connection::handle_http_error_eof,
@@ -280,172 +280,56 @@ void connection::handle_http_error_eof(



void connection::load_content(booster::system::error_code const &e,http::context *context,ehandler const &h)
void connection::load_content(http::context *context,ehandler const &h)
{
if(e) {
set_error(h,e.message());
return;
}

http::content_type content_type = context->request().content_type_parsed();
char const *s_content_length=cgetenv("CONTENT_LENGTH");

long long content_length = *s_content_length == 0 ? 0 : atoll(s_content_length);

if(content_length < 0) {
handle_http_error(400,context,h);
return;
}
int status = context->on_headers_ready(content_length > 0);
if(status != 0) {
int status=0;
if((status = context->on_headers_ready())!=0) {
handle_http_error(status,context,h);
return;
}

if(content_length > 0) {
if(content_type.is_multipart_form_data()) {
// 64 MB
long long allowed=context->request().limits().multipart_form_data_limit();
if(content_length > allowed) {
BOOSTER_NOTICE("cppcms") << "multipart/form-data size too big " << content_length <<
" REMOTE_ADDR = `" << getenv("REMOTE_ADDR") << "' REMOTE_HOST=`" << getenv("REMOTE_HOST") << "'";
handle_http_error(413,context,h);
return;
}
multipart_parser_.reset(new multipart_parser(
context->request().limits().uploads_path(),
context->request().limits().file_in_memory_limit()));
read_size_ = content_length;
if(!multipart_parser_->set_content_type(content_type)) {
BOOSTER_NOTICE("cppcms") << "Invalid multipart/form-data request" << content_length <<
" REMOTE_ADDR = `" << getenv("REMOTE_ADDR") << "' REMOTE_HOST=`" << getenv("REMOTE_HOST") << "'";
handle_http_error(400,context,h);
return;
}
content_.clear();
content_.resize(8192);
async_read_some(&content_.front(),content_.size(),
mfunc_to_io_handler(&connection::on_some_multipart_read,
self(),
context,
h));
}
else {
long long allowed=context->request().limits().content_length_limit();
if(content_length > allowed) {
BOOSTER_NOTICE("cppcms") << "POST data size too big " << content_length <<
" REMOTE_ADDR = `" << getenv("REMOTE_ADDR") << "' REMOTE_HOST=`" << getenv("REMOTE_HOST") << "'";
handle_http_error(413,context,h);
return;
}
content_.clear();
content_.resize(content_length,0);
async_read( &content_.front(),
content_.size(),
mfunc_to_io_handler(&connection::on_post_data_loaded,self(),context,h));
}
if(context->request().content_length() > 0) {
std::pair<char *,size_t> buffer = context->request().get_buffer();
async_read_some(buffer.first,buffer.second,
mfunc_to_io_handler(&connection::on_some_content_read,
self(),
context,
h));
}
else {
on_post_data_loaded(booster::system::error_code(),0,context,h);
on_async_read_complete();
h(http::context::operation_completed);
}
}

void connection::on_some_multipart_read(booster::system::error_code const &e,size_t n,http::context *context,ehandler const &h)

void connection::on_some_content_read(booster::system::error_code const &e,size_t n,http::context *context,ehandler const &h)
{
if(e) { set_error(h,e.message()); return; }
read_size_-=n;
if(read_size_ < 0) { handle_http_error(400,context,h); return ;}
char const *begin = &content_.front();
char const *end = begin + n;
multipart_parser::parsing_result_type r = multipart_parser::continue_input;
long long allowed=context->request().limits().content_length_limit();
bool has_filter = context->has_file_filter();
while(begin!=end) {
r = multipart_parser_->consume(begin,end);
if(has_filter) {
int status;
switch(r) {
case multipart_parser::meta_ready:
status = context->send_to_file_filter(multipart_parser_->get_file(),0);
break;
case multipart_parser::content_partial:
status = context->send_to_file_filter(multipart_parser_->get_file(),1);
break;
case multipart_parser::content_ready:
status = context->send_to_file_filter(multipart_parser_->last_file(),2);
break;
default:
status = 0;
}
if(status != 0) {
handle_http_error(status,context,h);
return;
}
}

if(r==multipart_parser::content_ready || r==multipart_parser::content_partial) {
http::file &f= (r == multipart_parser::content_ready)
? multipart_parser_->last_file()
: multipart_parser_->get_file();

if(!f.has_mime() && f.size() > allowed) {
BOOSTER_NOTICE("cppcms") << "multipart/form-data non-file entry size too big " <<
f.size()
<< " REMOTE_ADDR = `" << getenv("REMOTE_ADDR")
<< "' REMOTE_HOST=`" << getenv("REMOTE_HOST") << "'";
handle_http_error(413,context,h);
return;
}
continue;
}
else if(r==multipart_parser::meta_ready)
continue;
break;

int status = context->on_content_progress(n);
if(status !=0) {
handle_http_error(status,context,h);
return;
}

if(r == multipart_parser::eof) {
if(read_size_ != 0) {
handle_http_error(400,context,h);
return;
}
content_.clear();
multipart_parser::files_type files = multipart_parser_->get_files();
context->request().set_post_data(files);
multipart_parser_.reset();
std::pair<char *,size_t> buffer = context->request().get_buffer();

if(buffer.second==0) {
on_async_read_complete();
h(http::context::operation_completed);
return;
}
else if (r==multipart_parser::parsing_error) {
handle_http_error(400,context,h);
return;
}
else if(r==multipart_parser::no_room_left) {
handle_http_error(413,context,h);
return;
}
else if(read_size_ == 0) {
handle_http_error(400,context,h);
return;
}
else {
async_read_some(&content_.front(),content_.size(),
mfunc_to_io_handler(&connection::on_some_multipart_read,
async_read_some(buffer.first,buffer.second,
mfunc_to_io_handler(&connection::on_some_content_read,
self(),
context,
h));
}
}


void connection::on_post_data_loaded(booster::system::error_code const &e,size_t /*unused*/,http::context *context,ehandler const &h)
{
if(e) { set_error(h,e.message()); return; }
context->request().set_post_data(content_);
on_async_read_complete();
h(http::context::operation_completed);
}

bool connection::is_reuseable()
{
return error_.empty() && keep_alive();


+ 3
- 3
src/http_content_filter.cpp View File

@@ -45,7 +45,7 @@ std::string abort_upload::message() const
struct content_limits::_data {};

content_limits::content_limits(impl::cached_settings const &s) :
content_length_limit_(s.security.content_length_limit * 1024),
content_length_limit_(s.security.content_length_limit * 1024LL),
file_in_memory_limit_(s.security.file_in_memory_limit),
multipart_form_data_limit_(s.security.multipart_form_data_limit * 1024LL),
uploads_path_(s.security.uploads_path)
@@ -63,8 +63,8 @@ content_limits::content_limits() :
{
}

size_t content_limits::content_length_limit() const { return content_length_limit_; }
void content_limits::content_length_limit(size_t size) { content_length_limit_=size; }
long long content_limits::content_length_limit() const { return content_length_limit_; }
void content_limits::content_length_limit(long long size) { content_length_limit_=size; }

long long content_limits::multipart_form_data_limit() const { return multipart_form_data_limit_; }
void content_limits::multipart_form_data_limit(long long size) { multipart_form_data_limit_=size; }


+ 29
- 60
src/http_context.cpp View File

@@ -129,11 +129,13 @@ namespace {
public:
context_guard(cppcms::application &app,cppcms::http::context &ctx) : app_(&app)
{
app_->add_context(ctx);
if(app_)
app_->add_context(ctx);
}
~context_guard()
{
app_->remove_context();
if(app_)
app_->remove_context();
}
private:
cppcms::application *app_;
@@ -204,13 +206,14 @@ int context::translate_exception()
return 0;
}

int context::on_headers_ready(bool has_content)
int context::on_headers_ready()
{
char const *host = conn_->cgetenv("HTTP_HOST");
char const *path_info = conn_->cgetenv("PATH_INFO");
char const *script_name = conn_->cgetenv("SCRIPT_NAME");
std::string matched;

booster::intrusive_ptr<application> app;
booster::shared_ptr<application_specific_pool> pool =
service().applications_pool().get_application_specific_pool(
host,
@@ -220,50 +223,37 @@ int context::on_headers_ready(bool has_content)
);
if(!pool)
return 404;
request().prepare();

int flags;
if(!has_content || ((flags=pool->flags()) & app::op_mode_mask) == app::synchronous || (flags & app::content_filter)==0) {
d->pool.swap(pool);
d->matched.swap(matched);
return 0;
if(request().content_length() != 0 && ((flags=pool->flags()) & app::op_mode_mask) != app::synchronous && (flags & app::content_filter)!=0) {
app = pool->get(service());
if(!app)
return 500;
try {
context_guard g(*app,*this);
app->main(matched);
}
catch(...) {
return translate_exception();
}
}

booster::intrusive_ptr<application> app = d->pool->get(service());
if(!app)
return 500;

try {
context_guard g(*app,*this);
app->main(matched);
}
catch(...) {
return translate_exception();
}
int status = request().on_content_start();
if(status!=0)
return status;
d->pool.swap(pool);
d->app.swap(app);
d->matched.swap(matched);
d->app.swap(app);
return 0;
}

bool context::has_file_filter()
int context::on_content_progress(size_t n)
{
return dynamic_cast<multipart_filter *>(request().content_filter())!=0;
}
int context::send_to_file_filter(file &f,int stage)
{
try {
context_guard g(*d->app,*this);
multipart_filter *filter=static_cast<multipart_filter *>(request().content_filter());
switch(stage) {
case 0: filter->on_new_file(f); break;
case 1: filter->on_upload_progress(f); break;
case 2: filter->on_data_ready(f); break;
}
}
catch(...) {
return translate_exception();
}
return 0;
context_guard g(*d->app,*this);
return request().on_content_progress(n);
}

void context::on_request_ready(bool error)
@@ -272,33 +262,12 @@ void context::on_request_ready(bool error)
booster::intrusive_ptr<application> app;
pool.swap(d->pool);
app.swap(d->app);
basic_content_filter *filter = 0;

if(error && app && (filter=request().content_filter())!=0) {
context_guard g(*app,*this);
try {
filter->on_error();
}
catch(...) {}
if(error) {
request().on_error();
return;
}

if(error)
return;

request().set_ready();

if(app && filter) {
context_guard g(*app,*this);
try {
filter->on_end_of_content();
}
catch(...) {
translate_exception();
return;
}
}

if(app) {
app->assign_context(self());
dispatch(app,d->matched,false);


+ 216
- 26
src/http_request.cpp View File

@@ -15,6 +15,7 @@
#include <cppcms/util.h>
#include "cached_settings.h"
#include <cppcms/service.h>
#include "multipart_parser.h"

#include <stdio.h>
#include <string.h>
@@ -23,7 +24,7 @@


namespace cppcms { namespace http {
using cppcms::impl::multipart_parser;
namespace {
template<typename Iterator>
void skip_after_period(Iterator &p,Iterator e)
@@ -130,8 +131,26 @@ struct request::_data {
std::vector<char> post_data;
content_limits limits;
basic_content_filter *filter;
bool filter_is_raw_content_filter;
bool filter_is_multipart_filter;
bool ready;
_data(cppcms::service &srv) : limits(srv.cached_settings()),filter(0),ready(false) {}
long long content_length;
long long read_size;
bool read_full;
bool no_on_error;
booster::hold_ptr<cppcms::impl::multipart_parser> multipart_parser;
_data(cppcms::service &srv) :
limits(srv.cached_settings()),
filter(0),
filter_is_raw_content_filter(false),
filter_is_multipart_filter(false),
ready(false),
content_length(0),
read_size(0),
read_full(false),
no_on_error(false)
{
}
};

basic_content_filter *request::content_filter()
@@ -142,55 +161,221 @@ basic_content_filter *request::content_filter()
void request::content_filter(basic_content_filter *filter)
{
d->filter = filter;
d->filter_is_multipart_filter = dynamic_cast<multipart_filter *>(filter) != 0;
d->filter_is_raw_content_filter = dynamic_cast<raw_content_filter *>(filter) != 0;
}

bool request::is_ready()
{
return d->ready;
}
void request::set_ready()
{
d->ready = true;
}

void request::set_post_data(std::vector<char> &post_data)
std::pair<char *,size_t > request::get_buffer()
{
d->post_data.clear();
d->post_data.swap(post_data);

if(content_type_.is_form_urlencoded()) {
if(!d->post_data.empty()) {
char const *pdata=&d->post_data.front();
parse_form_urlencoded(pdata,pdata+d->post_data.size(),post_);
char *ptr = 0;
size_t size = 0;
if(d->read_full) {
ptr = &d->post_data[0] + d->read_size;
size = d->post_data.size() - d->read_size;
}
else {
long long reminder = d->content_length - d->read_size;
if(static_cast<long long>(d->post_data.size()) < reminder) {
d->post_data.resize(d->content_length);
}
if(d->post_data.size() == 0) {
std::vector<char> tmp;
tmp.swap(d->post_data);
}
else {
ptr = &d->post_data[0];
size = d->post_data.size();
}
}
return std::make_pair(ptr,size);
}


bool request::size_ok(file &f,long long size)
{
if(!f.has_mime() && f.size() > size) {
BOOSTER_NOTICE("cppcms") << "multipart/form-data non-file entry size too big " <<
f.size()
<< " REMOTE_ADDR = `" << getenv("REMOTE_ADDR")
<< "' REMOTE_HOST=`" << getenv("REMOTE_HOST") << "'";
return false;
}
return true;
}
namespace {
std::string read_file(std::istream &in)
std::string read_file(size_t reserve,std::istream &in)
{
std::string res;
while(in.good() && !in.eof()) {
char buf[256];
in.read(buf,256);
res.append(buf,in.gcount());
res.reserve(reserve);
in.seekg(0);
std::streambuf *buf = in.rdbuf();
int c;
while((c=buf->sbumpc())!=EOF) {
res+=char(c);
}
return res;
}
}

void request::set_post_data(std::vector<booster::shared_ptr<file> > const &multipart)

int request::on_content_progress(size_t n)
{
for(unsigned i=0;i<multipart.size();i++) {
if(!multipart[i]->has_mime()) {
post_.insert(std::make_pair(multipart[i]->name(),read_file(multipart[i]->data())));
if(n==0)
return 0;
char const *begin = &d->post_data[0];
char const *end = begin + n;
d->read_size += n;
try {
if(d->filter_is_raw_content_filter) {
static_cast<raw_content_filter *>(d->filter)->on_data_chunk(&d->post_data[0],n);
}
else {
files_.push_back(multipart[i]);

if(d->multipart_parser.get()) {
multipart_parser::parsing_result_type r = multipart_parser::continue_input;

long long allowed=d->limits.content_length_limit();

while(begin!=end) {
r = d->multipart_parser->consume(begin,end);
switch(r) {
case multipart_parser::meta_ready:
{
if(d->filter_is_multipart_filter) {
file &f=d->multipart_parser->get_file();
static_cast<multipart_filter *>(d->filter)->on_new_file(f);
}
}
break;
case multipart_parser::content_partial:
{
file &f=d->multipart_parser->get_file();
if(!size_ok(f,allowed))
return 413;
if(d->filter_is_multipart_filter)
static_cast<multipart_filter *>(d->filter)->on_upload_progress(f);
}
break;
case multipart_parser::content_ready:
{
file &f=d->multipart_parser->last_file();
f.data().seekg(0);
if(!size_ok(f,allowed))
return 413;
if(d->filter_is_multipart_filter)
static_cast<multipart_filter *>(d->filter)->on_data_ready(f);
}
break;
case multipart_parser::continue_input:
break;
case multipart_parser::no_room_left:
return 413;
case multipart_parser::eof:
if(begin!=end)
return 400;
if(d->read_size != d->content_length)
return 400;
break;
case multipart_parser::parsing_error:
default:
return 400;
}
}
if(begin==end && d->read_size==d->content_length && r!=multipart_parser::eof) {
return 400;
}
}

if(d->read_size == d->content_length) {
if(d->read_full) {
if(content_type_.is_form_urlencoded()) {
char const *data = &d->post_data[0];
char const *data_end = data + d->post_data.size();
parse_form_urlencoded(data,data_end,post_);
}
}
else {
std::vector<char> tmp;
tmp.swap(d->post_data);
}
if(d->filter)
d->filter->on_end_of_content();
if(d->multipart_parser.get()) {
multipart_parser::files_type mp=d->multipart_parser->get_files();
d->multipart_parser.reset();
for(multipart_parser::files_type::iterator p=mp.begin();p!=mp.end();++p) {
multipart_parser::file_ptr f=*p;
if(!f->has_mime())
post_.insert(std::make_pair(f->name(),read_file(f->size(),f->data())));
else
files_.push_back(f);
}
}
d->ready = true;
}
}
catch(abort_upload const &ab) {
d->no_on_error=true;
return ab.code();
}
catch(std::exception const &e) {
BOOSTER_ERROR("cppcms") << e.what() << booster::trace(e);
d->no_on_error=true;
return 500;
}
catch(...) {
BOOSTER_ERROR("cppcms") << "Unknown exception ";
d->no_on_error=true;
return 500;
}
return 0;
}

void request::on_error()
{
if(d->filter) {
d->filter->on_error();
}
}

int request::on_content_start()
{
if(d->content_length == 0)
return 0;
if(content_type_.is_multipart_form_data()) {
if(d->content_length > d->limits.multipart_form_data_limit())
return 413;
}
else {
if(d->content_length > static_cast<long long>(d->limits.content_length_limit()))
return 413;
}
if(!d->filter_is_raw_content_filter && !content_type_.is_multipart_form_data()) {
d->post_data.resize(d->content_length);
d->read_full = true;
}
else {
if(d->content_length < 65535)
d->post_data.resize(d->content_length);
else
d->post_data.resize(65536);
if(content_type_.is_multipart_form_data() && !d->filter_is_raw_content_filter) {
d->multipart_parser.reset(new multipart_parser(
d->limits.uploads_path(),
d->limits.file_in_memory_limit()));
if(!d->multipart_parser->set_content_type(content_type_)) {
return 400;
}
}
}
return 0;
}

bool request::parse_form_urlencoded(char const *begin,char const *end,form_type &out)
{
@@ -215,6 +400,11 @@ bool request::prepare()
get_.clear();
}
parse_cookies();
char const *s = conn_->cgetenv("CONTENT_LENGTH");
if(!s || *s==0)
d->content_length = 0;
else
d->content_length = atoll(s);
content_type_ = cppcms::http::content_type(conn_->cgetenv("CONTENT_TYPE"));
return true;
}
@@ -261,7 +451,7 @@ cppcms::http::content_type request::content_type_parsed()
}

std::string request::auth_type() { return conn_->getenv("AUTH_TYPE"); }
unsigned long long request::content_length() { return atoll(conn_->getenv("CONTENT_LENGTH").c_str()); }
unsigned long long request::content_length() { return d->content_length; }
std::string request::content_type() { return conn_->getenv("CONTENT_TYPE"); }
std::string request::gateway_interface(){ return conn_->getenv("GATEWAY_INTERFACE"); }
std::string request::path_info() { return conn_->getenv("PATH_INFO"); }


+ 1
- 0
tests/multipart_parser_test.cpp View File

@@ -138,6 +138,7 @@ struct random_consumer {
buffer+=block;
size-=block;
if(res==cppcms::impl::multipart_parser::eof) {
TEST(start == end);
*files = parser->get_files();
return res;
}


Loading…
Cancel
Save