aboutsummaryrefslogtreecommitdiffstats
path: root/http-server/http_server.cc
blob: a92c8fd993e79520f6560d06ff21835325641c50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
create host-interface name vpp1
set int state host-vpp1 up
set int ip address host-vpp1 6.0.2.1/24
create host-interface name vpp1_rtr
set int state host-vpp1_rtr up
set int ip address host-vpp1_rtr 6.0.3.1/24

lisp enable

lisp map-resolver add 6.0.3.100
lisp locator-set add ls1 iface host-vpp1_rtr p 1 w 1
lisp eid-table add eid 6.0.2.0/24 locator-set ls1
a id='n338' href='#n338'>338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2016 Ole Christian Eidheim
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "http_server.h"
namespace icn_httpserver {

HttpServer::HttpServer(unsigned short port,
                       std::string icn_name,
                       size_t num_threads,
                       long timeout_request,
                       long timeout_send_or_receive)
    : config_(port, num_threads),
      icn_name_(icn_name),
      internal_io_service_(std::make_shared<boost::asio::io_service>()),
      io_service_(*internal_io_service_),
      acceptor_(io_service_),
      timeout_request_(timeout_request),
      timeout_content_(timeout_send_or_receive) {
}

HttpServer::HttpServer(unsigned short port,
                       std::string icn_name,
                       size_t num_threads,
                       long timeout_request,
                       long timeout_send_or_receive,
                       boost::asio::io_service &ioService)
    : config_(port, num_threads),
      icn_name_(icn_name),
      io_service_(ioService),
      acceptor_(io_service_),
      timeout_request_(timeout_request),
      timeout_content_(timeout_send_or_receive) {
}

void HttpServer::onIcnRequest(std::shared_ptr<libl4::http::HTTPServerPublisher> &publisher,
                              const uint8_t *buffer,
                              std::size_t size,
                              int request_id) {
  std::shared_ptr<Request> request = std::make_shared<IcnRequest>(publisher);
  request->getContent().rdbuf()->sputn((char*)buffer, size);

  if (!parse_request(request, request->getContent())) {
    return;
  }

  std::map<int, std::shared_ptr<libl4::http::HTTPServerPublisher>>& icn_publishers = icn_acceptor_->getPublishers();

  std::unique_lock<std::mutex> lock(thread_list_mtx_);
  if (icn_publishers.size() < config_.getNum_threads()) {
      std::cout << "Received request for: " << request->getPath() << std::endl;

      publisher->attachPublisher();
      std::cout << "Starting new thread" << std::endl;
      io_service_.dispatch([this, request, request_id]() {
        std::map<int, std::shared_ptr<libl4::http::HTTPServerPublisher>>& icn_publishers = icn_acceptor_->getPublishers();
        find_resource(nullptr, request);
        icn_publishers[request_id]->serveClients();
        std::unique_lock<std::mutex> lock(thread_list_mtx_);
        icn_publishers.erase(request_id);
      });
  }
}

void HttpServer::setIcnAcceptor() {
  icn_acceptor_ = std::make_shared<libl4::http::HTTPServerAcceptor>(icn_name_, std::bind(&HttpServer::onIcnRequest,
                                                                     this,
                                                                     std::placeholders::_1,
                                                                     std::placeholders::_2,
                                                                     std::placeholders::_3,
                                                                     std::placeholders::_4));
  icn_acceptor_->listen(true);
}

void HttpServer::spawnThreads() {
  if (io_service_.stopped()) {
    io_service_.reset();
  }

  boost::asio::ip::tcp::endpoint endpoint;

  if (config_.getAddress().size() > 0) {
    endpoint =
        boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(config_.getAddress()), config_.getPort());
  } else {
    endpoint = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), config_.getPort());
  }

  acceptor_.open(endpoint.protocol());
  acceptor_.set_option(boost::asio::socket_base::reuse_address(config_.isReuse_address()));
  acceptor_.bind(endpoint);
  acceptor_.listen();

  accept();


  //If num_threads>1, start m_io_service.run() in (num_threads-1) threads for thread-pooling
  socket_threads_.clear();
  for (size_t c = 1; c < config_.getNum_threads(); c++) {
    socket_threads_.emplace_back([this]() {
      io_service_.run();
    });
  }

}

