123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- /*
- * Copyright (C) 2011 Emweb bvba, Kessel-Lo, Belgium.
- *
- * See the LICENSE file for terms of use.
- */
- #include <Wt/WConfig.h>
- #ifdef WT_THREADED
- #include <boost/test/unit_test.hpp>
- #include <boost/thread.hpp>
- #include <boost/thread/condition.hpp>
- #include <Wt/WResource>
- #include <Wt/WServer>
- #include <Wt/WIOService>
- #include <Wt/Http/Client>
- #include <Wt/Http/Response>
- #include <Wt/Http/ResponseContinuation>
- #include <Wt/Http/Request>
- using namespace Wt;
- namespace {
- class TestResource : public WResource
- {
- public:
- TestResource()
- : continuation_(false),
- delaySendingBody_(false),
- haveEverMoreData_(false),
- haveRandomMoreData_(false),
- aborted_(0)
- { }
- virtual ~TestResource() {
- beingDeleted();
- }
- void useContinuation() {
- continuation_ = true;
- }
- void delaySendingBody() {
- delaySendingBody_ = true;
- }
- void haveEverMoreData() {
- haveEverMoreData_ = true;
- }
- void haveRandomMoreData() {
- haveRandomMoreData_ = true;
- }
- int abortedCount() const {
- return aborted_;
- }
- virtual void handleRequest(const Http::Request& request,
- Http::Response& response)
- {
- if (continuation_)
- handleWithContinuation(request, response);
- else
- handleSimple(request, response);
- }
- virtual void handleAbort(const Http::Request& request)
- {
- ++aborted_;
- }
- private:
- bool continuation_;
- bool delaySendingBody_;
- bool haveEverMoreData_;
- bool haveRandomMoreData_;
- int aborted_;
- void handleSimple(const Http::Request& request,
- Http::Response& response)
- {
- response.setStatus(200);
- response.out() << "Hello";
- }
- void handleWithContinuation(const Http::Request& request,
- Http::Response& response)
- {
- if (request.continuation()) {
- response.out() << "Hello";
- if (haveEverMoreData_ ||
- (haveRandomMoreData_ && (rand() % 10 != 0)))
- response.createContinuation();
- } else {
- response.setStatus(200);
- Http::ResponseContinuation *c = response.createContinuation();
- if (delaySendingBody_)
- c->waitForMoreData();
- }
- }
- };
- class Server : public WServer
- {
- public:
- Server() {
- int argc = 7;
- const char *argv[]
- = { "test",
- "--http-address", "127.0.0.1",
- "--http-port", "0",
- "--docroot", "."
- };
- setServerConfiguration(argc, (char **)argv);
- addResource(&resource_, "/test");
- }
- std::string address()
- {
- return "127.0.0.1:" + boost::lexical_cast<std::string>(httpPort());
- }
- TestResource& resource() { return resource_; }
- private:
- TestResource resource_;
- };
- class Client : public Http::Client
- {
- public:
- Client()
- : done_(false),
- abortAfterHeaders_(false)
- {
- done().connect(this, &Client::onDone);
- headersReceived().connect(this, &Client::onHeadersReceived);
- bodyDataReceived().connect(this, &Client::onDataReceived);
- }
- void abortAfterHeaders()
- {
- abortAfterHeaders_ = true;
- }
- void waitDone()
- {
- boost::mutex::scoped_lock guard(doneMutex_);
- while (!done_)
- doneCondition_.wait(guard);
- }
- void reset()
- {
- done_ = false;
- }
- bool isDone()
- {
- return done_;
- }
- void onDone(boost::system::error_code err, const Http::Message& m)
- {
- boost::mutex::scoped_lock guard(doneMutex_);
- err_ = err;
- message_ = m;
- done_ = true;
- doneCondition_.notify_one();
- }
- void onHeadersReceived(const Http::Message& m)
- {
- if (abortAfterHeaders_)
- abort();
- }
- void onDataReceived(const std::string& d)
- {
- }
- boost::system::error_code err() { return err_; }
- const Http::Message& message() { return message_; }
- private:
- bool done_;
- bool abortAfterHeaders_;
- boost::condition doneCondition_;
- boost::mutex doneMutex_;
- boost::system::error_code err_;
- Http::Message message_;
- };
- }
- BOOST_AUTO_TEST_CASE( http_client_server_test1 )
- {
- Server server;
- if (server.start()) {
- Client client;
- client.get("http://" + server.address() + "/test");
- client.waitDone();
- BOOST_REQUIRE(!client.err());
- BOOST_REQUIRE(client.message().status() == 200);
- BOOST_REQUIRE(client.message().body() == "Hello");
- }
- }
- BOOST_AUTO_TEST_CASE( http_client_server_test2 )
- {
- Server server;
- server.resource().useContinuation();
- if (server.start()) {
- Client client;
- client.get("http://" + server.address() + "/test");
- client.waitDone();
- BOOST_REQUIRE(!client.err());
- BOOST_REQUIRE(client.message().status() == 200);
- BOOST_REQUIRE(client.message().body() == "Hello");
- }
- }
- BOOST_AUTO_TEST_CASE( http_client_server_test3 )
- {
- Server server;
- server.resource().useContinuation();
- server.resource().delaySendingBody();
- server.resource().haveEverMoreData();
- if (server.start()) {
- Client client;
- client.abortAfterHeaders();
- client.get("http://" + server.address() + "/test");
- client.waitDone();
- BOOST_REQUIRE(client.err() == boost::asio::error::bad_descriptor);
- }
- server.resource().haveMoreData();
- boost::this_thread::sleep(boost::posix_time::milliseconds(50));
- BOOST_REQUIRE(server.resource().abortedCount() == 1);
- }
- BOOST_AUTO_TEST_CASE( http_client_server_test4 )
- {
- Server server;
- server.resource().useContinuation();
- server.resource().delaySendingBody();
- server.resource().haveRandomMoreData();
- int abortedCount = 0;
- if (server.start()) {
- std::vector<Client *> clients;
- for (unsigned i = 0; i < 1000; ++i) {
- Client *client = new Client();
- client->get("http://" + server.address() + "/test");
- clients.push_back(client);
- }
- for (;;) {
- bool alldone = true;
- for (unsigned i = 0; i < clients.size(); ++i) {
- if (!clients[i]->isDone()) {
- if (i % 100 == 0) {
- clients[i]->abort();
- ++abortedCount;
- }
- alldone = false;
- break;
- }
- }
- if (!alldone)
- server.resource().haveMoreData();
- else
- break;
- }
- for (unsigned i = 0; i < 1000; ++i) {
- delete clients[i];
- }
- }
- }
- #endif // WT_THREADED
|