/////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) // // See accompanying file COPYING.TXT file for licensing details. // /////////////////////////////////////////////////////////////////////////////// //#define DEBUG_MULTIPART_PARSER #include #include "multipart_parser.h" #include #include "test.h" #include #include 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; } in.clear(); in.seekg(0); return res; } std::string getcontent(cppcms::http::file &file) { long long len = file.size(); std::string res = getcontent(file.data()); TEST(int(res.size()) == len); return res; } std::string getcontent(booster::shared_ptr const &p) { return getcontent(*p); } struct random_consumer { random_consumer(int bs,cppcms::impl::multipart_parser &p,cppcms::impl::multipart_parser::files_type &f,std::vector *cont = 0) : block_size(bs), parser(&p), files(&f), strings(cont) { } int block_size; cppcms::impl::multipart_parser *parser; cppcms::impl::multipart_parser::files_type *files; std::vector *strings; 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 = cppcms::impl::multipart_parser::continue_input; char const *start = buffer; char const *end = start + block; while(start != end) { res = parser->consume(start,end); TEST(start<=end); if(res == cppcms::impl::multipart_parser::meta_ready) { TEST(parser->has_file()); TEST(!parser->get_file().name().empty()); TEST(parser->get_file().size()==0); continue; } else if(res == cppcms::impl::multipart_parser::content_partial) { TEST(parser->has_file()); TEST(!parser->get_file().name().empty()); continue; } else if(res == cppcms::impl::multipart_parser::content_ready) { TEST(!parser->has_file()); if(strings) strings->push_back(getcontent(parser->last_file())); continue; } else break; } buffer+=block; size-=block; if(res==cppcms::impl::multipart_parser::eof) { TEST(start == end); *files = parser->get_files(); return res; } if(res==cppcms::impl::multipart_parser::parsing_error) { return res; } TEST( res==cppcms::impl::multipart_parser::continue_input || res==cppcms::impl::multipart_parser::meta_ready || res==cppcms::impl::multipart_parser::content_partial || res==cppcms::impl::multipart_parser::content_ready ); } 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, 1000 }; int max_mem_size[] = { 0, 3, 10000 }; for(unsigned i=0;i cts; random_consumer c(block_size[i],parser,files,&cts); 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]); TEST(content=="hello\r\n"); TEST(cts.at(0) == content); TEST(files[1]->name()=="test2"); TEST(files[1]->filename()==""); TEST(files[1]->mime()==""); TEST(getcontent(files[1])=="שלום"); TEST(cts.at(1)=="שלום"); TEST(getcontent(files[2])=="x\r"); TEST(getcontent(files[3])=="x\r\n-"); TEST(getcontent(files[4])=="x\r\n--"); TEST(getcontent(files[5])=="x\r\n--x"); TEST(getcontent(files[6])=="x\r\n--x-"); TEST(cts.at(6)=="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]); 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])=="שלום"); 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])=="שלום עולם!\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])=="Send"); } } } } } catch(std::exception const &e) { std::cerr << "Fail: " <