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