Imported Upstream version 14.45.0
[platform/upstream/libzypp.git] / tests / lib / WebServer.cc
index 1b6d9e4..145f56e 100644 (file)
 
-#include <sys/types.h>
-#include <sys/select.h>
-#include <sys/wait.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <string.h>
+#include <sstream>
+#include <string>
+#include "boost/bind.hpp"
+#include "boost/thread.hpp"
+#include "boost/version.hpp"
 
-#include "zypp/ZYpp.h"
+#include "zypp/base/Logger.h"
+#include "zypp/base/String.h"
+#include "zypp/base/Exception.h"
+#include "zypp/ExternalProgram.h"
+#include "WebServer.h"
 
-using namespace zypp;
+#include "mongoose.h"
 
-#include "shttpd.h"
-#include "boost/bind.hpp"
-#include "WebServer.h"
+using namespace zypp;
+using namespace std;
 
-#define LISTENING_PORT "8080"
+#if ( BOOST_VERSION >= 105000 )
+// https://svn.boost.org/trac/boost/ticket/7085
+namespace boost
+{
+  namespace system
+  {
+    class fake_error_category : public error_category
+    {
+      virtual const char *     name() const noexcept(true)
+      { return "falke_name"; }
+      virtual std::string      message( int ev ) const
+      { return "falke_message"; }
+    };
+    const error_category &  generic_category()
+    {
+      static fake_error_category _e;
+      return _e;
+      throw std::exception(/*"boost/ticket/7085 workaound sucks :("*/);
+    }
+    const error_category &  system_category()
+    {
+      static fake_error_category _e;
+      return _e;
+      throw std::exception(/*"boost/ticket/7085 workaound sucks :("*/);
+    }
+  }
+}
+#endif
 
-static shttpd_ctx * do_init_ctx()
+static inline string hostname()
 {
-    static char *argv[] = {"a", "-ports", LISTENING_PORT, NULL};
-    static int argc = sizeof(argv) / sizeof(argv[0]) - 1;
-    shttpd_ctx *ctx;
-    
-    ctx = shttpd_init(argc, argv);
-    return ctx;
+    static char buf[256];
+    string result;
+    if (!::gethostname(buf, 255))
+        result += string(buf);
+    else
+        return "localhost";
+    return result;
 }
 