void HttpServer::start() {
  //Copy the resources to opt_resource for more efficient request processing
  opt_resource_.clear();
  for (auto &res: resource) {
    for (auto &res_method: res.second) {
      auto it = opt_resource_.end();
      for (auto opt_it = opt_resource_.begin(); opt_it != opt_resource_.end(); opt_it++) {
        if (res_method.first == opt_it->first) {
          it = opt_it;
          break;
        }
      }
      if (it == opt_resource_.end()) {
        opt_resource_.emplace_back();
        it = opt_resource_.begin() + (opt_resource_.size() - 1);
        it->first = res_method.first;
      }
      it->second.emplace_back(boost::regex(res.first), res_method.second);
    }
  }

  spawnThreads();

  setIcnAcceptor();

  // Wait for the rest of the threads, if any, to finish as well
  for (auto &t: socket_threads_) {
    t.join();
  }
  //  for (auto &t : icn_threads) {
  //    t.second.get();
  //  }
}

void HttpServer::stop() {
  io_service_.stop();
  
acceptor_.close();

  std::map<int, std::shared_ptr<libl4::http::HTTPServerPublisher>>& icn_publishers = icn_acceptor_->getPublishers();

  for (auto &p : icn_publishers) {
    p.second->stop();
  }
}

void HttpServer::accept() {
  //Create new socket for this connection
  //Shared_ptr is used to pass temporary objects to the asynchronous functions
  std::shared_ptr<socket_type> socket = std::make_shared<socket_type>(io_service_);

  acceptor_.async_accept(*socket, [this, socket](const boost::system::error_code &ec) {
    //Immediately start accepting a new connection
    accept();

    if (!ec) {
      boost::asio::ip::tcp::no_delay option(true);
      socket->set_option(option);
      read_request_and_content(socket);
    }
  });
}

void HttpServer::send(std::shared_ptr<Response> response, SendCallback callback) const {
  response->send(callback);
}

std::shared_ptr<boost::asio::deadline_timer> HttpServer::set_timeout_on_socket(std::shared_ptr<socket_type> socket,
                                                                               long seconds) {
  std::shared_ptr<boost::asio::deadline_timer> timer = std::make_shared<boost::asio::deadline_timer>(io_service_);
  timer->expires_from_now(boost::posix_time::seconds(seconds));
  timer->async_wait([socket](const boost::system::error_code &ec) {
    if (!ec) {
      boost::system::error_code ec;
      socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
      socket->lowest_layer().close();
    }
  });
  return timer;
}

void HttpServer::read_request_and_content(std::shared_ptr<socket_type> socket) {
  // Create new streambuf (Request::streambuf) for async_read_until()
  // shared_ptr is used to pass temporary objects to the asynchronous functions
  std::shared_ptr<Request> request = std::make_shared<SocketRequest>();
  request->read_remote_endpoint_data(*socket);

  // Set timeout on the following boost::asio::async-read or write function
  std::shared_ptr<boost::asio::deadline_timer> timer;
  if (timeout_request_ > 0) {
    timer = set_timeout_on_socket(socket, timeout_request_);
  }

  boost::asio::async_read_until(*socket,
                                request->getStreambuf(),
                                "\r\n\r\n",
                                [this, socket, request, timer](const boost::system::error_code &ec,
                                                               size_t bytes_transferred) {
                                  if (timeout_request_ > 0) {
                                    timer->cancel();
                                  }
                                  if (!ec) {
                                    //request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
                                    //"After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
                                    //The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
                                    //streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
                                    size_t num_additional_bytes = request->getStreambuf().size() - bytes_transferred;

                                    if (!parse_request(request, request->getContent())) {
                                      return;
                                    }

                                    //If content, read that as well
                                    auto it = request->getHeader().find("Content-Length");
                                    if (it != request->getHeader().end()) {
                                      //Set timeout on the following boost::asio::async-read or write function
                                      std::shared_ptr<boost::asio::deadline_timer> timer;
                                      if (timeout_content_ > 0) {
                                        timer = set_timeout_on_socket(socket, timeout_content_);
                                      }
                                      unsigned long long content_length;
                                      try {
                                        content_length = atol(it->second.c_str());
                                      } catch (const std::exception &) {
                                        return;
                                      }
                                      if (content_length > num_additional_bytes) {
                                        boost::asio::async_read(*socket,
                                                                request->getStreambuf(),
                                                                boost::asio::transfer_exactly(
                                                                    content_length - num_additional_bytes),
                                                                [this, socket, request, timer](const boost::system::error_code &ec,
                                                                                               size_t /*bytes_transferred*/) {
                                                                  if (timeout_content_ > 0) {
                                                                    timer->cancel();
                                                                  }
                                                                  if (!ec) {
                                                                    find_resource(socket, request);
                                                                  }
                                                                });
                                      } else {

                                        if (timeout_content_ > 0) {
                                          timer->cancel();
                                        }

                                        find_resource(socket, request);
                                      }
                                    } else {
                                      find_resource(socket, request);
                                    }
                                  }
                                });
}

