Utils/t/multipart_parser_test.cpp
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// See accompanying file COPYING.TXT file for licensing details.
//
///////////////////////////////////////////////////////////////////////////////
//#define DEBUG_MULTIPART_PARSER
#include "multipart_parser.h"
#include <iostream>
#include "test.h"
#include <string.h>
#include <stdlib.h>
char const test_1_content[] = "multipart/form-data; boundary=xxyy";
char const test_1_file[] =
"--xxyy\r\n"
"Content-Disposition: form-data; name=\"test1\"; filename=\"foo.txt\"\r\n"
"Content-Type: text/plain\r\n"
"\r\n"
"hello\r\n"
"\r\n"
"--xxyy\r\n"
"Content-Disposition: form-data; name=\"test2\"\r\n"
"\r\n"
"שלום\r\n"
"--xxyy\r\n"
"Content-Disposition: form-data; name=\"test3\"\r\n"
"\r\n"
"x\r"
"\r\n--xxyy\r\n"
"Content-Disposition: form-data; name=\"test4\"\r\n"
"\r\n"
"x\r\n-"
"\r\n--xxyy\r\n"
"Content-Disposition: form-data; name=\"test5\"\r\n"
"\r\n"
"x\r\n--"
"\r\n--xxyy\r\n"
"Content-Disposition: form-data; name=\"test6\"\r\n"
"\r\n"
"x\r\n--x"
"\r\n--xxyy\r\n"
"Content-Disposition: form-data; name=\"test7\"\r\n"
"\r\n"
"x\r\n--x-"
"\r\n--xxyy--\r\n";
char const test_2_content[] = "multipart/form-data; boundary=-AbC";
char const test_2_file[] =
"---AbC\r\n"
"Content-Disposition: form-data; name=\"test1\" \r\n"
"\r\n"
"hello"
"\r\n"
"---AbC--\r\n";
std::string getcontent(std::istream &in)
{
std::string res;
while(!in.eof()) {
char c;
in.get(c);
if(in.gcount() == 1)
res+=c;
}
return res;
}
struct random_consumer {
random_consumer(int bs,cppcms::impl::multipart_parser &p,cppcms::impl::multipart_parser::files_type &f) :
block_size(bs),
parser(&p),
files(&f)
{
}
int block_size;
cppcms::impl::multipart_parser *parser;
cppcms::impl::multipart_parser::files_type *files;
cppcms::impl::multipart_parser::parsing_result_type operator()(char const *buffer,int size)
{
while(size > 0) {
int block = 1;
if(block_size > 1)
block = (rand() % (block_size-1) + 1);
else if(block_size < 0)
block=size;
if(block > size)
block=size;
cppcms::impl::multipart_parser::parsing_result_type res = parser->consume(buffer,block);
buffer+=block;
size-=block;
if(res==cppcms::impl::multipart_parser::eof) {
cppcms::impl::multipart_parser::files_type fblock = parser->get_files();
for(unsigned i=0;i<fblock.size();i++) {
files->push_back(fblock[i]);
}
return res;
}
if(res==cppcms::impl::multipart_parser::parsing_error)
return res;
if(res==cppcms::impl::multipart_parser::got_something) {
cppcms::impl::multipart_parser::files_type fblock = parser->get_files();
TEST(!fblock.empty());
for(unsigned i=0;i<fblock.size();i++) {
files->push_back(fblock[i]);
}
}
}
TEST(!"Never get there");
return cppcms::impl::multipart_parser::eof;
}
};
int main(int argc,char **argv)
{
if(argc!=2) {
std::cerr << "Required path to tests folder" << std::endl;
return 1;
}
try {
int block_size[]={ 1, -1, 5, 3, 10 };
int max_mem_size[] = { 0, 3, 10000 };
for(unsigned i=0;i<sizeof(block_size)/sizeof(block_size[0]);i++) {
for(unsigned j=0;j<sizeof(max_mem_size)/sizeof(max_mem_size[0]);j++) {
std::cout << "Testing for max-block-size = " << block_size[i] << " mem file size = " << max_mem_size[j] << std::endl;
{
cppcms::impl::multipart_parser parser("",max_mem_size[j]);
TEST(parser.set_content_type(std::string(test_1_content)));
cppcms::impl::multipart_parser::files_type files;
random_consumer c(block_size[i],parser,files);
TEST(c(test_1_file,strlen(test_1_file))==cppcms::impl::multipart_parser::eof);
TEST(files.size()==7);
TEST(files[0]->name()=="test1");
TEST(files[0]->filename()=="foo.txt");
TEST(files[0]->mime()=="text/plain");
std::string content = getcontent(files[0]->data());
TEST(content=="hello\r\n");
TEST(files[1]->name()=="test2");
TEST(files[1]->filename()=="");
TEST(files[1]->mime()=="");
TEST(getcontent(files[1]->data())=="שלום");
TEST(getcontent(files[2]->data())=="x\r");
TEST(getcontent(files[3]->data())=="x\r\n-");
TEST(getcontent(files[4]->data())=="x\r\n--");
TEST(getcontent(files[5]->data())=="x\r\n--x");
TEST(getcontent(files[6]->data())=="x\r\n--x-");
}
{
cppcms::impl::multipart_parser parser("",max_mem_size[j]);
TEST(parser.set_content_type(std::string(test_2_content)));
cppcms::impl::multipart_parser::files_type files;
random_consumer c(block_size[i],parser,files);
TEST(c(test_2_file,strlen(test_2_file))==cppcms::impl::multipart_parser::eof);
TEST(files.size()==1);
TEST(files[0]->name()=="test1");
TEST(files[0]->filename()=="");
TEST(files[0]->mime()=="");
std::string content = getcontent(files[0]->data());
TEST(content=="hello");
}
std::string boundaries[4]= {
"multipart/form-data; boundary=---------------------------11395741071221114234100471568",
"multipart/form-data; boundary=----WebKitFormBoundaryuYwgZwieYHQ3+AR8",
"multipart/form-data; boundary=----------jrFLC4hxayof1KyJEgmmCw",
"multipart/form-data; boundary=---------------------------7da3a5810028"
};
std::string filenames[4] = {
"firefox",
"chrome",
"opera",
"ie"
};
std::string location[2] = {
".",
""
};
for(int loc=0;loc<2;loc++) {
std::cout << "- location [" << location[loc] <<']'<< std::endl;
for(int i=0;i<4;i++) {
std::cout << "-- Browser " << filenames[i] << std::endl;
std::string file_name = std::string(argv[1])+"/multipart/" + filenames[i]+".txt";
std::ifstream file(file_name.c_str(),std::ifstream::binary);
if(!file) {
std::cerr << "Failed to open file " << file_name << std::endl;
return 1;
}
std::string content = getcontent(file);
cppcms::impl::multipart_parser parser(location[loc],max_mem_size[j]);
TEST(parser.set_content_type(boundaries[i]));
cppcms::impl::multipart_parser::files_type files;
random_consumer c(block_size[i],parser,files);
TEST(c(content.c_str(),content.size())==cppcms::impl::multipart_parser::eof);
TEST(files.size()==3);
TEST(files[0]->name()=="submit-name");
TEST(files[0]->mime()=="" && files[0]->filename().empty());
TEST(getcontent(files[0]->data())=="שלום");
TEST(files[1]->name()=="file");
TEST(files[1]->mime()=="text/plain");
if(i==3) // IE
TEST(files[1]->filename()=="z:\\tmp\\שלום.txt" || files[1]->filename()=="z:tmpשלום.txt");
else
TEST(files[1]->filename()=="שלום.txt");
TEST(getcontent(files[1]->data())=="שלום עולם!\n");
files[1]->save_to("test.txt");
{
std::ifstream tmp("test.txt");
TEST(tmp);
TEST(getcontent(tmp)=="שלום עולם!\n");
tmp.close();
std::remove("test.txt");
}
TEST(files[2]->name()=="submit");
TEST(files[2]->mime().empty());
TEST(files[2]->filename().empty());
TEST(getcontent(files[2]->data())=="Send");
}
}
}
}
}
catch(std::exception const &e) {
std::cerr << "Fail: " <<e.what() << std::endl;
return 1;
}
std::cout << "Ok" << std::endl;
return 0;
}