Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(865)

Unified Diff: net/websockets/websocket_handshake_handler.cc

Issue 723343002: Update from https://crrev.com/304121 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/websockets/websocket_handshake_handler.cc
diff --git a/net/websockets/websocket_handshake_handler.cc b/net/websockets/websocket_handshake_handler.cc
index 63247109b689c2c8cf6df6c60bdbc4ee1e6dea2c..6bcc2304cc057a7a579936cd4dbd530eb33de140 100644
--- a/net/websockets/websocket_handshake_handler.cc
+++ b/net/websockets/websocket_handshake_handler.cc
@@ -4,346 +4,12 @@
#include "net/websockets/websocket_handshake_handler.h"
-#include <limits>
-
#include "base/base64.h"
+#include "base/logging.h"
#include "base/sha1.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_tokenizer.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/http/http_request_headers.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_util.h"
#include "net/websockets/websocket_handshake_constants.h"
-#include "url/gurl.h"
namespace net {
-namespace {
-
-const int kVersionHeaderValueForRFC6455 = 13;
-
-// Splits |handshake_message| into Status-Line or Request-Line (including CRLF)
-// and headers (excluding 2nd CRLF of double CRLFs at the end of a handshake
-// response).
-void ParseHandshakeHeader(
- const char* handshake_message, int len,
- std::string* request_line,
- std::string* headers) {
- size_t i = base::StringPiece(handshake_message, len).find_first_of("\r\n");
- if (i == base::StringPiece::npos) {
- *request_line = std::string(handshake_message, len);
- *headers = "";
- return;
- }
- // |request_line| includes \r\n.
- *request_line = std::string(handshake_message, i + 2);
-
- int header_len = len - (i + 2) - 2;
- if (header_len > 0) {
- // |handshake_message| includes trailing \r\n\r\n.
- // |headers| doesn't include 2nd \r\n.
- *headers = std::string(handshake_message + i + 2, header_len);
- } else {
- *headers = "";
- }
-}
-
-void FetchHeaders(const std::string& headers,
- const char* const headers_to_get[],
- size_t headers_to_get_len,
- std::vector<std::string>* values) {
- net::HttpUtil::HeadersIterator iter(headers.begin(), headers.end(), "\r\n");
- while (iter.GetNext()) {
- for (size_t i = 0; i < headers_to_get_len; i++) {
- if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(),
- headers_to_get[i])) {
- values->push_back(iter.values());
- }
- }
- }
-}
-
-bool GetHeaderName(std::string::const_iterator line_begin,
- std::string::const_iterator line_end,
- std::string::const_iterator* name_begin,
- std::string::const_iterator* name_end) {
- std::string::const_iterator colon = std::find(line_begin, line_end, ':');
- if (colon == line_end) {
- return false;
- }
- *name_begin = line_begin;
- *name_end = colon;
- if (*name_begin == *name_end || net::HttpUtil::IsLWS(**name_begin))
- return false;
- net::HttpUtil::TrimLWS(name_begin, name_end);
- return true;
-}
-
-// Similar to HttpUtil::StripHeaders, but it preserves malformed headers, that
-// is, lines that are not formatted as "<name>: <value>\r\n".
-std::string FilterHeaders(
- const std::string& headers,
- const char* const headers_to_remove[],
- size_t headers_to_remove_len) {
- std::string filtered_headers;
-
- base::StringTokenizer lines(headers.begin(), headers.end(), "\r\n");
- while (lines.GetNext()) {
- std::string::const_iterator line_begin = lines.token_begin();
- std::string::const_iterator line_end = lines.token_end();
- std::string::const_iterator name_begin;
- std::string::const_iterator name_end;
- bool should_remove = false;
- if (GetHeaderName(line_begin, line_end, &name_begin, &name_end)) {
- for (size_t i = 0; i < headers_to_remove_len; ++i) {
- if (LowerCaseEqualsASCII(name_begin, name_end, headers_to_remove[i])) {
- should_remove = true;
- break;
- }
- }
- }
- if (!should_remove) {
- filtered_headers.append(line_begin, line_end);
- filtered_headers.append("\r\n");
- }
- }
- return filtered_headers;
-}
-
-bool CheckVersionInRequest(const std::string& request_headers) {
- std::vector<std::string> values;
- const char* const headers_to_get[1] = {
- websockets::kSecWebSocketVersionLowercase};
- FetchHeaders(request_headers, headers_to_get, 1, &values);
- DCHECK_LE(values.size(), 1U);
- if (values.empty())
- return false;
-
- int version;
- bool conversion_success = base::StringToInt(values[0], &version);
- if (!conversion_success)
- return false;
-
- return version == kVersionHeaderValueForRFC6455;
-}
-
-// Append a header to a string. Equivalent to
-// response_message += header + ": " + value + "\r\n"
-// but avoids unnecessary allocations and copies.
-void AppendHeader(const base::StringPiece& header,
- const base::StringPiece& value,
- std::string* response_message) {
- static const char kColonSpace[] = ": ";
- const size_t kColonSpaceSize = sizeof(kColonSpace) - 1;
- static const char kCrNl[] = "\r\n";
- const size_t kCrNlSize = sizeof(kCrNl) - 1;
-
- size_t extra_size =
- header.size() + kColonSpaceSize + value.size() + kCrNlSize;
- response_message->reserve(response_message->size() + extra_size);
- response_message->append(header.begin(), header.end());
- response_message->append(kColonSpace, kColonSpace + kColonSpaceSize);
- response_message->append(value.begin(), value.end());
- response_message->append(kCrNl, kCrNl + kCrNlSize);
-}
-
-} // namespace
-
-WebSocketHandshakeRequestHandler::WebSocketHandshakeRequestHandler()
- : original_length_(0),
- raw_length_(0) {}
-
-bool WebSocketHandshakeRequestHandler::ParseRequest(
- const char* data, int length) {
- DCHECK_GT(length, 0);
- std::string input(data, length);
- int input_header_length =
- HttpUtil::LocateEndOfHeaders(input.data(), input.size(), 0);
- if (input_header_length <= 0)
- return false;
-
- ParseHandshakeHeader(input.data(),
- input_header_length,
- &request_line_,
- &headers_);
-
- if (!CheckVersionInRequest(headers_)) {
- NOTREACHED();
- return false;
- }
-
- original_length_ = input_header_length;
- return true;
-}
-
-size_t WebSocketHandshakeRequestHandler::original_length() const {
- return original_length_;
-}
-
-void WebSocketHandshakeRequestHandler::AppendHeaderIfMissing(
- const std::string& name, const std::string& value) {
- DCHECK(!headers_.empty());
- HttpUtil::AppendHeaderIfMissing(name.c_str(), value, &headers_);
-}
-
-void WebSocketHandshakeRequestHandler::RemoveHeaders(
- const char* const headers_to_remove[],
- size_t headers_to_remove_len) {
- DCHECK(!headers_.empty());
- headers_ = FilterHeaders(
- headers_, headers_to_remove, headers_to_remove_len);
-}
-
-HttpRequestInfo WebSocketHandshakeRequestHandler::GetRequestInfo(
- const GURL& url, std::string* challenge) {
- HttpRequestInfo request_info;
- request_info.url = url;
- size_t method_end = base::StringPiece(request_line_).find_first_of(" ");
- if (method_end != base::StringPiece::npos)
- request_info.method = std::string(request_line_.data(), method_end);
-
- request_info.extra_headers.Clear();
- request_info.extra_headers.AddHeadersFromString(headers_);
-
- request_info.extra_headers.RemoveHeader(websockets::kUpgrade);
- request_info.extra_headers.RemoveHeader(HttpRequestHeaders::kConnection);
-
- std::string key;
- bool header_present = request_info.extra_headers.GetHeader(
- websockets::kSecWebSocketKey, &key);
- DCHECK(header_present);
- request_info.extra_headers.RemoveHeader(websockets::kSecWebSocketKey);
- *challenge = key;
- return request_info;
-}
-
-bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock(
- const GURL& url,
- SpdyHeaderBlock* headers,
- std::string* challenge,
- int spdy_protocol_version) {
- // Construct opening handshake request headers as a SPDY header block.
- // For details, see WebSocket Layering over SPDY/3 Draft 8.
- if (spdy_protocol_version <= 2) {
- (*headers)["path"] = url.path();
- (*headers)["version"] = "WebSocket/13";
- (*headers)["scheme"] = url.scheme();
- } else {
- (*headers)[":path"] = url.path();
- (*headers)[":version"] = "WebSocket/13";
- (*headers)[":scheme"] = url.scheme();
- }
-
- HttpUtil::HeadersIterator iter(headers_.begin(), headers_.end(), "\r\n");
- while (iter.GetNext()) {
- if (LowerCaseEqualsASCII(iter.name_begin(),
- iter.name_end(),
- websockets::kUpgradeLowercase) ||
- LowerCaseEqualsASCII(
- iter.name_begin(), iter.name_end(), "connection") ||
- LowerCaseEqualsASCII(iter.name_begin(),
- iter.name_end(),
- websockets::kSecWebSocketVersionLowercase)) {
- // These headers must be ignored.
- continue;
- } else if (LowerCaseEqualsASCII(iter.name_begin(),
- iter.name_end(),
- websockets::kSecWebSocketKeyLowercase)) {
- *challenge = iter.values();
- // Sec-WebSocket-Key is not sent to the server.
- continue;
- } else if (LowerCaseEqualsASCII(
- iter.name_begin(), iter.name_end(), "host") ||
- LowerCaseEqualsASCII(
- iter.name_begin(), iter.name_end(), "origin") ||
- LowerCaseEqualsASCII(
- iter.name_begin(),
- iter.name_end(),
- websockets::kSecWebSocketProtocolLowercase) ||
- LowerCaseEqualsASCII(
- iter.name_begin(),
- iter.name_end(),
- websockets::kSecWebSocketExtensionsLowercase)) {
- // TODO(toyoshim): Some WebSocket extensions may not be compatible with
- // SPDY. We should omit them from a Sec-WebSocket-Extension header.
- std::string name;
- if (spdy_protocol_version <= 2)
- name = base::StringToLowerASCII(iter.name());
- else
- name = ":" + base::StringToLowerASCII(iter.name());
- (*headers)[name] = iter.values();
- continue;
- }
- // Others should be sent out to |headers|.
- std::string name = base::StringToLowerASCII(iter.name());
- SpdyHeaderBlock::iterator found = headers->find(name);
- if (found == headers->end()) {
- (*headers)[name] = iter.values();
- } else {
- // For now, websocket doesn't use multiple headers, but follows to http.
- found->second.append(1, '\0'); // +=() doesn't append 0's
- found->second.append(iter.values());
- }
- }
-
- return true;
-}
-
-std::string WebSocketHandshakeRequestHandler::GetRawRequest() {
- DCHECK(!request_line_.empty());
- DCHECK(!headers_.empty());
-
- std::string raw_request = request_line_ + headers_ + "\r\n";
- raw_length_ = raw_request.size();
- return raw_request;
-}
-
-size_t WebSocketHandshakeRequestHandler::raw_length() const {
- DCHECK_GT(raw_length_, 0);
- return raw_length_;
-}
-
-WebSocketHandshakeResponseHandler::WebSocketHandshakeResponseHandler()
- : original_header_length_(0) {}
-
-WebSocketHandshakeResponseHandler::~WebSocketHandshakeResponseHandler() {}
-
-size_t WebSocketHandshakeResponseHandler::ParseRawResponse(
- const char* data, int length) {
- DCHECK_GT(length, 0);
- if (HasResponse()) {
- DCHECK(!status_line_.empty());
- // headers_ might be empty for wrong response from server.
-
- return 0;
- }
-
- size_t old_original_length = original_.size();
-
- original_.append(data, length);
- // TODO(ukai): fail fast when response gives wrong status code.
- original_header_length_ = HttpUtil::LocateEndOfHeaders(
- original_.data(), original_.size(), 0);
- if (!HasResponse())
- return length;
-
- ParseHandshakeHeader(original_.data(),
- original_header_length_,
- &status_line_,
- &headers_);
- int header_size = status_line_.size() + headers_.size();
- DCHECK_GE(original_header_length_, header_size);
- header_separator_ = std::string(original_.data() + header_size,
- original_header_length_ - header_size);
- return original_header_length_ - old_original_length;
-}
-
-bool WebSocketHandshakeResponseHandler::HasResponse() const {
- return original_header_length_ > 0 &&
- static_cast<size_t>(original_header_length_) <= original_.size();
-}
void ComputeSecWebSocketAccept(const std::string& key,
std::string* accept) {
@@ -354,145 +20,4 @@ void ComputeSecWebSocketAccept(const std::string& key,
base::Base64Encode(hash, accept);
}
-bool WebSocketHandshakeResponseHandler::ParseResponseInfo(
- const HttpResponseInfo& response_info,
- const std::string& challenge) {
- if (!response_info.headers.get())
- return false;
-
- // TODO(ricea): Eliminate all the reallocations and string copies.
- std::string response_message;
- response_message = response_info.headers->GetStatusLine();
- response_message += "\r\n";
-
- AppendHeader(websockets::kUpgrade,
- websockets::kWebSocketLowercase,
- &response_message);
-
- AppendHeader(
- HttpRequestHeaders::kConnection, websockets::kUpgrade, &response_message);
-
- std::string websocket_accept;
- ComputeSecWebSocketAccept(challenge, &websocket_accept);
- AppendHeader(
- websockets::kSecWebSocketAccept, websocket_accept, &response_message);
-
- void* iter = NULL;
- std::string name;
- std::string value;
- while (response_info.headers->EnumerateHeaderLines(&iter, &name, &value)) {
- AppendHeader(name, value, &response_message);
- }
- response_message += "\r\n";
-
- return ParseRawResponse(response_message.data(),
- response_message.size()) == response_message.size();
-}
-
-bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock(
- const SpdyHeaderBlock& headers,
- const std::string& challenge,
- int spdy_protocol_version) {
- SpdyHeaderBlock::const_iterator status;
- if (spdy_protocol_version <= 2)
- status = headers.find("status");
- else
- status = headers.find(":status");
- if (status == headers.end())
- return false;
-
- std::string hash =
- base::SHA1HashString(challenge + websockets::kWebSocketGuid);
- std::string websocket_accept;
- base::Base64Encode(hash, &websocket_accept);
-
- std::string response_message = base::StringPrintf(
- "%s %s\r\n", websockets::kHttpProtocolVersion, status->second.c_str());
-
- AppendHeader(
- websockets::kUpgrade, websockets::kWebSocketLowercase, &response_message);
- AppendHeader(
- HttpRequestHeaders::kConnection, websockets::kUpgrade, &response_message);
- AppendHeader(
- websockets::kSecWebSocketAccept, websocket_accept, &response_message);
-
- for (SpdyHeaderBlock::const_iterator iter = headers.begin();
- iter != headers.end();
- ++iter) {
- // For each value, if the server sends a NUL-separated list of values,
- // we separate that back out into individual headers for each value
- // in the list.
- if ((spdy_protocol_version <= 2 &&
- LowerCaseEqualsASCII(iter->first, "status")) ||
- (spdy_protocol_version >= 3 &&
- LowerCaseEqualsASCII(iter->first, ":status"))) {
- // The status value is already handled as the first line of
- // |response_message|. Just skip here.
- continue;
- }
- const std::string& value = iter->second;
- size_t start = 0;
- size_t end = 0;
- do {
- end = value.find('\0', start);
- std::string tval;
- if (end != std::string::npos)
- tval = value.substr(start, (end - start));
- else
- tval = value.substr(start);
- if (spdy_protocol_version >= 3 &&
- (LowerCaseEqualsASCII(iter->first,
- websockets::kSecWebSocketProtocolSpdy3) ||
- LowerCaseEqualsASCII(iter->first,
- websockets::kSecWebSocketExtensionsSpdy3)))
- AppendHeader(iter->first.substr(1), tval, &response_message);
- else
- AppendHeader(iter->first, tval, &response_message);
- start = end + 1;
- } while (end != std::string::npos);
- }
- response_message += "\r\n";
-
- return ParseRawResponse(response_message.data(),
- response_message.size()) == response_message.size();
-}
-
-void WebSocketHandshakeResponseHandler::GetHeaders(
- const char* const headers_to_get[],
- size_t headers_to_get_len,
- std::vector<std::string>* values) {
- DCHECK(HasResponse());
- DCHECK(!status_line_.empty());
- // headers_ might be empty for wrong response from server.
- if (headers_.empty())
- return;
-
- FetchHeaders(headers_, headers_to_get, headers_to_get_len, values);
-}
-
-void WebSocketHandshakeResponseHandler::RemoveHeaders(
- const char* const headers_to_remove[],
- size_t headers_to_remove_len) {
- DCHECK(HasResponse());
- DCHECK(!status_line_.empty());
- // headers_ might be empty for wrong response from server.
- if (headers_.empty())
- return;
-
- headers_ = FilterHeaders(headers_, headers_to_remove, headers_to_remove_len);
-}
-
-std::string WebSocketHandshakeResponseHandler::GetRawResponse() const {
- DCHECK(HasResponse());
- return original_.substr(0, original_header_length_);
-}
-
-std::string WebSocketHandshakeResponseHandler::GetResponse() {
- DCHECK(HasResponse());
- DCHECK(!status_line_.empty());
- // headers_ might be empty for wrong response from server.
-
- return status_line_ + headers_ + header_separator_;
-}
-
} // namespace net
« no previous file with comments | « net/websockets/websocket_handshake_handler.h ('k') | net/websockets/websocket_handshake_handler_spdy_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698