Skip to content

Commit e65cee7

Browse files
committed
Testing of filter added - incomplete yet
1 parent df2ac17 commit e65cee7

13 files changed

Lines changed: 597 additions & 39 deletions

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ set(ALL_TESTS
706706
hash_map_test
707707
response_test
708708
file_buffer_test
709+
filter_test
709710
)
710711

711712
if(NOT DISABLE_PREFORK_CACHE AND NOT IS_WINDOWS)

cppcms/applications_pool.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ namespace cppcms {
4444
namespace app {
4545
static const int synchronous = 0x0000; ///< Synchronous application
4646
static const int asynchronous = 0x0001; ///< Asynchronous application that operates in asynchronous mode
47-
// TBD
48-
//static const int content_filter = 0x0002; ///< Asynchronous application that validates incoming content during upload
4947

5048
static const int op_mode_mask = 0x000F; /// mask to select sync vs async flags
5149

cppcms/http_content_filter.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,11 @@ namespace http {
3333
/// Abort
3434
///
3535
abort_upload(int status_code);
36-
abort_upload(int status_code,std::string const &message);
3736
virtual ~abort_upload() throw();
3837

3938
int code() const;
40-
std::string message() const;
41-
4239
private:
4340
int code_;
44-
std::string message_;
4541
};
4642

4743

cppcms/http_context.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,56 @@ namespace cppcms {
190190
/// This function can be called from any thread
191191
///
192192
void submit_to_asynchronous_application(booster::intrusive_ptr<application> app,std::string const &matched_url);
193+
194+
private:
195+
struct holder { virtual ~holder() {} };
196+
template<typename T>
197+
struct specific_holder : public holder {
198+
specific_holder(T *ptr) : p(ptr) {}
199+
virtual ~specific_holder() {}
200+
booster::hold_ptr<T> p;
201+
};
202+
public:
203+
template<typename T>
204+
T *get_specific()
205+
{
206+
specific_holder<T> *sh=dynamic_cast<specific_holder<T> *>(get_holder());
207+
if(!sh)
208+
return 0;
209+
return sh->p.get();
210+
}
211+
template<typename T>
212+
void reset_specific(T *ptr = 0)
213+
{
214+
if(ptr == 0) {
215+
set_holder(0);
216+
return;
217+
}
218+
specific_holder<T> *sh=dynamic_cast<specific_holder<T> *>(get_holder());
219+
if(sh) {
220+
sh->p.reset(ptr);
221+
}
222+
else {
223+
specific_holder<T> *sh = new specific_holder<T>(ptr);
224+
set_holder(sh);
225+
}
226+
}
227+
template<typename T>
228+
T *release_specific()
229+
{
230+
T *r = 0;
231+
specific_holder<T> *sh=dynamic_cast<specific_holder<T> *>(get_holder());
232+
if(sh) {
233+
r = sh->p.release();
234+
}
235+
set_holder(0);
236+
return r;
237+
}
193238
private:
239+
240+
void set_holder(holder *p);
241+
holder *get_holder();
242+
194243
friend class impl::cgi::connection;
195244
int on_content_progress(size_t n);
196245
int on_headers_ready();

cppcms/http_request.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,19 +299,33 @@ namespace http {
299299
content_limits &limits();
300300

301301
///
302-
/// Get installed content filter
302+
/// Get installed content filter, returns 0 if it is not installed, no ownership is transfered
303303
///
304304
basic_content_filter *content_filter();
305305

306306
///
307-
/// Install content filter, setting it to 0 would remove the filter
307+
/// Installs content filter. If another filter installed it is removed
308308
///
309-
void content_filter(basic_content_filter *flt);
309+
void set_content_filter(basic_content_filter &flt);
310310

311+
///
312+
/// Installs new content filter (or removes existing), the ownership of new filter is transfered to the request object
313+
///
314+
void reset_content_filter(basic_content_filter *flt = 0);
315+
///
316+
/// Release existing content filter owned by request
317+
///
318+
basic_content_filter *release_content_filter();
311319
///
312320
/// Returns true when full request content is ready
313321
///
314322
bool is_ready();
323+
///
324+
/// Set the size of the buffer for content that isn't loaded to memory directly,
325+
/// like for example multipart/form-data, default is defined in configuration as
326+
/// service.input_buffer_size and defaults to 65536
327+
///
328+
void setbuf(int size);
315329
public:
316330
/// \cond INTERNAL
317331
request(impl::cgi::connection &);
@@ -321,6 +335,8 @@ namespace http {
321335
friend class context;
322336
friend class impl::cgi::connection;
323337

338+
void set_filter(basic_content_filter *ptr,bool owns);
339+
324340
int on_content_start();
325341
void on_error();
326342
int on_content_progress(size_t n);

private/cached_settings.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ namespace impl {
5555
std::string ip;
5656
int port;
5757
int output_buffer_size;
58+
int input_buffer_size;
5859
int async_output_buffer_size;
5960
bool disable_xpowered_by;
6061
bool disable_xpowered_by_version;
@@ -66,6 +67,7 @@ namespace impl {
6667
ip = v.get("service.ip","127.0.0.1");
6768
port = v.get("service.port",8080);
6869
output_buffer_size = v.get("service.output_buffer_size",16384);
70+
input_buffer_size = v.get("service.input_buffer_size",65536);
6971
async_output_buffer_size = v.get("service.async_output_buffer_size",1024);
7072
disable_xpowered_by = v.get("service.disable_xpowered_by",false);
7173
disable_xpowered_by_version = v.get("service.disable_xpowered_by_version",false);

src/cgi_api.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,10 @@ void connection::handle_http_error(int code,http::context *context,ehandler cons
257257
"</body>\r\n"
258258
"</html>\r\n";
259259
}
260+
else {
261+
booster::system::error_code e;
262+
context->response().flush_async_chunk(e);
263+
}
260264
async_write(booster::aio::buffer(async_chunk_),true,
261265
mfunc_to_event_handler(
262266
&connection::handle_http_error_eof,

src/http_content_filter.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,7 @@ namespace http {
1616

1717
abort_upload::abort_upload(int status_code) :
1818
cppcms_error(http::response::status_to_string(status_code)),
19-
code_(status_code),
20-
message_(http::response::status_to_string(status_code))
21-
{
22-
}
23-
24-
abort_upload::abort_upload(int status_code,std::string const &message):
25-
cppcms_error(message),
26-
code_(status_code),
27-
message_(message)
19+
code_(status_code)
2820
{
2921
}
3022

@@ -37,11 +29,6 @@ abort_upload::~abort_upload() throw()
3729
{
3830
}
3931

40-
std::string abort_upload::message() const
41-
{
42-
return message_;
43-
}
44-
4532
struct content_limits::_data {};
4633

4734
content_limits::content_limits(impl::cached_settings const &s) :

src/http_context.cpp

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ namespace http {
4242
booster::shared_ptr<application_specific_pool> pool;
4343
booster::intrusive_ptr<application> app;
4444
std::string matched;
45+
booster::hold_ptr<context::holder> specific;
4546
_data(context &cntx) :
4647
locale(cntx.connection().service().locale()),
4748
request(cntx.connection())
@@ -56,6 +57,15 @@ context::context(booster::shared_ptr<impl::cgi::connection> conn) :
5657
skin(service().views_pool().default_skin());
5758
}
5859

60+
void context::set_holder(holder *p)
61+
{
62+
d->specific.reset(p);
63+
}
64+
context::holder *context::get_holder()
65+
{
66+
return d->specific.get();
67+
}
68+
5969
std::string context::skin()
6070
{
6171
return d->skin;
@@ -264,7 +274,18 @@ void context::on_request_ready(bool error)
264274
app.swap(d->app);
265275

266276
if(error) {
267-
request().on_error();
277+
if(app) {
278+
try {
279+
context_guard g(*app,*this);
280+
request().on_error();
281+
}
282+
catch(std::exception const &e) {
283+
BOOSTER_ERROR("cppcms") << "exception at request::on_error" << e.what() << booster::trace(e);
284+
}
285+
catch(...) {
286+
BOOSTER_ERROR("cppcms") << "Unknown exception at request::on_error";
287+
}
288+
}
268289
return;
269290
}
270291

@@ -352,12 +373,19 @@ void context::dispatch(booster::intrusive_ptr<application> const &app,std::strin
352373
}
353374

354375
if(app->get_context()) {
355-
if(syncronous) {
356-
app->context().complete_response();
376+
try {
377+
if(syncronous) {
378+
app->context().complete_response();
379+
}
380+
else {
381+
app->context().async_complete_response();
382+
}
357383
}
358-
else {
359-
app->context().async_complete_response();
384+
catch(...) {
385+
app->release_context();
386+
throw;
360387
}
388+
app->release_context();
361389
}
362390
}
363391

src/http_request.cpp

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -131,38 +131,79 @@ struct request::_data {
131131
std::vector<char> post_data;
132132
content_limits limits;
133133
basic_content_filter *filter;
134+
bool filter_owned;
134135
bool filter_is_raw_content_filter;
135136
bool filter_is_multipart_filter;
136137
bool ready;
137138
long long content_length;
138139
long long read_size;
139140
bool read_full;
140141
bool no_on_error;
142+
int buffer_size;
141143
booster::hold_ptr<cppcms::impl::multipart_parser> multipart_parser;
142144
_data(cppcms::service &srv) :
143145
limits(srv.cached_settings()),
144146
filter(0),
147+
filter_owned(false),
145148
filter_is_raw_content_filter(false),
146149
filter_is_multipart_filter(false),
147150
ready(false),
148151
content_length(0),
149152
read_size(0),
150153
read_full(false),
151-
no_on_error(false)
154+
no_on_error(false),
155+
buffer_size(srv.cached_settings().service.input_buffer_size)
152156
{
153157
}
158+
~_data()
159+
{
160+
if(filter_owned)
161+
delete filter;
162+
}
154163
};
155164

165+
void request::setbuf(int size)
166+
{
167+
if(size < 1)
168+
size = 1;
169+
d->buffer_size = size;
170+
}
171+
156172
basic_content_filter *request::content_filter()
157173
{
158174
return d->filter;
159175
}
160176

161-
void request::content_filter(basic_content_filter *filter)
177+
void request::set_content_filter(basic_content_filter &flt)
162178
{
179+
set_filter(&flt,false);
180+
}
181+
void request::reset_content_filter(basic_content_filter *flt)
182+
{
183+
set_filter(flt,true);
184+
}
185+
basic_content_filter *request::release_content_filter()
186+
{
187+
if(d->filter_owned) {
188+
basic_content_filter *flt = d->filter;
189+
d->filter = 0;
190+
d->filter_owned = false;
191+
return flt;
192+
}
193+
d->filter = 0;
194+
return 0;
195+
}
196+
197+
void request::set_filter(basic_content_filter *filter,bool owned)
198+
{
199+
if(d->filter && d->filter != filter && d->filter_owned) {
200+
delete d->filter;
201+
d->filter = 0;
202+
}
163203
d->filter = filter;
164-
d->filter_is_multipart_filter = dynamic_cast<multipart_filter *>(filter) != 0;
165-
d->filter_is_raw_content_filter = dynamic_cast<raw_content_filter *>(filter) != 0;
204+
d->filter_owned = filter ? owned : false;
205+
d->filter_is_multipart_filter = dynamic_cast<multipart_filter *>(d->filter) != 0;
206+
d->filter_is_raw_content_filter = dynamic_cast<raw_content_filter *>(d->filter) != 0;
166207
}
167208

168209
bool request::is_ready()
@@ -180,9 +221,10 @@ std::pair<char *,size_t > request::get_buffer()
180221
}
181222
else {
182223
long long reminder = d->content_length - d->read_size;
183-
if(static_cast<long long>(d->post_data.size()) < reminder) {
184-
d->post_data.resize(d->content_length);
185-
}
224+
if(reminder < d->buffer_size)
225+
d->post_data.resize(reminder);
226+
else
227+
d->post_data.resize(d->buffer_size);
186228
if(d->post_data.size() == 0) {
187229
std::vector<char> tmp;
188230
tmp.swap(d->post_data);
@@ -339,6 +381,8 @@ int request::on_content_progress(size_t n)
339381

340382
void request::on_error()
341383
{
384+
if(d->no_on_error)
385+
return;
342386
if(d->filter) {
343387
d->filter->on_error();
344388
}
@@ -361,10 +405,6 @@ int request::on_content_start()
361405
d->read_full = true;
362406
}
363407
else {
364-
if(d->content_length < 65535)
365-
d->post_data.resize(d->content_length);
366-
else
367-
d->post_data.resize(65536);
368408
if(content_type_.is_multipart_form_data() && !d->filter_is_raw_content_filter) {
369409
d->multipart_parser.reset(new multipart_parser(
370410
d->limits.uploads_path(),
@@ -406,6 +446,8 @@ bool request::prepare()
406446
else
407447
d->content_length = atoll(s);
408448
content_type_ = cppcms::http::content_type(conn_->cgetenv("CONTENT_TYPE"));
449+
if(d->content_length == 0)
450+
d->ready = true;
409451
return true;
410452
}
411453

0 commit comments

Comments
 (0)