-WebServer::WebServer(const Pathname root, unsigned int port)
-    : _docroot(root), _port(port), _stop(false)
+#define WEBRICK 0
+
+class WebServer::Impl
+{
+public:
+    Impl()
+    {}
+
+    virtual ~Impl()
+    {}
+
+    virtual string log() const
+    { return string(); }
+
+    virtual void start()
+    {}
+
+    virtual void stop()
+    {}
+
+    virtual void worker_thread()
+    {}
+
+    virtual int port() const
+    {
+        return 0;
+    }
+
+
+
+private:
+    friend Impl * rwcowClone<Impl>( const Impl * rhs );
+    /** clone for RWCOW_pointer */
+    Impl * clone() const
+    { return new Impl( *this ); }
+};
+
+class WebServerWebrickImpl : public WebServer::Impl
+{
+public:
+    WebServerWebrickImpl(const Pathname &root, unsigned int port)
+        : _docroot(root), _port(port), _stop(false), _stopped(true)
+    {
+    }
+
+    ~WebServerWebrickImpl()
+    {
+        if ( ! _stopped )
+            stop();
+    }
+
+    virtual int port() const
+    {
+        return _port;
+    }
+
+
+    virtual void worker_thread()
+    {
+        _log.clear();
+
+        stringstream strlog(_log);
+
+        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());
+
+        const char* argv[] =
+        {
+            "/usr/bin/ruby",
+            "-e",
+            webrick_code.c_str(),
+            NULL
+        };
+
+        ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
+        string line;
+
+        _stopped = false;
+
+        while ( ! _stop );
+
+        MIL << "Thread end requested" << endl;
+        //prog.close();
+        if ( prog.running() )
+            prog.kill();
+        MIL << "Thread about to finish" << endl;
+    }
+
+    virtual string log() const
+    {
+        return _log;
+    }
+
+    virtual void stop()
+    {
+        MIL << "Waiting for Webrick thread to finish" << endl;
+        _stop = true;
+        _thrd->join();
+        MIL << "Webrick thread finished" << endl;
+        _thrd.reset();
+        _stopped = true;
+    }
+
+    virtual void start()
+    {
+        //_thrd.reset( new boost::thread( boost::bind(&WebServerWebrickImpl::worker_thread, this) ) );
+    }
+
+    zypp::Pathname _docroot;
+    unsigned int _port;
+    zypp::shared_ptr<boost::thread> _thrd;
+    bool _stop;
+    bool _stopped;
+    std::string _log;
+};
+
+class WebServerMongooseImpl : public WebServer::Impl
+{
+public:
+    WebServerMongooseImpl(const Pathname &root, unsigned int port)
+        : _ctx(0L), _docroot(root)
+        , _port(port)
+        , _stopped(true)
+    {
+    }
+
+    ~WebServerMongooseImpl()
+    {
+        MIL << "Destroying web server" << endl;
+
+        if ( ! _stopped )
+            stop();
+    }
+
+    virtual void start()
+    {
+        if ( ! _stopped )
+        {
+            MIL << "mongoose server already running, stopping." << endl;
+            stop();
+        }
+
+        MIL << "Starting shttpd (mongoose)" << endl;
+        _log.clear();
+        _ctx = mg_start();
+
+        int ret = 0;
+        ret = mg_set_option(_ctx, "ports", str::form("%d", _port).c_str());
+        if (  ret != 1 )
+            ZYPP_THROW(Exception(str::form("Failed to set port: %d", ret)));
+
+        MIL << "Setting root directory to : '" << _docroot << "'" << endl;
+        ret = mg_set_option(_ctx, "root", _docroot.c_str());
+        if (  ret != 1 )
+            ZYPP_THROW(Exception(str::form("Failed to set docroot: %d", ret)));
+
+        _stopped = false;
+    }
+
+    virtual int port() const
+    {
+        return _port;
+    }
+
+
+    virtual string log() const
+    {
+        return _log;
+    }
+
+    virtual void stop()
+    {
+        MIL << "Stopping shttpd" << endl;
+        mg_stop(_ctx);
+        MIL << "shttpd finished" << endl;
+        _ctx = 0;
+        _stopped = true;
+    }
+
+    mg_context *_ctx;
+    zypp::Pathname _docroot;
+    unsigned int _port;
+    bool _stopped;
+    std::string _log;
+};
+
+
+WebServer::WebServer(const Pathname &root, unsigned int port)
+#if WEBRICK
+    : _pimpl(new WebServerWebrickImpl(root, port))
+#else
+    : _pimpl(new WebServerMongooseImpl(root, port))
+#endif
 {
-    // init with a user port
-    _ctx = do_init_ctx();    
-    setStrOption("root", root.asString());
-    setNumOption("ports", port);
 }
 
 void WebServer::start()
 {
-//    _thrd.reset( new boost::thread(web_thread(_ctx)) );
-    _thrd.reset( new boost::thread( boost::bind(&WebServer::worker_thread, this) ) );
+    _pimpl->start();
 }
 
-void WebServer::worker_thread()
+
+std::string WebServer::log() const
 {
-    while( ! _stop )
-        shttpd_poll(_ctx, 1000);
+    return _pimpl->log();
 }
 
-
-void WebServer::setStrOption( std::string name, std::string value)
+int WebServer::port() const
 {
-    if ( ! shttpd_set_option(_ctx, name.c_str(),
-                             value.c_str() ) )
-        ZYPP_THROW(Exception("bad option"));    
+    return _pimpl->port();
 }
 
-void WebServer::setNumOption( std::string name, int value)
+
+Url WebServer::url() const
 {
-    if ( ! shttpd_set_option(_ctx, name.c_str(),
-                             str::numstring(value).c_str()) )
-        ZYPP_THROW(Exception("bad ioption"));    
+    Url url;
+    url.setHost("localhost");
+    url.setPort(str::numstring(port()));
+    url.setScheme("http");
+    return url;
 }
 
 void WebServer::stop()
 {
-    _stop = true;
-    _thrd->join();
-    _thrd.reset();
+    _pimpl->stop();
 }
 
 WebServer::~WebServer()
 {
-    shttpd_fini(_ctx);
 }