websocket_handshake_stream_base.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/websockets/websocket_handshake_stream_base.h"
  5. #include <unordered_set>
  6. #include "base/metrics/histogram_macros.h"
  7. #include "base/strings/string_util.h"
  8. #include "net/http/http_request_headers.h"
  9. #include "net/http/http_response_headers.h"
  10. #include "net/websockets/websocket_extension.h"
  11. #include "net/websockets/websocket_extension_parser.h"
  12. #include "net/websockets/websocket_handshake_constants.h"
  13. namespace net {
  14. // static
  15. std::string WebSocketHandshakeStreamBase::MultipleHeaderValuesMessage(
  16. const std::string& header_name) {
  17. return std::string("'") + header_name +
  18. "' header must not appear more than once in a response";
  19. }
  20. // static
  21. void WebSocketHandshakeStreamBase::AddVectorHeaderIfNonEmpty(
  22. const char* name,
  23. const std::vector<std::string>& value,
  24. HttpRequestHeaders* headers) {
  25. if (value.empty())
  26. return;
  27. headers->SetHeader(name, base::JoinString(value, ", "));
  28. }
  29. // static
  30. bool WebSocketHandshakeStreamBase::ValidateSubProtocol(
  31. const HttpResponseHeaders* headers,
  32. const std::vector<std::string>& requested_sub_protocols,
  33. std::string* sub_protocol,
  34. std::string* failure_message) {
  35. size_t iter = 0;
  36. std::string value;
  37. std::unordered_set<std::string> requested_set(requested_sub_protocols.begin(),
  38. requested_sub_protocols.end());
  39. int count = 0;
  40. bool has_multiple_protocols = false;
  41. bool has_invalid_protocol = false;
  42. while (!has_invalid_protocol || !has_multiple_protocols) {
  43. std::string temp_value;
  44. if (!headers->EnumerateHeader(&iter, websockets::kSecWebSocketProtocol,
  45. &temp_value))
  46. break;
  47. value = temp_value;
  48. if (requested_set.count(value) == 0)
  49. has_invalid_protocol = true;
  50. if (++count > 1)
  51. has_multiple_protocols = true;
  52. }
  53. if (has_multiple_protocols) {
  54. *failure_message =
  55. MultipleHeaderValuesMessage(websockets::kSecWebSocketProtocol);
  56. return false;
  57. } else if (count > 0 && requested_sub_protocols.size() == 0) {
  58. *failure_message = std::string(
  59. "Response must not include 'Sec-WebSocket-Protocol' "
  60. "header if not present in request: ") +
  61. value;
  62. return false;
  63. } else if (has_invalid_protocol) {
  64. *failure_message = "'Sec-WebSocket-Protocol' header value '" + value +
  65. "' in response does not match any of sent values";
  66. return false;
  67. } else if (requested_sub_protocols.size() > 0 && count == 0) {
  68. *failure_message =
  69. "Sent non-empty 'Sec-WebSocket-Protocol' header "
  70. "but no response was received";
  71. return false;
  72. }
  73. *sub_protocol = value;
  74. return true;
  75. }
  76. // static
  77. bool WebSocketHandshakeStreamBase::ValidateExtensions(
  78. const HttpResponseHeaders* headers,
  79. std::string* accepted_extensions_descriptor,
  80. std::string* failure_message,
  81. WebSocketExtensionParams* params) {
  82. size_t iter = 0;
  83. std::string header_value;
  84. std::vector<std::string> header_values;
  85. // TODO(ricea): If adding support for additional extensions, generalise this
  86. // code.
  87. bool seen_permessage_deflate = false;
  88. while (headers->EnumerateHeader(&iter, websockets::kSecWebSocketExtensions,
  89. &header_value)) {
  90. WebSocketExtensionParser parser;
  91. if (!parser.Parse(header_value)) {
  92. // TODO(yhirano) Set appropriate failure message.
  93. *failure_message =
  94. "'Sec-WebSocket-Extensions' header value is "
  95. "rejected by the parser: " +
  96. header_value;
  97. return false;
  98. }
  99. const std::vector<WebSocketExtension>& extensions = parser.extensions();
  100. for (const auto& extension : extensions) {
  101. if (extension.name() == "permessage-deflate") {
  102. if (seen_permessage_deflate) {
  103. *failure_message = "Received duplicate permessage-deflate response";
  104. return false;
  105. }
  106. seen_permessage_deflate = true;
  107. auto& deflate_parameters = params->deflate_parameters;
  108. if (!deflate_parameters.Initialize(extension, failure_message) ||
  109. !deflate_parameters.IsValidAsResponse(failure_message)) {
  110. *failure_message = "Error in permessage-deflate: " + *failure_message;
  111. return false;
  112. }
  113. // Note that we don't have to check the request-response compatibility
  114. // here because we send a request compatible with any valid responses.
  115. // TODO(yhirano): Place a DCHECK here.
  116. header_values.push_back(header_value);
  117. } else {
  118. *failure_message = "Found an unsupported extension '" +
  119. extension.name() +
  120. "' in 'Sec-WebSocket-Extensions' header";
  121. return false;
  122. }
  123. }
  124. }
  125. *accepted_extensions_descriptor = base::JoinString(header_values, ", ");
  126. params->deflate_enabled = seen_permessage_deflate;
  127. return true;
  128. }
  129. void WebSocketHandshakeStreamBase::RecordHandshakeResult(
  130. HandshakeResult result) {
  131. UMA_HISTOGRAM_ENUMERATION("Net.WebSocket.HandshakeResult2", result,
  132. HandshakeResult::NUM_HANDSHAKE_RESULT_TYPES);
  133. }
  134. } // namespace net