///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// See accompanying file COPYING.TXT file for licensing details.
//
///////////////////////////////////////////////////////////////////////////////
#include <cppcms/service.h>
#include <cppcms/application.h>
#include <cppcms/applications_pool.h>
#include <cppcms/http_request.h>
#include <cppcms/http_response.h>
#include <cppcms/http_content_filter.h>
#include <cppcms/http_context.h>
#include <cppcms/http_file.h>
#include <cppcms/url_dispatcher.h>
#include <cppcms/mount_point.h>
#include <booster/aio/deadline_timer.h>
#include <booster/posix_time.h>
#include <cppcms/json.h>
#include <booster/thread.h>
#include <iostream>
#include "client.h"
#include <sstream>
#include <booster/log.h>
#include "test.h"
int g_fail;
int total_on_error;
#define TESTNT(x) do { if(x) break; std::cerr << "FAIL: " #x " in line: " << __LINE__ << std::endl; g_fail = 1; return; } while(0)
class file_test : public cppcms::application, public cppcms::http::multipart_filter {
public:
file_test(cppcms::service &s) : cppcms::application(s)
{
}
std::string get_ref(std::string const &name)
{
int len = atoi(request().get("l_" + name).c_str());
char c = request().get("f_" + name).c_str()[0];
std::string r;
r.reserve(len);
for(int i=0;i<len;i++) {
r += c;
c++;
if(c>'z')
c='a';
}
return r;
}
struct test_data {
int on_new_file;
int on_upload_progress;
int on_data_ready;
int on_end_of_content;
int on_error;
void write(std::ostream &out)
{
out <<
"on_new_file="<<on_new_file<<"\n"
"on_upload_progress="<<on_upload_progress<<"\n"
"on_data_ready="<<on_data_ready<<"\n"
"on_end_of_content="<<on_end_of_content<<"\n"
;
}
};
test_data *data()
{
return context().get_specific<test_data>();
}
void on_new_file(cppcms::http::file &input_file)
{
data()->on_new_file++;
TESTNT(input_file.size() == 0);
std::string loc;
if((loc=request().get("save_to_"+input_file.name()))!="") {
std::cerr << "Saving to " << loc << std::endl;
input_file.output_file(loc);
}
if(request().get("abort")=="on_new_file" && input_file.name() == request().get("at"))
do_abort(502);
}
void on_upload_progress(cppcms::http::file &input_file)
{
data()->on_upload_progress++;
TESTNT(input_file.size() > 0);
std::string ref = get_ref(input_file.name());
TESTNT(size_t(input_file.size()) << ref.size());
std::ostringstream ss;
input_file.data().seekg(0);
ss<<input_file.data().rdbuf();
std::string r = ss.str();
TESTNT(r.size() == size_t(input_file.size()));
//std::cerr << "\n\nRef=" << ref << std::endl;
//std::cerr << "Res=" << r << "\n\n" << std::endl;
TESTNT(ref.substr(0,r.size())==r);
if(request().get("abort")=="on_upload_progress" && input_file.name() == request().get("at"))
do_abort(503);
}
void on_data_ready(cppcms::http::file &input_file) {
data()->on_data_ready++;
std::string ref = get_ref(input_file.name());
TESTNT(size_t(input_file.size()) == ref.size());
std::ostringstream ss;
input_file.data().seekg(0);
ss<<input_file.data().rdbuf();
std::string r = ss.str();
TESTNT(r.size() == size_t(input_file.size()));
TESTNT(ref==r);
if(request().get("abort")=="on_data_ready" && input_file.name() == request().get("at"))
do_abort(504);
}
void on_end_of_content(){
data()->on_end_of_content++;
TESTNT(request().get("fail")=="");
if(request().get("abort")=="on_end_of_content")
do_abort(505);
}
void on_error() {
data()->on_error++;
TESTNT(request().get("fail")=="1");
total_on_error++;
}
void do_abort(int code)
{
int how=atoi(request().get("how").c_str());
switch(how){
case 3:
response().setbuf(0);
case 2:
response().full_asynchronous_buffering(false);
case 1:
response().status(code);
response().set_plain_text_header();
response().out() << "at="<<request().get("abort");
case 0:
throw cppcms::http::abort_upload(code);
}
}
void main(std::string path)
{
if(path=="/total_on_error") {
response().out() << "total_on_error=" << total_on_error;
total_on_error = 0;
return;
}
if(path=="/no_content") {
TESTNT(request().is_ready());
response().out() << "no_content=1";
return;
}
if(request().get("setbuf")!="") {
request().setbuf(atoi(request().get("setbuf").c_str()));
}
TESTNT(request().is_ready() || context().get_specific<test_data>()==0);
if(!request().is_ready()) {
test_data *td = new test_data();
context().reset_specific<test_data>(td);
if(request().get("abort")=="on_headers_ready")
do_abort(501);
request().set_content_filter(*this);
std::string cl_limit,mp_limit;
if((cl_limit=request().get("cl_limit"))!="")
request().limits().content_length_limit(atoi(cl_limit.c_str()));
if((mp_limit=request().get("mp_limit"))!="")
request().limits().multipart_form_data_limit(atoi(mp_limit.c_str()));
}
else {
test_data *td = context().get_specific<test_data>();
TESTNT(td);
if(request().get("abort")=="") {
TESTNT(td->on_error == 0);
TESTNT(td->on_end_of_content == 1);
TESTNT(td->on_new_file == td->on_data_ready);
if(request().content_type_parsed().is_multipart_form_data())
TESTNT(td->on_new_file == int(request().post().size() + request().files().size()));
if(request().get("chunks")!="")
TESTNT(td->on_upload_progress != 0);
}
td->write(response().out());
response().out() <<
"files=" << request().files().size() << "\n"
"post=" << request().post().size() << "\n"
"total=" << request().files().size() + request().post().size() << "\n"
;
}
}
};
int main(int argc,char **argv)
{
try {
using cppcms::mount_point;
cppcms::service srv(argc,argv);
srv.applications_pool().mount( cppcms::create_pool<file_test>(),
mount_point("/upload"),
cppcms::app::asynchronous | cppcms::app::content_filter);
srv.after_fork(submitter(srv));
srv.run();
}
catch(std::exception const &e) {
std::cerr << e.what() << booster::trace(e) << std::endl;
return EXIT_FAILURE;
}
if(run_ok && !g_fail) {
std::cout << "Full Test: Ok" << std::endl;
return EXIT_SUCCESS;
}
else {
std::cout << "FAILED" << std::endl;
return EXIT_FAILURE;
}
}