1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/websockets/websocket_handshake_handler.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/md5.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_piece.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/http/http_response_headers.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_util.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst size_t kRequestKey3Size = 8U;
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst size_t kResponseKeySize = 16U;
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ParseHandshakeHeader(
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* handshake_message, int len,
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string* status_line,
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string* headers) {
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t i = base::StringPiece(handshake_message, len).find_first_of("\r\n");
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (i == base::StringPiece::npos) {
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *status_line = std::string(handshake_message, len);
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *headers = "";
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |status_line| includes \r\n.
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *status_line = std::string(handshake_message, i + 2);
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int header_len = len - (i + 2) - 2;
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (header_len > 0) {
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // |handshake_message| includes tailing \r\n\r\n.
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // |headers| doesn't include 2nd \r\n.
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *headers = std::string(handshake_message + i + 2, header_len);
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *headers = "";
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid FetchHeaders(const std::string& headers,
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  const char* const headers_to_get[],
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  size_t headers_to_get_len,
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  std::vector<std::string>* values) {
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::HttpUtil::HeadersIterator iter(headers.begin(), headers.end(), "\r\n");
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (iter.GetNext()) {
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < headers_to_get_len; i++) {
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(),
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               headers_to_get[i])) {
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        values->push_back(iter.values());
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetHeaderName(std::string::const_iterator line_begin,
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   std::string::const_iterator line_end,
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   std::string::const_iterator* name_begin,
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   std::string::const_iterator* name_end) {
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string::const_iterator colon = std::find(line_begin, line_end, ':');
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (colon == line_end) {
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *name_begin = line_begin;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *name_end = colon;
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (*name_begin == *name_end || net::HttpUtil::IsLWS(**name_begin))
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::HttpUtil::TrimLWS(name_begin, name_end);
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Similar to HttpUtil::StripHeaders, but it preserves malformed headers, that
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is, lines that are not formatted as "<name>: <value>\r\n".
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string FilterHeaders(
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& headers,
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* const headers_to_remove[],
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size_t headers_to_remove_len) {
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string filtered_headers;
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StringTokenizer lines(headers.begin(), headers.end(), "\r\n");
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (lines.GetNext()) {
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string::const_iterator line_begin = lines.token_begin();
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string::const_iterator line_end = lines.token_end();
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string::const_iterator name_begin;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string::const_iterator name_end;
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool should_remove = false;
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (GetHeaderName(line_begin, line_end, &name_begin, &name_end)) {
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      for (size_t i = 0; i < headers_to_remove_len; ++i) {
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (LowerCaseEqualsASCII(name_begin, name_end, headers_to_remove[i])) {
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          should_remove = true;
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!should_remove) {
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      filtered_headers.append(line_begin, line_end);
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      filtered_headers.append("\r\n");
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return filtered_headers;
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Gets a key number from |key| and appends the number to |challenge|.
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The key number (/part_N/) is extracted as step 4.-8. in
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 5.2. Sending the server's opening handshake of
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// http://www.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-00.txt
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetKeyNumber(const std::string& key, std::string* challenge) {
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  uint32 key_number = 0;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  uint32 spaces = 0;
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < key.size(); ++i) {
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (isdigit(key[i])) {
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // key_number should not overflow. (it comes from
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // WebCore/websockets/WebSocketHandshake.cpp).
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      key_number = key_number * 10 + key[i] - '0';
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (key[i] == ' ') {
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++spaces;
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // spaces should not be zero in valid handshake request.
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (spaces == 0)
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  key_number /= spaces;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  char part[4];
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < 4; i++) {
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    part[3 - i] = key_number & 0xFF;
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    key_number >>= 8;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  challenge->append(part, 4);
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // anonymous namespace
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace net {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebSocketHandshakeRequestHandler::WebSocketHandshakeRequestHandler()
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : original_length_(0),
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      raw_length_(0) {}
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WebSocketHandshakeRequestHandler::ParseRequest(
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* data, int length) {
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GT(length, 0);
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string input(data, length);
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int input_header_length =
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      HttpUtil::LocateEndOfHeaders(input.data(), input.size(), 0);
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (input_header_length <= 0 ||
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      input_header_length + kRequestKey3Size > input.size())
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ParseHandshakeHeader(input.data(),
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       input_header_length,
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       &status_line_,
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       &headers_);
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // draft-hixie-thewebsocketprotocol-76 or later will send /key3/
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // after handshake request header.
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Assumes WebKit doesn't send any data after handshake request message
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // until handshake is finished.
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Thus, |key3_| is part of handshake message, and not in part
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // of WebSocket frame stream.
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(kRequestKey3Size,
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            input.size() -
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            input_header_length);
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  key3_ = std::string(input.data() + input_header_length,
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      input.size() - input_header_length);
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  original_length_ = input.size();
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsize_t WebSocketHandshakeRequestHandler::original_length() const {
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return original_length_;
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketHandshakeRequestHandler::AppendHeaderIfMissing(
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& name, const std::string& value) {
177dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(!headers_.empty());
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HttpUtil::AppendHeaderIfMissing(name.c_str(), value, &headers_);
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketHandshakeRequestHandler::RemoveHeaders(
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* const headers_to_remove[],
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size_t headers_to_remove_len) {
184dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(!headers_.empty());
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers_ = FilterHeaders(
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      headers_, headers_to_remove, headers_to_remove_len);
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochHttpRequestInfo WebSocketHandshakeRequestHandler::GetRequestInfo(
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& url, std::string* challenge) {
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HttpRequestInfo request_info;
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_info.url = url;
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::StringPiece method = status_line_.data();
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t method_end = base::StringPiece(
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      status_line_.data(), status_line_.size()).find_first_of(" ");
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (method_end != base::StringPiece::npos)
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    request_info.method = std::string(status_line_.data(), method_end);
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_info.extra_headers.Clear();
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_info.extra_headers.AddHeadersFromString(headers_);
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_info.extra_headers.RemoveHeader("Upgrade");
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_info.extra_headers.RemoveHeader("Connection");
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  challenge->clear();
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string key;
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_info.extra_headers.GetHeader("Sec-WebSocket-Key1", &key);
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key1");
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetKeyNumber(key, challenge);
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_info.extra_headers.GetHeader("Sec-WebSocket-Key2", &key);
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_info.extra_headers.RemoveHeader("Sec-WebSocket-Key2");
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetKeyNumber(key, challenge);
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  challenge->append(key3_);
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return request_info;
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock(
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& url, spdy::SpdyHeaderBlock* headers, std::string* challenge) {
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't set "method" and "version".  These are fixed value in WebSocket
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // protocol.
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  (*headers)["url"] = url.spec();
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string key1;
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string key2;
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HttpUtil::HeadersIterator iter(headers_.begin(), headers_.end(), "\r\n");
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (iter.GetNext()) {
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(),
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             "connection")) {
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Ignore "Connection" header.
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(),
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    "upgrade")) {
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Ignore "Upgrade" header.
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(),
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    "sec-websocket-key1")) {
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Use only for generating challenge.
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      key1 = iter.values();
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(),
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    "sec-websocket-key2")) {
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Use only for generating challenge.
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      key2 = iter.values();
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Others should be sent out to |headers|.
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string name = StringToLowerASCII(iter.name());
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    spdy::SpdyHeaderBlock::iterator found = headers->find(name);
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (found == headers->end()) {
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (*headers)[name] = iter.values();
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // For now, websocket doesn't use multiple headers, but follows to http.
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      found->second.append(1, '\0');  // +=() doesn't append 0's
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      found->second.append(iter.values());
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  challenge->clear();
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetKeyNumber(key1, challenge);
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetKeyNumber(key2, challenge);
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  challenge->append(key3_);
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string WebSocketHandshakeRequestHandler::GetRawRequest() {
270dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(!status_line_.empty());
271dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(!headers_.empty());
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(kRequestKey3Size, key3_.size());
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string raw_request = status_line_ + headers_ + "\r\n" + key3_;
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  raw_length_ = raw_request.size();
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return raw_request;
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsize_t WebSocketHandshakeRequestHandler::raw_length() const {
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GT(raw_length_, 0);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return raw_length_;
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebSocketHandshakeResponseHandler::WebSocketHandshakeResponseHandler()
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : original_header_length_(0) {
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2873f50c38dc070f4bb515c1b64450dae14f316474eKristian MonsenWebSocketHandshakeResponseHandler::~WebSocketHandshakeResponseHandler() {}
2883f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsize_t WebSocketHandshakeResponseHandler::ParseRawResponse(
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* data, int length) {
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GT(length, 0);
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasResponse()) {
293dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    DCHECK(!status_line_.empty());
294dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    DCHECK(!headers_.empty());
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK_EQ(kResponseKeySize, key_.size());
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return 0;
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t old_original_length = original_.size();
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  original_.append(data, length);
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(ukai): fail fast when response gives wrong status code.
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  original_header_length_ = HttpUtil::LocateEndOfHeaders(
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      original_.data(), original_.size(), 0);
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!HasResponse())
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return length;
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ParseHandshakeHeader(original_.data(),
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       original_header_length_,
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       &status_line_,
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       &headers_);
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int header_size = status_line_.size() + headers_.size();
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GE(original_header_length_, header_size);
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  header_separator_ = std::string(original_.data() + header_size,
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  original_header_length_ - header_size);
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  key_ = std::string(original_.data() + original_header_length_,
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     kResponseKeySize);
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return original_header_length_ + kResponseKeySize - old_original_length;
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WebSocketHandshakeResponseHandler::HasResponse() const {
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return original_header_length_ > 0 &&
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      original_header_length_ + kResponseKeySize <= original_.size();
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WebSocketHandshakeResponseHandler::ParseResponseInfo(
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const HttpResponseInfo& response_info,
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& challenge) {
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!response_info.headers.get())
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string response_message;
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_message = response_info.headers->GetStatusLine();
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_message += "\r\n";
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_message += "Upgrade: WebSocket\r\n";
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_message += "Connection: Upgrade\r\n";
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void* iter = NULL;
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string name;
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string value;
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (response_info.headers->EnumerateHeaderLines(&iter, &name, &value)) {
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    response_message += name + ": " + value + "\r\n";
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_message += "\r\n";
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MD5Digest digest;
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MD5Sum(challenge.data(), challenge.size(), &digest);
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* digest_data = reinterpret_cast<char*>(digest.a);
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_message.append(digest_data, sizeof(digest.a));
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ParseRawResponse(response_message.data(),
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          response_message.size()) == response_message.size();
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock(
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const spdy::SpdyHeaderBlock& headers,
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& challenge) {
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string response_message;
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_message = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n";
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_message += "Upgrade: WebSocket\r\n";
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_message += "Connection: Upgrade\r\n";
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (spdy::SpdyHeaderBlock::const_iterator iter = headers.begin();
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       iter != headers.end();
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++iter) {
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // For each value, if the server sends a NUL-separated list of values,
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // we separate that back out into individual headers for each value
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // in the list.
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& value = iter->second;
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size_t start = 0;
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size_t end = 0;
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    do {
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      end = value.find('\0', start);
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::string tval;
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (end != std::string::npos)
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tval = value.substr(start, (end - start));
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      else
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tval = value.substr(start);
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      response_message += iter->first + ": " + tval + "\r\n";
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      start = end + 1;
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } while (end != std::string::npos);
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_message += "\r\n";
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MD5Digest digest;
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MD5Sum(challenge.data(), challenge.size(), &digest);
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* digest_data = reinterpret_cast<char*>(digest.a);
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_message.append(digest_data, sizeof(digest.a));
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ParseRawResponse(response_message.data(),
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          response_message.size()) == response_message.size();
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketHandshakeResponseHandler::GetHeaders(
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* const headers_to_get[],
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size_t headers_to_get_len,
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<std::string>* values) {
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(HasResponse());
400dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(!status_line_.empty());
401dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(!headers_.empty());
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(kResponseKeySize, key_.size());
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FetchHeaders(headers_, headers_to_get, headers_to_get_len, values);
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketHandshakeResponseHandler::RemoveHeaders(
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* const headers_to_remove[],
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size_t headers_to_remove_len) {
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(HasResponse());
411dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(!status_line_.empty());
412dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(!headers_.empty());
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(kResponseKeySize, key_.size());
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers_ = FilterHeaders(headers_, headers_to_remove, headers_to_remove_len);
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstd::string WebSocketHandshakeResponseHandler::GetRawResponse() const {
4193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(HasResponse());
4203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return std::string(original_.data(),
4213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                     original_header_length_ + kResponseKeySize);
4223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string WebSocketHandshakeResponseHandler::GetResponse() {
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(HasResponse());
426dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(!status_line_.empty());
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // headers_ might be empty for wrong response from server.
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(kResponseKeySize, key_.size());
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return status_line_ + headers_ + header_separator_ + key_;
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace net
434