/* * bitz-server, An ICAP server implementation in C++ * Copyright (C) 2012 Uditha Atukorala * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "worker.h" #include "logger.h" #include "util.h" #include "options_request_handler.h" #include "reqmod_request_handler.h" #include "respmod_request_handler.h" #include #include namespace bitz { Worker::Worker() { // load request handlers load_req_handlers(); } Worker::~Worker() { // logger Logger &logger = Logger::instance(); logger.debug( "[worker] exiting" ); // cleanup request handlers util::delete_req_handlers( _req_handlers ); delete _req_handlers["OPTIONS"]; } void Worker::run( psocksxx::tcpnsockstream * server_sock, unsigned int max_requests, unsigned int comm_timeout ) throw() { // logger Logger &logger = Logger::instance(); // client socket stream psocksxx::nsockstream * client_sock; while ( max_requests > 0 ) { logger.debug( std::string( "[worker] waiting for a connection" ) ); try { // accept a client connection client_sock = server_sock->accept(); // FIXME: log accepted client details (e.g. address, port etc.) logger.debug( std::string( "[worker] new connection accepted on [...]" ) ); // set timeout value if ( comm_timeout > 0 ) { client_sock->timeout( comm_timeout, 0 ); // TODO: add debug logging } } catch ( psocksxx::sockexception &e ) { // failed to accept client connection logger.error( std::string( "[worker] failed to accept connection: " ).append( e.what() ) ); // update request count max_requests--; continue; } // handle client request(s) max_requests = serve_client( client_sock, max_requests ); // destroy / close connection delete client_sock; }; } void Worker::load_req_handlers() throw() { OptionsRequestHandler * options_handler; // OPTIONS handler options_handler = new OptionsRequestHandler(); _req_handlers["OPTIONS"] = options_handler; /* request handlers */ // REQMOD _req_handlers["REQMOD"] = new ReqmodRequestHandler(); options_handler->register_handler( _req_handlers["REQMOD"] ); // RESPMOD _req_handlers["RESPMOD"] = new RespmodRequestHandler(); options_handler->register_handler( _req_handlers["RESPMOD"] ); } unsigned int Worker::serve_client( psocksxx::nsockstream * client_sock, unsigned int max_requests ) throw() { // logger Logger &logger = Logger::instance(); icap::RequestHeader * req_header = NULL; icap::Response * response; RequestHandler * req_handler; do { // cleanup request header if ( req_header != NULL ) { delete req_header; } // request header req_header = icap::util::read_req_header( client_sock ); logger.debug( std::string( "[worker] request header:\r\n" ).append( req_header->raw_data() ) ); // check timeout if ( client_sock->timedout() ) { logger.warn( "[worker] communication timed out..." ); return --max_requests; } // try to find a handler for the request req_handler = util::find_req_handler( _req_handlers, req_header->method() ); // sanity check if ( req_handler != NULL ) { logger.debug( std::string( "[worker] handling request: " ).append( req_header->method() ) ); // process the request and grab the response response = req_handler->process( req_header, client_sock ); } else { // unsupported request logger.info( std::string( "[worker] unsupported request: " ).append( req_header->method() ) ); response = new icap::Response( new icap::ResponseHeader( icap::ResponseHeader::NOT_ALLOWED ) ); } // FIXME: this should be configurable and should default to close // connection if the client doesn't send a connection header if ( req_header->value( "Connection" ) == "keep-alive" ) { response->header()->attach( "Connection" , "keep-alive" ); } // send the response back to the client icap::util::send_response( response, client_sock ); // cleanup delete response; } while ( ( --max_requests > 0 ) && ( req_header->value( "Connection" ) == "keep-alive" ) ); // cleanup request header if ( req_header != NULL ) { delete req_header; } return max_requests; } } /* end of namespace bitz */