Imported Upstream version 17.6.1
[platform/upstream/libzypp.git] / tests / lib / WebServer.cc
1 #include <sstream>
2 #include <string>
3 #include "boost/version.hpp"
4
5 #if BOOST_VERSION >= 106800
6 #define BOOST_ERROR_CODE_HEADER_ONLY
7 #endif
8
9 #include "boost/bind.hpp"
10 #include "boost/thread.hpp"
11
12 #include "zypp/base/Logger.h"
13 #include "zypp/base/String.h"
14 #include "zypp/base/Exception.h"
15 #include "zypp/ExternalProgram.h"
16 #include "WebServer.h"
17
18 #include "mongoose.h"
19
20 using namespace zypp;
21 using namespace std;
22
23 #if ( BOOST_VERSION >= 105000 ) && ( BOOST_VERSION < 106800)
24 // https://svn.boost.org/trac/boost/ticket/7085
25 namespace boost
26 {
27   namespace system
28   {
29     class fake_error_category : public error_category
30     {
31       virtual const char *     name() const noexcept(true)
32       { return "falke_name"; }
33       virtual std::string      message( int ev ) const
34       { return "falke_message"; }
35     };
36     const error_category &  generic_category()
37     {
38       static fake_error_category _e;
39       return _e;
40       throw std::exception(/*"boost/ticket/7085 workaound sucks :("*/);
41     }
42     const error_category &  system_category()
43     {
44       static fake_error_category _e;
45       return _e;
46       throw std::exception(/*"boost/ticket/7085 workaound sucks :("*/);
47     }
48   }
49 }
50 #endif
51
52 static inline string hostname()
53 {
54     static char buf[256];
55     string result;
56     if (!::gethostname(buf, 255))
57         result += string(buf);
58     else
59         return "localhost";
60     return result;
61 }
62
63 #define WEBRICK 0
64
65 class WebServer::Impl
66 {
67 public:
68     Impl()
69     {}
70
71     virtual ~Impl()
72     {}
73
74     virtual string log() const
75     { return string(); }
76
77     virtual void start()
78     {}
79
80     virtual void stop()
81     {}
82
83     virtual void worker_thread()
84     {}
85
86     virtual int port() const
87     {
88         return 0;
89     }
90
91
92
93 private:
94     friend Impl * rwcowClone<Impl>( const Impl * rhs );
95     /** clone for RWCOW_pointer */
96     Impl * clone() const
97     { return new Impl( *this ); }
98 };
99
100 class WebServerWebrickImpl : public WebServer::Impl
101 {
102 public:
103     WebServerWebrickImpl(const Pathname &root, unsigned int port)
104         : _docroot(root), _port(port), _stop(false), _stopped(true)
105     {
106     }
107
108     ~WebServerWebrickImpl()
109     {
110         if ( ! _stopped )
111             stop();
112     }
113
114     virtual int port() const
115     {
116         return _port;
117     }
118
119
120     virtual void worker_thread()
121     {
122         _log.clear();
123
124         stringstream strlog(_log);
125
126         string webrick_code = str::form("require \"webrick\"; s = WEBrick::HTTPServer.new(:Port => %d, :DocumentRoot    => \"%s\"); trap(\"INT\"){ s.shutdown }; trap(\"SIGKILL\") { s.shutdown }; s.start;", _port, _docroot.c_str());
127
128         const char* argv[] =
129         {
130             "/usr/bin/ruby",
131             "-e",
132             webrick_code.c_str(),
133             NULL
134         };
135
136         ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
137         string line;
138
139         _stopped = false;
140
141         while ( ! _stop );
142
143         MIL << "Thread end requested" << endl;
144         //prog.close();
145         if ( prog.running() )
146             prog.kill();
147         MIL << "Thread about to finish" << endl;
148     }
149
150     virtual string log() const
151     {
152         return _log;
153     }
154
155     virtual void stop()
156     {
157         MIL << "Waiting for Webrick thread to finish" << endl;
158         _stop = true;
159         _thrd->join();
160         MIL << "Webrick thread finished" << endl;
161         _thrd.reset();
162         _stopped = true;
163     }
164
165     virtual void start()
166     {
167         //_thrd.reset( new boost::thread( boost::bind(&WebServerWebrickImpl::worker_thread, this) ) );
168     }
169
170     zypp::Pathname _docroot;
171     unsigned int _port;
172     zypp::shared_ptr<boost::thread> _thrd;
173     bool _stop;
174     bool _stopped;
175     std::string _log;
176 };
177
178 class WebServerMongooseImpl : public WebServer::Impl
179 {
180 public:
181     WebServerMongooseImpl(const Pathname &root, unsigned int port)
182         : _ctx(0L), _docroot(root)
183         , _port(port)
184         , _stopped(true)
185     {
186     }
187
188     ~WebServerMongooseImpl()
189     {
190         MIL << "Destroying web server" << endl;
191
192         if ( ! _stopped )
193             stop();
194     }
195
196     virtual void start()
197     {
198         if ( ! _stopped )
199         {
200             MIL << "mongoose server already running, stopping." << endl;
201             stop();
202         }
203
204         MIL << "Starting shttpd (mongoose)" << endl;
205         _log.clear();
206         _ctx = mg_start();
207
208         int ret = 0;
209         ret = mg_set_option(_ctx, "ports", str::form("%d", _port).c_str());
210         if (  ret != 1 )
211             ZYPP_THROW(Exception(str::form("Failed to set port: %d", ret)));
212
213         MIL << "Setting root directory to : '" << _docroot << "'" << endl;
214         ret = mg_set_option(_ctx, "root", _docroot.c_str());
215         if (  ret != 1 )
216             ZYPP_THROW(Exception(str::form("Failed to set docroot: %d", ret)));
217
218         _stopped = false;
219     }
220
221     virtual int port() const
222     {
223         return _port;
224     }
225
226
227     virtual string log() const
228     {
229         return _log;
230     }
231
232     virtual void stop()
233     {
234         MIL << "Stopping shttpd" << endl;
235         mg_stop(_ctx);
236         MIL << "shttpd finished" << endl;
237         _ctx = 0;
238         _stopped = true;
239     }
240
241     mg_context *_ctx;
242     zypp::Pathname _docroot;
243     unsigned int _port;
244     bool _stopped;
245     std::string _log;
246 };
247
248
249 WebServer::WebServer(const Pathname &root, unsigned int port)
250 #if WEBRICK
251     : _pimpl(new WebServerWebrickImpl(root, port))
252 #else
253     : _pimpl(new WebServerMongooseImpl(root, port))
254 #endif
255 {
256 }
257
258 void WebServer::start()
259 {
260     _pimpl->start();
261 }
262
263
264 std::string WebServer::log() const
265 {
266     return _pimpl->log();
267 }
268
269 int WebServer::port() const
270 {
271     return _pimpl->port();
272 }
273
274
275 Url WebServer::url() const
276 {
277     Url url;
278     url.setHost("localhost");
279     url.setPort(str::numstring(port()));
280     url.setScheme("http");
281     return url;
282 }
283
284 void WebServer::stop()
285 {
286     _pimpl->stop();
287 }
288
289 WebServer::~WebServer()
290 {
291 }
292
293