bool HttpServer::parse_request(std::shared_ptr<Request> request, std::istream &stream) const {
  std::string line;
  getline(stream, line);
  size_t method_end;
  if ((method_end = line.find(' ')) != std::string::npos) {
    size_t path_end;
    if ((path_end = line.find(' ', method_end + 1)) != std::string::npos) {
      request->setMethod(line.substr(0, method_end));
      request->setPath(line.substr(method_end + 1, path_end - method_end - 1));

      size_t protocol_end;
      if ((protocol_end = line.find('/', path_end + 1)) != std::string::npos) {
        if (line.substr(path_end + 1, protocol_end - path_end - 1) != "HTTP") {
          return false;
        }
        request->setHttp_version(line.substr(protocol_end + 1, line.size() - protocol_end - 2));
      } else {
        return false;
      }

      getline(stream, line);
      size_t param_end;
      while ((param_end = line.find(':')) != std::string::npos) {
        size_t value_start = param_end + 1;
        if ((value_start) < line.size()) {
          if (line[value_start] == ' ') {
            value_start++;
          }
          if (value_start < line.size()) {
            request->getHeader().insert(std::make_pair(line.substr(0, param_end),
                                                       line.substr(value_start, line.size() - value_start - 1)));
          }
        }

        getline(stream, line);
      }
    } else {
      return false;
    }
  } else {
    return false;
  }
  return true;
}

void HttpServer::find_resource(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request) {
  //Find path- and method-match, and call write_response
  for (auto &res: opt_resource_) {
    if (request->getMethod() == res.first) {
      for (auto &res_path: res.second) {
        boost::smatch sm_res;
        if (boost::regex_match(request->getPath(), sm_res, res_path.first)) {
          request->setPath_match(std::move(sm_res));
          write_response(socket, request, res_path.second);
          return;
        }
      }
    }
  }
  auto it_method = default_resource.find(request->getMethod());
  if (it_method != default_resource.end()) {
    write_response(socket, request, it_method->second);
    return;
  }

  std::cout << "resource not found" << std::endl;
}

void HttpServer::write_response(std::shared_ptr<socket_type> socket,
                                std::shared_ptr<Request> request,
                                ResourceCallback &resource_function) {
  //Set timeout on the following boost::asio::async-read or write function
  std::shared_ptr<boost::asio::deadline_timer> timer;
  if (timeout_content_ > 0 && socket) {
    timer = set_timeout_on_socket(socket, timeout_content_);
  }

  Response *resp;

  if (socket) {
    resp = new SocketResponse(socket);
  } else {
    resp = new IcnResponse(std::static_pointer_cast<IcnRequest>(request)->getHttpPublisher(),
                           std::static_pointer_cast<IcnRequest>(request)->getName(),
                           std::static_pointer_cast<IcnRequest>(request)->getPath(),
                           std::static_pointer_cast<IcnRequest>(request)->getRequest_id());
  }

  auto response = std::shared_ptr<Response>(resp, [this, request, timer, socket](Response *response_ptr) {

    auto response = std::shared_ptr<Response>(response_ptr);
    response->setIsLast(true);

    send(response, [this, response, request, timer, socket](const boost::system::error_code &ec) {
      if (!ec) {
        if (socket && timeout_content_ > 0) {
          timer->cancel();
        }

        float http_version;
        try {
          http_version = atof(request->getHttp_version().c_str());
        } catch (const std::exception &) {
          return;
        }

        auto range = request->getHeader().equal_range("Connection");
        for (auto it = range.first; it != range.second; it++) {
          if (boost::iequals(it->second, "close")) {
            return;
          }
        }
        if (http_version > 1.05) {
          read_request_and_content(std::static_pointer_cast<SocketResponse>(response)->getSocket());
        }
      }
    });
  });


  try {
    resource_function(response, request);
  } catch (const std::exception &) {
    return;
  }

}

} // end namespace icn_httpserver