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