Project

General

Profile

Bug #7093 » HttpClientServerTest.C

Marco Kinski, 07/03/2020 12:11 PM

 
1
/*
2
 * Copyright (C) 2011 Emweb bv, Herent, Belgium.
3
 *
4
 * See the LICENSE file for terms of use.
5
 */
6
#include <Wt/WConfig.h>
7

    
8
#ifdef WT_THREADED
9

    
10
#include <boost/test/unit_test.hpp>
11

    
12
#include <Wt/WResource.h>
13
#include <Wt/WServer.h>
14
#include <Wt/WIOService.h>
15
#include <Wt/Http/Client.h>
16
#include <Wt/Http/Response.h>
17
#include <Wt/Http/ResponseContinuation.h>
18
#include <Wt/Http/Request.h>
19

    
20
#include <chrono>
21
#include <condition_variable>
22
#include <mutex>
23
#include <thread>
24

    
25
using namespace Wt;
26

    
27
namespace {
28

    
29
  class TestRecursive : public WResource {
30
    public:
31
      TestRecursive ()
32
      { }
33

    
34
      virtual ~TestRecursive () {
35
        beingDeleted();
36
      }
37

    
38
      virtual void handleRequest(const Http::Request& request,
39
              Http::Response& response) override;
40

    
41
      std::function<std::string(void)> address_;
42
  };
43

    
44
  class TestResource : public WResource
45
  {
46
  public:
47
    TestResource()
48
      : continuation_(false),
49
	delaySendingBody_(false),
50
	haveEverMoreData_(false),
51
	haveRandomMoreData_(false),
52
	aborted_(0)
53
    { }
54

    
55
    virtual ~TestResource() {
56
      beingDeleted();
57
    }
58

    
59
    void useContinuation() {
60
      continuation_ = true;
61
    }
62

    
63
    void delaySendingBody() {
64
      delaySendingBody_ = true;
65
    }
66

    
67
    void haveEverMoreData() {
68
      haveEverMoreData_ = true;
69
    }
70

    
71
    void haveRandomMoreData() {
72
      haveRandomMoreData_ = true;
73
    }
74

    
75
    int abortedCount() const {
76
      return aborted_;
77
    }
78

    
79
    virtual void handleRequest(const Http::Request& request,
80
			       Http::Response& response) override
81
    {
82
      if (continuation_)
83
	handleWithContinuation(request, response);
84
      else
85
	handleSimple(request, response);
86
    }
87

    
88
    virtual void handleAbort(const Http::Request& request) override
89
    {
90
      ++aborted_;
91
    }
92

    
93
  private:
94
    bool continuation_;
95
    bool delaySendingBody_;
96
    bool haveEverMoreData_;
97
    bool haveRandomMoreData_;
98
    int aborted_;
99

    
100
    void handleSimple(const Http::Request& request,
101
		      Http::Response& response)
102
    {
103
      response.setStatus(200);
104
      response.out() << "Hello";
105
    }
106

    
107
    void handleWithContinuation(const Http::Request& request,
108
				Http::Response& response) 
109
    {
110
      if (request.continuation()) {
111
	response.out() << "Hello";
112
	if (haveEverMoreData_ ||
113
	    (haveRandomMoreData_ && (rand() % 10 != 0)))
114
	  response.createContinuation();
115
      } else {
116
	response.setStatus(200);
117
	Http::ResponseContinuation *c = response.createContinuation();
118
	if (delaySendingBody_)
119
	  c->waitForMoreData();
120
      }
121
    }
122
  };
123

    
124
  class Server : public WServer
125
  {
126
  public:
127
    Server() {
128
      int argc = 7;
129
      const char *argv[]
130
	= { "test",
131
	    "--http-address", "127.0.0.1",
132
	    "--http-port", "0",
133
	    "--docroot", "." 
134
          };
135
      setServerConfiguration(argc, (char **)argv);
136
      addResource(&resource_, "/test");
137
      addResource(&recursive_, "/recursive");
138

    
139
      recursive_.address_ = std::bind(&Server::address, this);
140
    }
141

    
142
    std::string address() 
143
    {
144
      return "127.0.0.1:" + std::to_string(httpPort());
145
    }
146

    
147
    TestResource& resource() { return resource_; }
148

    
149
  private:
150
    TestResource resource_;
151
    TestRecursive recursive_;
152
  };
153

    
154
  class Client : public Http::Client
155
  {
156
  public:
157
    Client()
158
      : done_(false),
159
	abortAfterHeaders_(false)
160
    { 
161
      done().connect(this, &Client::onDone);
162
      headersReceived().connect(this, &Client::onHeadersReceived);
163
      bodyDataReceived().connect(this, &Client::onDataReceived);
164
    }
165

    
166
    void abortAfterHeaders()
167
    {
168
      abortAfterHeaders_ = true;
169
    }
170

    
171
    void waitDone()
172
    {
173
      std::unique_lock<std::mutex> guard(doneMutex_);
174

    
175
      while (!done_)
176
	doneCondition_.wait(guard);
177
    }
178

    
179
    void reset() 
180
    {
181
      done_ = false;
182
    }
183

    
184
    bool isDone()
185
    {
186
      return done_;
187
    }
188

    
189
    void onDone(Wt::AsioWrapper::error_code err, const Http::Message& m)
190
    {
191
      std::unique_lock<std::mutex> guard(doneMutex_);
192

    
193
      err_ = err;
194
      message_ = m;
195

    
196
      done_ = true;
197
      doneCondition_.notify_one();
198
    }
199

    
200
    void onHeadersReceived(const Http::Message& m)
201
    {
202
      if (abortAfterHeaders_)
203
	abort();
204
    }
205

    
206
    void onDataReceived(const std::string& d)
207
    {
208
    }
209

    
210
    Wt::AsioWrapper::error_code err() { return err_; }
211
    const Http::Message& message() { return message_; }
212

    
213
  private:
214
    bool done_;
215
    bool abortAfterHeaders_;
216
    std::condition_variable doneCondition_;
217
    std::mutex doneMutex_;
218

    
219
    Wt::AsioWrapper::error_code err_;
220
    Http::Message message_;
221
  };
222

    
223

    
224
  void TestRecursive::handleRequest(const Http::Request& request,
225
          Http::Response& response) {
226

    
227
            Client client;
228
            client.get("http://" + address_() + "/test");
229
            client.waitDone();
230

    
231
            response.out() << client.message().body();
232
          }
233

    
234
}
235

    
236

    
237
BOOST_AUTO_TEST_CASE( http_client_server_recursive ) 
238
{
239
  Server server;
240

    
241
  if (server.start()) {
242
    for (int i = 0; i < 1000; ++i) {
243
      Client client;
244
      client.get("http://" + server.address() + "/recursive");
245
      client.waitDone();
246

    
247
      BOOST_REQUIRE(!client.err());
248
      BOOST_REQUIRE(client.message().status() == 200);
249
      BOOST_REQUIRE(client.message().body() == "Hello");    
250
    }
251
  }
252

    
253
}
254

    
255
#endif // WT_THREADED
256

    
257

    
258

    
259

    
260

    
261

    
262

    
(6-6/6)