2013-04-07 36 views
3

我試圖通過修改Boost ASIO example來編寫一個簡單的HTTPS服務器。它可以工作,但問題在於它爲來自客戶端的每個請求建立安全連接,這極大地降低了通信速度。簡單的HTTPS服務器和Keep-Alive連接

我知道HTTPS服務器應該使用Keep-Alive連接。但我不知道如何擴展所提到的例子來做到這一點。我的情況非常簡單,因爲我總是有1:1的連接,所以不需要會話管理,總是隻有一個有效的會話。

我採用兩種HTTP響應:

std::string HTTPS::createResponse(status_type status) 
{ 
    std::stringstream response; 
    response<<statusCodeToString(status); 
    response<<"Content-Length: "<<statusToContentString(status).size()<<"\r\n"; 
    response<<"Content-Type: text/html\r\n\r\n"; 
    response<<statusToContentString(status); 

    return response.str(); 
} 

std::string HTTPS::createResponse(status_type status, const std::string &data) 
{ 
    std::stringstream response; 
    response<<"HTTP/1.1 200 OK\r\n"; 
    response<<"Content-Length: "<<data.size()<<"\r\n"; 
    response<<"Content-Type: text/plain\r\n\r\n"; 
    response<<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[] = 
     "<html>" 
     "<head><title>Created</title></head>" 
     "<body><h1>201 Created</h1></body>" 
     "</html>"; 
    static const char accepted_s[] = 
     "<html>" 
     "<head><title>Accepted</title></head>" 
     "<body><h1>202 Accepted</h1></body>" 
     "</html>"; 
    static const char no_content_s[] = 
     "<html>" 
     "<head><title>No Content</title></head>" 
     "<body><h1>204 Content</h1></body>" 
     "</html>"; 
    static const char multiple_choices_s[] = 
     "<html>" 
     "<head><title>Multiple Choices</title></head>" 
     "<body><h1>300 Multiple Choices</h1></body>" 
     "</html>"; 
    static const char moved_permanently_s[] = 
     "<html>" 
     "<head><title>Moved Permanently</title></head>" 
     "<body><h1>301 Moved Permanently</h1></body>" 
     "</html>"; 
    static const char moved_temporarily_s[] = 
     "<html>" 
     "<head><title>Moved Temporarily</title></head>" 
     "<body><h1>302 Moved Temporarily</h1></body>" 
     "</html>"; 
    static const char not_modified_s[] = 
     "<html>" 
     "<head><title>Not Modified</title></head>" 
     "<body><h1>304 Not Modified</h1></body>" 
     "</html>"; 
    static const char bad_request_s[] = 
     "<html>" 
     "<head><title>Bad Request</title></head>" 
     "<body><h1>400 Bad Request</h1></body>" 
     "</html>"; 
    static const char unauthorized_s[] = 
     "<html>" 
     "<head><title>Unauthorized</title></head>" 
     "<body><h1>401 Unauthorized</h1></body>" 
     "</html>"; 
    static const char forbidden_s[] = 
     "<html>" 
     "<head><title>Forbidden</title></head>" 
     "<body><h1>403 Forbidden</h1></body>" 
     "</html>"; 
    static const char not_found_s[] = 
     "<html>" 
     "<head><title>Not Found</title></head>" 
     "<body><h1>404 Not Found</h1></body>" 
     "</html>"; 
    static const char not_supported_s[] = 
     "<html>" 
     "<head><title>Method Not Supported</title></head>" 
     "<body><h1>Method Not Supported</h1></body>" 
     "</html>"; 
    static const char not_acceptable_s[] = 
     "<html>" 
     "<head><title>Request Not Acceptable</title></head>" 
     "<body><h1>Request Not Acceptable</h1></body>" 
     "</html>"; 
    static const char internal_server_error_s[] = 
     "<html>" 
     "<head><title>Internal Server Error</title></head>" 
     "<body><h1>500 Internal Server Error</h1></body>" 
     "</html>"; 
    static const char not_implemented_s[] = 
     "<html>" 
     "<head><title>Not Implemented</title></head>" 
     "<body><h1>501 Not Implemented</h1></body>" 
     "</html>"; 
    static const char bad_gateway_s[] = 
     "<html>" 
     "<head><title>Bad Gateway</title></head>" 
     "<body><h1>502 Bad Gateway</h1></body>" 
     "</html>"; 
    static const char service_unavailable_s[] = 
     "<html>" 
     "<head><title>Service Unavailable</title></head>" 
     "<body><h1>503 Service Unavailable</h1></body>" 
     "</html>"; 

    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; 
     } 
} 

