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
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
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
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 }
00259
00260 template<> template<>
00261 void HTTPServiceTestObject::test<4>()
00262 {
00263
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
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
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
00307 std::stringstream stream;
00308
00309
00310
00311
00312
00313
00314
00315
00316
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
00331
00332
00333 }