/
zOMGdev
/
cppcms
Обзор
Документация
Войти
/
zOMGdev
/
cppcms
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
tests/response_test.cpp
379 строк
9 KB
Artyom Beilis
Support of HTTP/1.1 - keep alive & chunked transfer encoding
05 сен 2020, 23:37
05 сен 2020, 23:37
3db1929
Код
Авторство
О чём код?
/////////////////////////////////////////////////////////////////////////////// // // 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/http_response.h> #include <cppcms/json.h> #include <cppcms/cache_interface.h> #include <cppcms/url_mapper.h> #include <cppcms/config.h> #include <cppcms/view.h> #include <string> #include <vector> #include <iomanip> #include "dummy_api.h" #include "test.h" #ifndef CPPCMS_NO_GZIP #include <zlib.h> #endif #include <iomanip> #include <sstream> void compare_strings(std::string const &l,std::string const &r,int file_line) { if(l==r) { //std::cerr << "[" << l << "] == [" << r << "]" << " at " << file_line << " OK !" << std::endl; return; } /* size_t m = l.size(); if(r.size() > m) m = r.size(); int line = 1; for(size_t i=0;i<m;i++) { std::string lstr = conv(l,i); std::string rstr = conv(r,i); if(lstr=="\\n") line++; std::cerr << std::setw(4) << line << " [" << lstr << '|' << rstr << "] "; if(lstr!=rstr) std::cerr << "<----------" << std::endl; else std::cerr << std::endl; }*/ std::cerr << "[" << l << "]!=[" << r << "]" << " at " << file_line << std::endl; throw std::runtime_error("Failed test"); } std::string remove_brakets(std::string const &in) { std::string r; for(size_t i=0;i<in.size();i++) if(in[i]!='[' && in[i]!=']') r+= in[i]; return r; } #define TEQ(l,r) compare_strings(l,r,__LINE__) #define TEQC(l,r) compare_strings(remove_brakets(l),remove_brakets(r),__LINE__) class test_app : public cppcms::application { public: test_app(cppcms::service &srv) : cppcms::application(srv), srv_(srv) { mapper().assign("foo","/foo"); mapper().assign("/"); mapper().assign("/{1}"); mapper().assign("/{1}/{2}"); } ~test_app() { release_context(); } void set_context(bool mark_chunks=false,bool mark_eof=false) { std::map<std::string,std::string> env; env["HTTP_HOST"]="www.example.com"; env["SCRIPT_NAME"]="/foo"; env["PATH_INFO"]="/bar"; env["REQUEST_METHOD"]="GET"; env["HTTP_ACCEPT_ENCODING"]="gzip"; booster::shared_ptr<dummy_api> api(new dummy_api(srv_,env,output_,mark_chunks,mark_eof)); booster::shared_ptr<cppcms::http::context> cnt(new cppcms::http::context(api)); assign_context(cnt); response().io_mode(cppcms::http::response::normal); output_.clear(); } std::string str() { std::string result = output_; output_.clear(); return result; } void ignore_headers() { size_t pos = output_.find("\r\n\r\n"); TEST(pos != std::string::npos); output_ = output_.substr(pos+4); } void test_buffer_size(bool async) { std::cout << "- Test setbuf/flush " << (async ? "async" : "sync")<< std::endl; set_context(true,true); if(async) { response().io_mode(cppcms::http::response::asynchronous); } else { response().io_mode(cppcms::http::response::nogzip); } response().full_asynchronous_buffering(false); response().out() << std::flush; response().setbuf(0); str(); response().out() << "x"; TEQ(str(),"[x]"); response().out() << 123; TEQC(str(),"[123]"); response().setbuf(4); response().out() << "abcdefg"; TEQ(str(),"[abcdefg]"); response().out() << 124; TEQ(str(),""); response().out() << std::flush; TEQ(str(),"[124]"); response().out() << '0'; TEQ(str(),""); response().out() << '1'; TEQ(str(),""); response().out() << '2'; TEQ(str(),""); response().out() << '3'; TEQ(str(),""); response().out() << '4'; TEQ(str(),"[01234]"); response().out() << "xxx"; response().setbuf(0); TEQ(str(),"[xxx]"); if(async) { response().setbuf(4); std::cout<< "-- fully/partially buffered mode" << std::endl; response().full_asynchronous_buffering(true); response().out() << "12345678"; TEQ(str(),""); response().out() << std::flush; TEQ(str(),""); response().full_asynchronous_buffering(false); TEQ(str(),"[12345678]"); response().full_asynchronous_buffering(true); response().out() << "123"; TEQ(str(),""); response().full_asynchronous_buffering(false); response().out() << std::flush; TEQ(str(),"[123]"); } response().finalize(); TEQ(str(),"[EOF]"); } void reset_context(bool async,bool gzip,bool set_cache) { set_context(false,false); if(async) { response().io_mode(cppcms::http::response::asynchronous); response().full_asynchronous_buffering(false); } else { if(!gzip) response().io_mode(cppcms::http::response::nogzip); } if(set_cache) cache().fetch_page("none"); response().out() << std::flush; ignore_headers(); } void test_io_error(bool async,bool gzip,bool cached) { std::cout << "- Test I/O errors " << (async ? "async" : "sync") << (gzip ? " gzip" : "") << (cached ? " cached" : "") << std::endl; reset_context(async,gzip,cached); response().setbuf(0); response().out() << "XXXXXXXXXXXXXXXX"; TEST(response().out()); response().out() << std::flush; TEST(response().out()); #ifndef CPPCMS_NO_GZIP if(gzip) { zsinit(); TEST(zstr() == "XXXXXXXXXXXXXXXX"); zs_done = true; zsdone(); } #endif output_="$$$ERROR$$$"; if(gzip || cached) { response().out() << "x" << std::flush; } else { response().out() << "x"; } TEST(!response().out()); reset_context(async,gzip,cached); response().setbuf(1024); response().out() << "XXXXXXXXXXXXXXXX"; TEST(response().out()); response().out() << std::flush; TEST(response().out()); output_="$$$ERROR$$$"; int i; std::cout << "--- error on stream... " << std::flush; for(i=0;i<=100000;i++) { response().out() << std::setw(9) << i << '\n'; if(!response().out()) break; } TEST(i<100000); std::cout << "Detected after " << (i*10) << " bytes " << std::endl; if(async) { reset_context(async,gzip,cached); response().setbuf(1024); response().out() << "xx" << std::flush; std::cout << "--- block on stream... " << std::flush; output_="$$$BLOCK$$$"; int i; for(i=0;i<=100000;i++) { response().out() << std::setw(9) << i << '\n'; TEST(response().out()); if(response().pending_blocked_output()) break; } TEST(i<100000); std::cout << "Detected after " << (i*10) << " bytes " << std::endl; } } #ifndef CPPCMS_NO_GZIP z_stream zs; bool zs_done; std::string total; std::string totalz; void zsinit() { memset(&zs,0,sizeof(zs)); inflateInit2(&zs,15+16); zs_done = false; total.clear(); totalz.clear(); } void zsdone() { TEST(zs_done == true); inflateEnd(&zs); } std::string zstr() { std::vector<char> out(4096); std::string s = str(); totalz += s; /* for(size_t i=0;i<totalz.size();i++) { std::cout << std::setfill('0') << std::setw(2) <<std::hex<< unsigned((unsigned char)totalz[i]); } std::cout << "->[" << total <<"]" << std::endl; */ if(zs_done) { TEST(s.empty()); return std::string(); } if(s.empty()) { return std::string(); } zs.avail_in = s.size(); zs.next_in = (Bytef*)s.c_str(); zs.avail_out = out.size(); zs.next_out = (Bytef*)&out[0]; int r = inflate(&zs,0); TEST(r==0 || r==Z_STREAM_END); std::string output; output.assign(&out[0],out.size() - zs.avail_out); if(r == Z_STREAM_END) zs_done = true; total += output; return output; } void test_gzipped(bool cached) { std::cout << "- Test gzip setbuf/flush " << (cached ? "cached" : "non cached")<< std::endl; set_context(false,false); if(cached) { cache().fetch_page("none"); } response().out() << std::flush; // We can't promice to flush headers only - gzip header may be written as well ignore_headers(); zsinit(); response().out() << "message"; TEQ(zstr(),""); response().out() << std::flush; TEQ(zstr(),"message"); response().setbuf(0); response().out() << "ABCD" << std::flush; TEQ(zstr(),"ABCD"); response().setbuf(2); response().out() << "XYZ" << std::flush; TEQ(zstr(),"XYZ"); response().setbuf(1024); response().out() << "11111111111111111111111111111111111" << std::flush; TEQ(zstr(),"11111111111111111111111111111111111"); response().out() << "x"; response().finalize(); TEQ(zstr(),"x"); zsdone(); std::string ztmp = totalz; std::string tmp = total; zsinit(); output_ = ztmp; TEST(tmp == zstr()); zsdone(); if(cached) { cache().store_page("p"); std::string ztmp2; TEST(cache().fetch_frame("_Z:p",ztmp2,true)); TEST(ztmp2 == ztmp); cache().rise("p"); } } #endif private: std::string output_; cppcms::service &srv_; }; int main() { try { cppcms::json::value cfg; cfg["cache"]["backend"]="thread_shared"; cfg["cache"]["limit"]=100; cppcms::service srv(cfg); test_app app(srv); app.test_buffer_size(false); app.test_buffer_size(true); //void test_io_error(bool async,bool gzip,bool cached) app.test_io_error(false,false,false); app.test_io_error(false,true,false); app.test_io_error(false,false,true); app.test_io_error(false,true,true); app.test_io_error(true,false,false); app.test_io_error(true,false,true); #ifndef CPPCMS_NO_GZIP app.test_gzipped(false); app.test_gzipped(true); #endif } catch(std::exception const &e) { std::cerr << "Fail " << e.what() << std::endl; return 1; } std::cout << "Ok" << std::endl; return 0; }