LCOV - code coverage report
Current view: top level - snapwebsites - snap_initialize_website.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 117 0.9 %
Date: 2019-12-15 17:13:15 Functions: 2 13 15.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Snap Websites Server -- snap websites initialize website implementation
       2             : // Copyright (c) 2011-2019  Made to Order Software Corp.  All Rights Reserved
       3             : //
       4             : // This program is free software; you can redistribute it and/or modify
       5             : // it under the terms of the GNU General Public License as published by
       6             : // the Free Software Foundation; either version 2 of the License, or
       7             : // (at your option) any later version.
       8             : //
       9             : // This program is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             : // GNU General Public License for more details.
      13             : //
      14             : // You should have received a copy of the GNU General Public License
      15             : // along with this program; if not, write to the Free Software
      16             : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      17             : 
      18             : 
      19             : // self
      20             : //
      21             : #include "snapwebsites/snap_initialize_website.h"
      22             : 
      23             : 
      24             : // snapwebsites lib
      25             : //
      26             : #include "snapwebsites/log.h"
      27             : #include "snapwebsites/tcp_client_server.h"
      28             : #include "snapwebsites/snapwebsites.h"
      29             : 
      30             : 
      31             : // C++ lib
      32             : //
      33             : #include <sstream>
      34             : 
      35             : 
      36             : // last include
      37             : //
      38             : #include <snapdev/poison.h>
      39             : 
      40             : 
      41             : 
      42             : 
      43             : 
      44             : 
      45             : namespace snap
      46             : {
      47             : 
      48             : 
      49           0 : snap_initialize_website::snap_initialize_website_runner::snap_initialize_website_runner(snap_initialize_website * parent,
      50             :                                                 QString const & snap_host, int snap_port, bool secure,
      51             :                                                 QString const & website_uri, int destination_port,
      52           0 :                                                 QString const & query_string, QString const & protocol)
      53             :     : snap_runner("initialize_website")
      54             :     , f_parent(parent)
      55             :     , f_snap_host(snap_host)
      56             :     , f_snap_port(snap_port)
      57             :     , f_secure(secure)
      58             :     , f_website_uri(website_uri)
      59             :     , f_destination_port(destination_port)
      60             :     , f_query_string(query_string)
      61           0 :     , f_protocol(protocol.toUpper())
      62             : {
      63           0 :     if(f_protocol != "HTTP"
      64           0 :     && f_protocol != "HTTPS")
      65             :     {
      66           0 :         throw snap_initialize_website_exception_invalid_parameter("protocol must be \"HTTP\" or \"HTTPS\".");
      67             :     }
      68           0 : }
      69             : 
      70             : 
      71           0 : void snap_initialize_website::snap_initialize_website_runner::run()
      72             : {
      73             :     try
      74             :     {
      75           0 :         send_init_command();
      76             :     }
      77           0 :     catch(...)
      78             :     {
      79             :         // we are in thread, throwing is not too good
      80             :         // TODO: add something to tell about the problem?
      81           0 :         message("Snap! Manager received an unknown exception while initializing a website.");
      82             :     }
      83           0 :     done();
      84           0 : }
      85             : 
      86             : 
      87           0 : void snap_initialize_website::snap_initialize_website_runner::send_init_command()
      88             : {
      89           0 :     tcp_client_server::bio_client::pointer_t socket;
      90             :     try
      91             :     {
      92           0 :          tcp_client_server::bio_client::mode_t const mode(f_secure
      93           0 :                     ? tcp_client_server::bio_client::mode_t::MODE_SECURE
      94             :                     : tcp_client_server::bio_client::mode_t::MODE_PLAIN);
      95           0 :          socket.reset(new tcp_client_server::bio_client(f_snap_host.toUtf8().data(), f_snap_port, mode));
      96             :     }
      97           0 :     catch(tcp_client_server::tcp_client_server_runtime_error const&)
      98             :     {
      99           0 :         message("Snap! Manager was not able to connect to the Snap! Server (connection error).\n\nPlease verify that a Snap! server is running at the specified IP address.");
     100           0 :         return;
     101             :     }
     102             : 
     103             :     // send the #INIT command
     104             : #define INIT_COMMAND "#INIT=" SNAPWEBSITES_VERSION_STRING
     105           0 :     if(socket->write(INIT_COMMAND "\n", sizeof(INIT_COMMAND)) != sizeof(INIT_COMMAND))
     106             :     {
     107           0 :         message("Snap! Manager was not able to communicate with the Snap! Server (write \"" INIT_COMMAND "\" error).");
     108           0 :         return;
     109             :     }
     110             : #undef INIT_COMMAND
     111             : 
     112             :     // now send the environment
     113           0 :     std::stringstream ss;
     114             : 
     115             :     // HTTP_HOST
     116           0 :     ss << "HTTP_HOST=" << f_website_uri << std::endl;
     117             : 
     118             :     // HTTP_USER_AGENT
     119           0 :     ss << "HTTP_USER_AGENT=Snap/" << SNAPWEBSITES_VERSION_MAJOR
     120           0 :        << "." << SNAPWEBSITES_VERSION_MINOR
     121           0 :        << " (Linux) libsnapwebsites/" << SNAPWEBSITES_VERSION_MAJOR
     122           0 :        << "." << SNAPWEBSITES_VERSION_MINOR
     123           0 :        << "." << SNAPWEBSITES_VERSION_PATCH << std::endl;
     124             : 
     125             :     // HTTP_ACCEPT
     126           0 :     ss << "HTTP_ACCEPT=text/plain" << std::endl;
     127             : 
     128             :     // HTTP_ACCEPT_LANGUAGE
     129           0 :     ss << "HTTP_ACCEPT_LANGUAGE=en-us,en;q=0.8" << std::endl;
     130             : 
     131             :     // HTTP_ACCEPT_ENCODING
     132             :     //
     133             :     // TODO: add support for gzip compression
     134             :     //ss << "HTTP_ACCEPT_ENCODING=..." << std::endl;
     135             : 
     136             :     // HTTP_ACCEPT_CHARSET
     137           0 :     ss << "HTTP_ACCEPT_CHARSET=utf-8" << std::endl;
     138             : 
     139             :     // HTTP_CONNECTION
     140           0 :     ss << "HTTP_CONNECTION=close" << std::endl; // close once done
     141             : 
     142             :     // HTTP_CACHE_CONTROL
     143           0 :     ss << "HTTP_CACHE_CONTROL=max-age=0" << std::endl;
     144             : 
     145             :     // SERVER_SOFTWARE
     146           0 :     ss << "SERVER_SOFTWARE=Snap" << std::endl;
     147             : 
     148             :     // SERVER_NAME
     149             :     // TBD... requires a reverse DNS if f_snap_host is an IP
     150             :     //ss << "SERVER_NAME=" << f_snap_host << std::endl;
     151             : 
     152             :     // SERVER_ADDR
     153             :     // TODO: if f_snap_host is a name, convert to IP (use socket name?)
     154           0 :     ss << "SERVER_ADDR=" << f_snap_host << std::endl;
     155             : 
     156             :     // SERVER_PORT
     157           0 :     ss << "SERVER_PORT=" << f_destination_port << std::endl;
     158             : 
     159             :     // REMOTE_HOST
     160             :     char hostname[HOST_NAME_MAX + 1];
     161           0 :     hostname[HOST_NAME_MAX] = '\0';
     162           0 :     if(gethostname(hostname, HOST_NAME_MAX) == -1)
     163             :     {
     164           0 :         message("Snap! Manager could not determine your host name.");
     165           0 :         strncpy(hostname, "UNKNOWN", HOST_NAME_MAX);
     166             :     }
     167           0 :     ss << "REMOTE_HOST=" << hostname << std::endl;
     168             : 
     169             :     // REMOTE_ADDR
     170           0 :     ss << "REMOTE_ADDR=" << socket->get_client_addr() << std::endl;
     171             : 
     172             :     // REMOTE_PORT
     173           0 :     ss << "REMOTE_PORT=" << socket->get_client_port() << std::endl;
     174             : 
     175             :     // GATEWAY_INTERFACE
     176           0 :     ss << "GATEWAY_INTERFACE=libsnapwebsites/" << SNAPWEBSITES_VERSION_MAJOR
     177           0 :        << "." << SNAPWEBSITES_VERSION_MINOR
     178           0 :        << "." << SNAPWEBSITES_VERSION_PATCH << std::endl;
     179             : 
     180             :     // SERVER_PROTOCOL
     181           0 :     ss << "SERVER_PROTOCOL=HTTP/1.1" << std::endl;
     182             : 
     183             :     // REQUEST_METHOD
     184           0 :     ss << snap::get_name(name_t::SNAP_NAME_CORE_REQUEST_METHOD) << "=GET" << std::endl;
     185             : 
     186             :     // QUERY_STRING
     187           0 :     ss << "QUERY_STRING=initialize_website=1";
     188           0 :     if(!f_query_string.isEmpty())
     189             :     {
     190           0 :         ss << "&" << f_query_string;
     191             :     }
     192           0 :     ss << std::endl;
     193             : 
     194             :     // REQUEST_URI
     195           0 :     ss << snap::get_name(name_t::SNAP_NAME_CORE_REQUEST_URI) << "=/" << std::endl;
     196             : 
     197             :     // SCRIPT_NAME
     198             :     //ss << "SCRIPT_NAME=..." << std::endl;
     199             : 
     200             :     // HTTPS
     201             :     //
     202           0 :     if(f_protocol == "HTTPS")
     203             :     {
     204           0 :         ss << "HTTPS=on" << std::endl;
     205             :     }
     206             : 
     207             :     // send the environment in one block
     208           0 :     std::string const env(ss.str());
     209           0 : std::cerr << "---ENV---\n" << env << "---ENV---\n";
     210           0 :     if(socket->write(env.c_str(), env.size()) != static_cast<int>(env.size()))
     211             :     {
     212           0 :         message("Snap! Manager was not able to communicate with the Snap! Server (write error while sending environment).");
     213           0 :         return;
     214             :     }
     215             : 
     216             :     // send the #END
     217           0 :     if(socket->write("#END\n", 5) != 5)
     218             :     {
     219           0 :         message("Snap! Manager was not able to communicate with the Snap! Server (write \"#END\" error).");
     220           0 :         return;
     221             :     }
     222             : 
     223             :     // read the results of the #START command
     224           0 :     bool started(false);
     225             :     for(;;)
     226             :     {
     227           0 :         std::string buf;
     228           0 :         int const r(socket->read_line(buf));
     229           0 :         if(r <= 0)
     230             :         {
     231             :             // note that r == 0 is not an error but it should not happen
     232             :             // (i.e. I/O is blocking so we should not return too soon.)
     233           0 :             if(started)
     234             :             {
     235           0 :                 message("Snap! Manager never received the #END signal.");
     236             :             }
     237             :             else
     238             :             {
     239           0 :                 message("Snap! Manager was not able to communicate with the Snap! Server (read error).");
     240             :             }
     241           0 :             return;
     242             :         }
     243           0 :         if(!started)
     244             :         {
     245           0 :             if(buf != "#START")
     246             :             {
     247           0 :                 message("Snap! Manager was able to communicate with the Snap! Server but got unexpected protocol data.");
     248           0 :                 return;
     249             :             }
     250           0 :             started = true;
     251             :         }
     252           0 :         else if(buf == "#END")
     253             :         {
     254             :             // got the #END mark, we are done
     255           0 :             break;
     256             :         }
     257             :         else
     258             :         {
     259           0 :             QString const line(QString::fromUtf8(buf.c_str(), buf.length()));
     260           0 :             message("Status: " + line);
     261             :         }
     262           0 :     }
     263             : }
     264             : 
     265             : 
     266           0 : void snap_initialize_website::snap_initialize_website_runner::message(QString const& msg)
     267             : {
     268           0 :     snap_thread::snap_lock lock(f_mutex);
     269           0 :     f_message_queue.push_back(msg);
     270           0 : }
     271             : 
     272             : 
     273           0 : QString snap_initialize_website::snap_initialize_website_runner::next_message()
     274             : {
     275             :     // TODO: It looks like we created our own queue here when the thread
     276             :     // implementation offers one that most certainly works just fine -- switch!
     277           0 :     snap_thread::snap_lock lock(f_mutex);
     278           0 :     if(f_message_queue.empty())
     279             :     {
     280           0 :         return QString();
     281             :     }
     282           0 :     QString const msg(f_message_queue.front());
     283           0 :     f_message_queue.pop_front();
     284           0 :     return msg;
     285             : }
     286             : 
     287             : 
     288           0 : bool snap_initialize_website::snap_initialize_website_runner::is_done() const
     289             : {
     290           0 :     snap_thread::snap_lock lock(f_mutex);
     291           0 :     return f_done;
     292             : }
     293             : 
     294             : 
     295           0 : void snap_initialize_website::snap_initialize_website_runner::done()
     296             : {
     297             :     // mark the process as done
     298           0 :     snap_thread::snap_lock lock(f_mutex);
     299           0 :     f_done = true;
     300           0 : }
     301             : 
     302             : 
     303             : 
     304             : 
     305           0 : snap_initialize_website::snap_initialize_website(QString const & snap_host, int snap_port, bool secure,
     306             :                                                  QString const & website_uri, int destination_port,
     307           0 :                                                  QString const & query_string, QString const & protocol)
     308           0 :     : f_website_runner(new snap_initialize_website_runner(this, snap_host, snap_port, secure, website_uri, destination_port, query_string, protocol))
     309           0 :     , f_process_thread(new snap_thread("Initialize Website Thread", f_website_runner.get()))
     310             : {
     311           0 : }
     312             : 
     313             : 
     314           0 : bool snap_initialize_website::start_process()
     315             : {
     316           0 :     if(!f_process_thread->start())
     317             :     {
     318           0 :         SNAP_LOG_FATAL("cannot start thread for website initialization!");
     319           0 :         return false;
     320             :     }
     321             : 
     322           0 :     return true;
     323             : }
     324             : 
     325             : 
     326           0 : QString snap_initialize_website::get_status()
     327             : {
     328           0 :     return f_website_runner->next_message();
     329             : }
     330             : 
     331             : 
     332           0 : bool snap_initialize_website::is_done() const
     333             : {
     334           0 :     return f_website_runner->is_done();
     335             : }
     336             : 
     337             : 
     338             : 
     339           6 : }
     340             : // namespace snap
     341             : 
     342             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13