title: Simple HTTPS server and Keep-Alive connections
body: <p>I am trying to write a simple HTTPS server by modifying the <a href="http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/ssl/server.cpp" rel="nofollow">Boost ASIO example</a>. It works, but the problem is that it establishes a secured connection for each request coming from a client, which terribly slows down the communication.</p>
  
  <p>I know the HTTPS server should use Keep-Alive connections. But I do not know how to extend the mentioned example to do that. The situation is very simple in my case as I always have 1:1 connection, so there is no need for session management, there is always only a one valid session. </p>
  
  <p>I use two kinds of HTTP responses:</p>
  
  <pre><code>std::string HTTPS::createResponse(status_type status)
  {
      std::stringstream response;
      response&lt;&lt;statusCodeToString(status);
      response&lt;&lt;"Content-Length: "&lt;&lt;statusToContentString(status).size()&lt;&lt;"\r\n";
      response&lt;&lt;"Content-Type: text/html\r\n\r\n";
      response&lt;&lt;statusToContentString(status);
  
      return response.str();
  }
  
  std::string HTTPS::createResponse(status_type status, const std::string &amp;data)
  {
      std::stringstream response;
      response&lt;&lt;"HTTP/1.1 200 OK\r\n";
      response&lt;&lt;"Content-Length: "&lt;&lt;data.size()&lt;&lt;"\r\n";
      response&lt;&lt;"Content-Type: text/plain\r\n\r\n";
      response&lt;&lt;data;
  
      return response.str();
  }
  
  std::string HLSProxyServerSSL::statusCodeToString(status_type status)
  {
      static const char ok_s[] =
          "HTTP/1.1 200 OK\r\n";
      static const char created_s[] =
          "HTTP/1.1 201 Created\r\n";
      static const char accepted_s[] =
          "HTTP/1.1 202 Accepted\r\n";
      static const char no_content_s[] =
          "HTTP/1.1 204 No Content\r\n";
      static const char multiple_choices_s[] =
          "HTTP/1.1 300 Multiple Choices\r\n";
      static const char moved_permanently_s[] =
          "HTTP/1.1 301 Moved Permanently\r\n";
      static const char moved_temporarily_s[] =
          "HTTP/1.1 302 Moved Temporarily\r\n";
      static const char not_modified_s[] =
          "HTTP/1.1 304 Not Modified\r\n";
      static const char bad_request_s[] =
          "HTTP/1.1 400 Bad Request\r\n";
      static const char unauthorized_s[] =
          "HTTP/1.1 401 Unauthorized\r\n";
      static const char forbidden_s[] =
          "HTTP/1.1 403 Forbidden\r\n";
      static const char not_found_s[] =
          "HTTP/1.1 404 Not Found\r\n";
      static const char not_supported_s[] =
          "HTTP/1.1 405 Method Not Supported\r\n";
      static const char not_acceptable_s[] =
          "HTTP/1.1 406 Method Not Acceptable\r\n";
      static const char internal_server_error_s[] =
          "HTTP/1.1 500 Internal Server Error\r\n";
      static const char not_implemented_s[] =
          "HTTP/1.1 501 Not Implemented\r\n";
      static const char bad_gateway_s[] =
          "HTTP/1.1 502 Bad Gateway\r\n";
      static const char service_unavailable_s[] =
          "HTTP/1.1 503 Service Unavailable\r\n";
  
      switch (status)
      {
          case ok:
              return ok_s;
          case created:
              return created_s;
          case accepted:
              return accepted_s;
          case no_content:
              return no_content_s;
          case multiple_choices:
              return multiple_choices_s;
          case moved_permanently:
              return moved_permanently_s;
          case moved_temporarily:
              return moved_temporarily_s;
          case not_modified:
              return not_modified_s;
          case bad_request:
              return bad_request_s;
          case unauthorized:
              return unauthorized_s;
          case forbidden:
              return forbidden_s;
          case not_found:
              return not_found_s;
          case not_supported:
              return not_supported_s;
          case not_acceptable:
              return not_acceptable_s;
          case internal_server_error:
              return internal_server_error_s;
          case not_implemented:
              return not_implemented_s;
          case bad_gateway:
              return bad_gateway_s;
          case service_unavailable:
              return service_unavailable_s;
          default:
              return internal_server_error_s;
      }
  }
  
  std::string HLSProxyServerSSL::statusToContentString(status_type status)
  {
      static const char ok_s[] = "";
      static const char created_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Created&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;201 Created&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char accepted_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Accepted&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;202 Accepted&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char no_content_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;No Content&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;204 Content&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char multiple_choices_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Multiple Choices&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;300 Multiple Choices&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char moved_permanently_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Moved Permanently&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;301 Moved Permanently&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char moved_temporarily_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Moved Temporarily&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;302 Moved Temporarily&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char not_modified_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Not Modified&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;304 Not Modified&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char bad_request_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Bad Request&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;400 Bad Request&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char unauthorized_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Unauthorized&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;401 Unauthorized&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char forbidden_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Forbidden&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;403 Forbidden&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char not_found_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Not Found&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;404 Not Found&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char not_supported_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Method Not Supported&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;Method Not Supported&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char not_acceptable_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Request Not Acceptable&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;Request Not Acceptable&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char internal_server_error_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Internal Server Error&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;500 Internal Server Error&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char not_implemented_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Not Implemented&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;501 Not Implemented&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char bad_gateway_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Bad Gateway&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;502 Bad Gateway&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
      static const char service_unavailable_s[] =
          "&lt;html&gt;"
          "&lt;head&gt;&lt;title&gt;Service Unavailable&lt;/title&gt;&lt;/head&gt;"
          "&lt;body&gt;&lt;h1&gt;503 Service Unavailable&lt;/h1&gt;&lt;/body&gt;"
          "&lt;/html&gt;";
  
      switch (status)
      {
          case ok:
              return ok_s;
          case created:
              return created_s;
          case accepted:
              return accepted_s;
          case no_content:
              return no_content_s;
          case multiple_choices:
              return multiple_choices_s;
          case moved_permanently:
              return moved_permanently_s;
          case moved_temporarily:
              return moved_temporarily_s;
          case not_modified:
              return not_modified_s;
          case bad_request:
              return bad_request_s;
          case unauthorized:
              return unauthorized_s;
          case forbidden:
              return forbidden_s;
          case not_found:
              return not_found_s;
          case not_supported:
              return not_supported_s;
          case not_acceptable:
              return not_acceptable_s;
          case internal_server_error:
              return internal_server_error_s;
          case not_implemented:
              return not_implemented_s;
          case bad_gateway:
              return bad_gateway_s;
          case service_unavailable:
              return service_unavailable_s;
          default:
              return internal_server_error_s;
          }
  }
  </code></pre>
  
  <p>I believe the responses are OK, but please check it – It is no my area of expertise.</p>
  
  <p>The communication flow is folowing now:</p>
  
  <p>1, Server starts to accept a new connection – creates a session, binds the asynchronous acceptor which waits for incoming request for handshake. </p>
  
  <p>2, if an incoming handshake occurs, then the server starts handshake on session created in the point 1.</p>
  
  <p>3, once the handshake finishes, it process the incoming message</p>
  
  <p>The session handshake handle is below. It reads one HTTP command and processes it. I intentionally do not care of the rest of the header because from the server side only the GET commands are valid – the server works like a simple re-sender. </p>
  
  <pre><code>void SSLSession::handleHandshake(const boost::system::error_code&amp; error)
  {
      __log_print(LOG_INFO, "SSLSession", "handleHandshake");
  
      if (!error)
      {
          boost::asio::async_read_until(_socket, _data, "\r\n", boost::bind(&amp;SSLSession::handleHttpRequestLine, this, _1));
      }
      else
      {
          delete this;
      }
  }
  
  void SSLSession::handleHttpRequestLine(boost::system::error_code ec)
  {
      std::string method, uri, version;
  
      if (!ec)
      {
          char sp1, sp2, cr, lf;
          std::istream is(&amp;_data);
          is.unsetf(std::ios_base::skipws);
          is &gt;&gt; method &gt;&gt; sp1 &gt;&gt; uri &gt;&gt; sp2 &gt;&gt; version &gt;&gt; cr &gt;&gt; lf;
      }
  
      handleHttpRequest(method, uri);
  }
  </code></pre>
  
  <p><strong>So my question is</strong>, how can I modify method: </p>
  
  <pre><code>void SSLSession::handleHandshake(const boost::system::error_code&amp; error)
  </code></pre>
  
  <p>to start listen not only to one command, but to continuously incoming GET commands which are valid for this session? I have tried adding another</p>
  
  <pre><code>boost::asio::async_read_until(_socket, _data, "\r\n", boost::bind(&amp;SSLSession::handleHttpRequestLine, this, _1));
  </code></pre>
  
  <p>call to the end of <code>handleHttpRequest(method, uri);</code> method, but I got a deadlock... I believe it must be trivial, but I am lost in all these async acceptors and handlers...</p>