我相信反應是正常的,但請檢查一下 - 這不是我的專業領域。現在

的通信流被如下因素:

1,服務器開始接受一個新的連接 - 創建一個會話,結合異步受體它等待握手傳入請求。

2,如果發生呼入的握手,則服務器開始在點1

3中創建會話握手,一旦握手完成後,它處理所述傳入消息

會話握手手柄下面。它讀取一個HTTP命令並對其進行處理。我故意不關心標題的其餘部分,因爲從服務器端只有GET命令是有效的 - 服務器像一個簡單的重發器一樣工作。

void SSLSession::handleHandshake(const boost::system::error_code& error) 
{ 
    __log_print(LOG_INFO, "SSLSession", "handleHandshake"); 

    if (!error) 
    { 
     boost::asio::async_read_until(_socket, _data, "\r\n", boost::bind(&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(&_data); 
     is.unsetf(std::ios_base::skipws); 
     is >> method >> sp1 >> uri >> sp2 >> version >> cr >> lf; 
    } 

    handleHttpRequest(method, uri); 
} 

所以我的問題是,我怎麼能修改方法:

void SSLSession::handleHandshake(const boost::system::error_code& error) 

開始傾聽不僅是一個命令,但不斷進入的GET命令的有效期爲這次會議?我曾嘗試加入另一個

boost::asio::async_read_until(_socket, _data, "\r\n", boost::bind(&SSLSession::handleHttpRequestLine, this, _1)); 

調用handleHttpRequest(method, uri);方法的結束,但我得到了僵局......我相信那一定是微不足道的,但我失去了所有這些異步受體和處理程序...

+0

您能否提供完整的代碼?也許粘貼到http://liveworkspace.org/,尤其是處理HttpRequest –

回答

3

要繼續偵聽傳入的GET命令,最簡單的解決方案是從處理async_read_until的鏈內啓動async_read_until操作。在示例代碼中,讓它在handleHttpRequest中聽起來像是一個可行的選項。

如果您在異步調用鏈迷路,然後再考慮出他們:

void SSLSession::handleHandshake(...) 
{ 
    if (!error) 
    { 
    boost::asio::async_read_until(...); ----. 
    }           | 
}    .-----------------------------' 
       | .--------------------------.      
       v v       | 
void SSLSession::handleHttpRequestLine(...) | 
{           | 
    handleHttpRequest(...); --.    | 
}       |    | 
       .------------'    | 
       v        | 
void SSLSession::handleHttpRequest(...)  | 
{           | 
    boost::asio::async_read_until(...); ------' 
} 

對於Boost.Asio的1.47+,用於調試鏈另一個偉大的選項,使handle tracking。只需定義BOOST_ASIO_ENABLE_HANDLER_TRACKING,Boost.Asio會將調試輸出(包括時間戳)寫入標準錯誤流。 This答案更詳細地介紹了調試處理程序。

如果遇到死鎖,那麼很可能是在應用程序代碼中。對於大多數提升。Asio類型,在對象上掛起多個異步操作是安全的;只是指定該對象上的併發調用是不安全的。儘管如此,它通常不會在某些類型上出現問題,例如ip::tcp::socket。但是,ssl::stream強調:

應用程序還必須確保所有異步操作都在相同的隱式或顯式鏈中執行。

未定義的行爲可能會發生,這可能會導致死鎖,如this問題中所示。如果多個線程正在處理io_service事件循環,則考慮在boost::asio::strand中運行異步操作。

+0

很好的答案,謝謝!我會去嘗試一下。 – vitakot