lliohttpserver_tut.cpp

Go to the documentation of this file.
00001 
00033 #include "linden_common.h"
00034 #include "lltut.h"
00035 #include "llbufferstream.h"
00036 #include "lliohttpserver.h"
00037 #include "llsdhttpserver.h"
00038 #include "llsdserialize.h"
00039 
00040 #include "llpipeutil.h"
00041 
00042 
00043 namespace tut
00044 {
00045         class HTTPServiceTestData
00046         {
00047         public:
00048                 class DelayedEcho : public LLHTTPNode
00049                 {
00050                         HTTPServiceTestData* mTester;
00051 
00052                 public:
00053                         DelayedEcho(HTTPServiceTestData* tester) : mTester(tester) { }
00054 
00055                         void post(ResponsePtr response, const LLSD& context, const LLSD& input) const
00056                         {
00057                                 ensure("response already set", mTester->mResponse == ResponsePtr(NULL));
00058                                 mTester->mResponse = response;
00059                                 mTester->mResult = input;
00060                         }
00061                 };
00062 
00063                 class WireHello : public LLIOPipe
00064                 {
00065                 protected:
00066                         virtual EStatus process_impl(
00067                                 const LLChannelDescriptors& channels,
00068                                 buffer_ptr_t& buffer,
00069                                 bool& eos,
00070                                 LLSD& context,
00071                                 LLPumpIO* pump)
00072                         {
00073                                 if(!eos) return STATUS_BREAK;
00074                                 LLSD sd = "yo!";
00075                                 LLBufferStream ostr(channels, buffer.get());
00076                                 ostr << LLSDXMLStreamer(sd);
00077                                 return STATUS_DONE;
00078                         }
00079                 };
00080 
00081                 HTTPServiceTestData()
00082                         : mResponse(NULL)
00083                 {
00084                         LLHTTPStandardServices::useServices();
00085                         LLHTTPRegistrar::buildAllServices(mRoot);
00086                         mRoot.addNode("/delayed/echo", new DelayedEcho(this));
00087                         mRoot.addNode("/wire/hello", new LLHTTPNodeForPipe<WireHello>);
00088                 }
00089                 
00090                 LLHTTPNode mRoot;
00091                 LLHTTPNode::ResponsePtr mResponse;
00092                 LLSD mResult;
00093 
00094                 void pumpPipe(LLPumpIO* pump, S32 iterations)
00095                 {
00096                         while(iterations > 0)
00097                         {
00098                                 pump->pump();
00099                                 pump->callback();
00100                                 --iterations;
00101                         }
00102                 }
00103 
00104                 std::string makeRequest(
00105                         const std::string& name,
00106                         const std::string& httpRequest,
00107                         bool timeout = false)
00108                 {
00109                         LLPipeStringInjector* injector = new LLPipeStringInjector(httpRequest);
00110                         LLPipeStringExtractor* extractor = new LLPipeStringExtractor();
00111                         
00112                         apr_pool_t* pool;
00113                         apr_pool_create(&pool, NULL);
00114 
00115                         LLPumpIO* pump;
00116                         pump = new LLPumpIO(pool);
00117 
00118                         LLPumpIO::chain_t chain;
00119                         LLSD context;
00120 
00121                         chain.push_back(LLIOPipe::ptr_t(injector));
00122                         LLIOHTTPServer::createPipe(chain, mRoot, LLSD());
00123                         chain.push_back(LLIOPipe::ptr_t(extractor));
00124 
00125                         pump->addChain(chain, DEFAULT_CHAIN_EXPIRY_SECS);
00126 
00127                         pumpPipe(pump, 10);
00128                         if(mResponse && (! timeout)) 
00129                         {
00130                                 mResponse->result(mResult);
00131                                 mResponse = NULL;
00132                         }
00133                         pumpPipe(pump, 10);
00134                         
00135                         std::string httpResult = extractor->string();
00136 
00137                         chain.clear();
00138                         delete pump;
00139                         apr_pool_destroy(pool);
00140 
00141                         if(mResponse && timeout)
00142                         {
00143                                 mResponse->result(mResult);
00144                                 mResponse = NULL;
00145                         }
00146                         
00147                         return httpResult;
00148                 }
00149                 
00150                 std::string httpGET(const std::string& uri, 
00151                                                         bool timeout = false)
00152                 {
00153                         std::string httpRequest = "GET " + uri + " HTTP/1.0\r\n\r\n";
00154                         return makeRequest(uri, httpRequest, timeout);
00155                 }
00156                 
00157                 std::string httpPOST(const std::string& uri,
00158                         const std::string& body,
00159                         bool timeout,
00160                         const std::string& evilExtra = "")
00161                 {
00162                         std::ostringstream httpRequest;
00163                         httpRequest << "POST " + uri + " HTTP/1.0\r\n";
00164                         httpRequest << "Content-Length: " << body.size() << "\r\n";
00165                         httpRequest << "\r\n";
00166                         httpRequest << body;
00167                         httpRequest << evilExtra;
00168                                 
00169                         return makeRequest(uri, httpRequest.str(), timeout);
00170                 }
00171 
00172                 std::string httpPOST(const std::string& uri,
00173                         const std::string& body,
00174                         const std::string& evilExtra = "")
00175                 {
00176                         bool timeout = false;
00177                         return httpPOST(uri, body, timeout, evilExtra);
00178                 }
00179         };
00180 
00181         typedef test_group<HTTPServiceTestData>         HTTPServiceTestGroup;
00182         typedef HTTPServiceTestGroup::object            HTTPServiceTestObject;
00183         HTTPServiceTestGroup httpServiceTestGroup("http service");
00184 
00185         template<> template<>
00186         void HTTPServiceTestObject::test<1>()
00187         {
00188                 std::string result = httpGET("web/hello");
00189                 
00190                 ensure_starts_with("web/hello status", result,
00191                         "HTTP/1.0 200 OK\r\n");
00192                                                 
00193                 ensure_contains("web/hello content type", result,
00194                         "Content-Type: application/xml\r\n");
00195 
00196                 ensure_contains("web/hello content length", result,
00197                         "Content-Length: 36\r\n");
00198 
00199                 ensure_contains("web/hello content", result,
00200                         "\r\n"
00201                         "<llsd><string>hello</string></llsd>"
00202                         );
00203         }
00204         
00205         template<> template<>
00206         void HTTPServiceTestObject::test<2>()
00207         {
00208                 // test various HTTP errors
00209                 
00210                 std::string actual;
00211 
00212                 actual = httpGET("web/missing");
00213                 ensure_starts_with("web/missing 404", actual,
00214                         "HTTP/1.0 404 Not Found\r\n");
00215 
00216                 actual = httpGET("web/echo");                   
00217                 ensure_starts_with("web/echo 405", actual,
00218                         "HTTP/1.0 405 Method Not Allowed\r\n");
00219         }
00220         
00221         template<> template<>
00222         void HTTPServiceTestObject::test<3>()
00223         {
00224                 // test POST & content-length handling
00225                 
00226                 std::string result;
00227                 
00228                 result = httpPOST("web/echo",
00229                         "<llsd><integer>42</integer></llsd>");
00230                         
00231                 ensure_starts_with("web/echo status", result,
00232                         "HTTP/1.0 200 OK\r\n");
00233                                                 
00234                 ensure_contains("web/echo content type", result,
00235                         "Content-Type: application/xml\r\n");
00236 
00237                 ensure_contains("web/echo content length", result,
00238                         "Content-Length: 35\r\n");
00239 
00240                 ensure_contains("web/hello content", result,
00241                         "\r\n"
00242                         "<llsd><integer>42</integer></llsd>"
00243                         );
00244 
00245 /* TO DO: this test doesn't pass!!
00246                 
00247                 result = httpPOST("web/echo",
00248                         "<llsd><string>evil</string></llsd>",
00249                         "really!  evil!!!");
00250                         
00251                 ensure_equals("web/echo evil result", result,
00252                         "HTTP/1.0 200 OK\r\n"
00253                         "Content-Length: 34\r\n"
00254                         "\r\n"
00255                         "<llsd><string>evil</string></llsd>"
00256                         );
00257 */
00258         }
00259 
00260         template<> template<>
00261         void HTTPServiceTestObject::test<4>()
00262         {
00263                 // test calling things based on pipes
00264 
00265                 std::string result;
00266 
00267                 result = httpGET("wire/hello");
00268 
00269                 ensure_contains("wire/hello", result, "yo!");
00270         }
00271 
00272     template<> template<>
00273         void HTTPServiceTestObject::test<5>()
00274     {
00275                 // test timeout before async response
00276                 std::string result;
00277 
00278                 bool timeout = true;
00279                 result = httpPOST("delayed/echo",
00280                         "<llsd><string>agent99</string></llsd>", timeout);
00281 
00282                 ensure_equals("timeout delayed/echo status", result, std::string(""));
00283         }
00284 
00285         template<> template<>
00286         void HTTPServiceTestObject::test<6>()
00287         {
00288                 // test delayed service         
00289                 std::string result;
00290                 
00291                 result = httpPOST("delayed/echo",
00292                         "<llsd><string>agent99</string></llsd>");
00293                         
00294                 ensure_starts_with("delayed/echo status", result,
00295                         "HTTP/1.0 200 OK\r\n");
00296                                                 
00297                 ensure_contains("delayed/echo content", result,
00298                         "\r\n"
00299                         "<llsd><string>agent99</string></llsd>"
00300                         );
00301         }
00302 
00303         template<> template<>
00304         void HTTPServiceTestObject::test<7>()
00305         {
00306                 // test large request
00307                 std::stringstream stream;
00308 
00309                 //U32 size = 36 * 1024 * 1024;
00310                 //U32 size = 36 * 1024;
00311                 //std::vector<char> data(size);
00312                 //memset(&(data[0]), '1', size);
00313                 //data[size - 1] = '\0';
00314 
00315                 
00316                 //std::string result = httpPOST("web/echo", &(data[0]));
00317 
00318                 stream << "<llsd><array>";
00319                 for(U32 i = 0; i < 1000000; ++i)
00320                 {
00321                         stream << "<integer>42</integer>";
00322                 }
00323                 stream << "</array></llsd>";
00324                 llinfos << "HTTPServiceTestObject::test<7>"
00325                                 << stream.str().length() << llendl;
00326                 std::string result = httpPOST("web/echo", stream.str());
00327                 ensure_starts_with("large echo status", result, "HTTP/1.0 200 OK\r\n");
00328         }
00329 
00330         /* TO DO:
00331                 test generation of not found and method not allowed errors
00332         */
00333 }

Generated on Fri May 16 08:34:29 2008 for SecondLife by  doxygen 1.5.5