RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
soa/service/testing/http_long_header_test.cc
00001 /* http_long_header_test.cc
00002    Jeremy Barnes, 31 January 2011
00003    Copyright (c) 2011 Datacratic.  All rights reserved.
00004 
00005    Test that we can't crash the server sending long headers.
00006 */
00007 
00008 #define BOOST_TEST_MAIN
00009 #define BOOST_TEST_DYN_LINK
00010 
00011 #include <boost/test/unit_test.hpp>
00012 #include "soa/service/http_endpoint.h"
00013 #include "soa/service/active_endpoint.h"
00014 #include "soa/service/passive_endpoint.h"
00015 #include <sys/socket.h>
00016 #include "jml/utils/guard.h"
00017 #include "jml/utils/filter_streams.h"
00018 #include "jml/arch/exception_handler.h"
00019 #include "jml/utils/testing/watchdog.h"
00020 #include "jml/utils/testing/fd_exhauster.h"
00021 #include "test_connection_error.h"
00022 
00023 using namespace std;
00024 using namespace ML;
00025 using namespace Datacratic;
00026 
00027 #define BOOST_TEST_MAIN
00028 #define BOOST_TEST_DYN_LINK
00029 
00030 #include <boost/test/unit_test.hpp>
00031 #include "soa/service/http_endpoint.h"
00032 #include "soa/service/active_endpoint.h"
00033 #include "soa/service/passive_endpoint.h"
00034 #include <sys/socket.h>
00035 #include "jml/utils/guard.h"
00036 #include "jml/arch/exception_handler.h"
00037 #include "jml/utils/testing/watchdog.h"
00038 #include "jml/utils/testing/fd_exhauster.h"
00039 #include <poll.h>
00040 
00041 using namespace std;
00042 using namespace ML;
00043 using namespace Datacratic;
00044 
00045 
00046 BOOST_AUTO_TEST_CASE( test_accept_speed )
00047 {
00048     Watchdog watchdog(5.0);
00049 
00050     string connectionError;
00051 
00052     PassiveEndpointT<SocketTransport> acceptor("acceptor");
00053 
00054     string error;
00055     
00056     struct TestHandler : HttpConnectionHandler {
00057 
00058         TestHandler(string & error)
00059             : bytesDone(0), error(error)
00060         {
00061         }
00062 
00063         int bytesDone;
00064         string & error;
00065 
00066         virtual void handleData(const std::string & data)
00067         {
00068 
00069             bytesDone += data.size();
00070             if (bytesDone > 1000000)
00071                 throw ML::Exception("allowed infinite headers");
00072             HttpConnectionHandler::handleData(data);
00073         }
00074 
00075         virtual void handleError(const std::string & error)
00076         {
00077             cerr << "got error " << error << endl;
00078             this->error = error;
00079         }
00080 
00081         virtual void
00082         handleHttpHeader(const HttpHeader & header)
00083         {
00084             
00085             cerr << "got header " << header << endl;
00086         }
00087 
00088         virtual void handleHttpChunk(const HttpHeader & header,
00089                                      const std::string & chunkHeader,
00090                                      const std::string & chunk)
00091         {
00092             cerr << "chunkHeader " << chunkHeader << endl;
00093             //cerr << "chunk has " << chunk.length() << " bytes" << endl;
00094         }
00095 
00096     };
00097 
00098     acceptor.onMakeNewHandler = [&] ()
00099         {
00100             return ML::make_std_sp(new TestHandler(error));
00101         };
00102     
00103     int port = acceptor.init();
00104 
00105     cerr << "port = " << port << endl;
00106 
00107     BOOST_CHECK_EQUAL(acceptor.numConnections(), 0);
00108 
00109     Date before = Date::now();
00110 
00111     /* Open a connection */
00112     int s = socket(AF_INET, SOCK_STREAM, 0);
00113     if (s == -1)
00114         throw Exception("socket");
00115 
00116     //cerr << "i = " << i << " s = " << s << " sockets.size() = "
00117     //     << sockets.size() << endl;
00118 
00119     struct sockaddr_in addr = { AF_INET, htons(port), { INADDR_ANY } }; 
00120     //cerr << "before connect on " << s << endl;
00121     int res = connect(s, reinterpret_cast<const sockaddr *>(&addr),
00122                       sizeof(addr));
00123     //cerr << "after connect on " << s << endl;
00124 
00125     if (res == -1) {
00126         cerr << "connect error: " << strerror(errno) << endl;
00127         close(s);
00128     }
00129 
00130     /* Try to write 32MB of headers into the socket. */
00131     const char * buf = "header: 9012345678901234567890\r\n";
00132 
00133     int written = 0;
00134     int writeError = 0;
00135 
00136     for (unsigned i = 0;  i < 1000000;  ++i) {
00137         int res = write(s, buf, strlen(buf));
00138         if (res > 0)
00139             written += res;
00140         else if (res == 0)
00141             throw ML::Exception("nothing written");
00142         else {
00143             writeError = errno;
00144             cerr << strerror(errno) << endl;
00145             cerr << "error after writing " << written << " bytes"
00146                  << endl;
00147             break;
00148         }
00149     }
00150 
00151     // Check we didn't write more than 1MB before the error...
00152     BOOST_CHECK_LT(written, 1000000);
00153     BOOST_CHECK_EQUAL(writeError, ECONNRESET);
00154     BOOST_CHECK_NE(error.find("HTTP header exceeds"), string::npos);
00155 
00156     cerr << "wrote " << written << " bytes" << endl;
00157 
00158     close(s);
00159 
00160     acceptor.shutdown();
00161 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator