12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/test/embedded_test_server/http_request.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)namespace net {
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace test_server {
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)size_t kRequestSizeLimit = 64 * 1024 * 1024;  // 64 mb.
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Helper function used to trim tokens in http request headers.
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string Trim(const std::string& value) {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string result;
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::TrimString(value, " \t", &result);
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result;
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpRequest::HttpRequest() : method(METHOD_UNKNOWN),
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             has_content(false) {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpRequest::~HttpRequest() {
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpRequestParser::HttpRequestParser()
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : http_request_(new HttpRequest()),
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      buffer_position_(0),
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_(STATE_HEADERS),
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      declared_content_length_(0) {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpRequestParser::~HttpRequestParser() {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HttpRequestParser::ProcessChunk(const base::StringPiece& data) {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  data.AppendToString(&buffer_);
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LE(buffer_.size() + data.size(), kRequestSizeLimit) <<
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "The HTTP request is too large.";
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string HttpRequestParser::ShiftLine() {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t eoln_position = buffer_.find("\r\n", buffer_position_);
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(std::string::npos, eoln_position);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int line_length = eoln_position - buffer_position_;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string result = buffer_.substr(buffer_position_, line_length);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  buffer_position_ += line_length + 2;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpRequestParser::ParseResult HttpRequestParser::ParseRequest() {
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(STATE_ACCEPTED, state_);
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Parse the request from beginning. However, entire request may not be
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // available in the buffer.
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ == STATE_HEADERS) {
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (ParseHeaders() == ACCEPTED)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return ACCEPTED;
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This should not be 'else if' of the previous block, as |state_| can be
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // changed in ParseHeaders().
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ == STATE_CONTENT) {
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (ParseContent() == ACCEPTED)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return ACCEPTED;
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return WAITING;
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpRequestParser::ParseResult HttpRequestParser::ParseHeaders() {
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check if the all request headers are available.
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (buffer_.find("\r\n\r\n", buffer_position_) == std::string::npos)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return WAITING;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Parse request's the first header line.
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Request main main header, eg. GET /foobar.html HTTP/1.1
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string header_line = ShiftLine();
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<std::string> header_line_tokens;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::SplitString(header_line, ' ', &header_line_tokens);
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(3u, header_line_tokens.size());
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Method.
926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    http_request_->method = GetMethodType(base::StringToLowerASCII(
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        header_line_tokens[0]));
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Address.
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Don't build an absolute URL as the parser does not know (should not
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // know) anything about the server address.
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    http_request_->relative_url = header_line_tokens[1];
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Protocol.
996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const std::string protocol =
1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        base::StringToLowerASCII(header_line_tokens[2]);
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK(protocol == "http/1.0" || protocol == "http/1.1") <<
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "Protocol not supported: " << protocol;
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Parse further headers.
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string header_name;
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    while (true) {
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string header_line = ShiftLine();
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (header_line.empty())
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (header_line[0] == ' ' || header_line[0] == '\t') {
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Continuation of the previous multi-line header.
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string header_value =
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Trim(header_line.substr(1, header_line.size() - 1));
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        http_request_->headers[header_name] += " " + header_value;
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // New header.
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        size_t delimiter_pos = header_line.find(":");
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DCHECK_NE(std::string::npos, delimiter_pos) << "Syntax error.";
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        header_name = Trim(header_line.substr(0, delimiter_pos));
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string header_value = Trim(header_line.substr(
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            delimiter_pos + 1,
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            header_line.size() - delimiter_pos - 1));
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        http_request_->headers[header_name] = header_value;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Headers done. Is any content data attached to the request?
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  declared_content_length_ = 0;
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (http_request_->headers.count("Content-Length") > 0) {
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    http_request_->has_content = true;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const bool success = base::StringToSizeT(
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        http_request_->headers["Content-Length"],
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &declared_content_length_);
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(success) << "Malformed Content-Length header's value.";
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (declared_content_length_ == 0) {
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // No content data, so parsing is finished.
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    state_ = STATE_ACCEPTED;
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ACCEPTED;
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The request has not yet been parsed yet, content data is still to be
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // processed.
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = STATE_CONTENT;
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return WAITING;
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpRequestParser::ParseResult HttpRequestParser::ParseContent() {
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const size_t available_bytes = buffer_.size() - buffer_position_;
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const size_t fetch_bytes = std::min(
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      available_bytes,
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      declared_content_length_ - http_request_->content.size());
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  http_request_->content.append(buffer_.data() + buffer_position_,
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                fetch_bytes);
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  buffer_position_ += fetch_bytes;
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (declared_content_length_ == http_request_->content.size()) {
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    state_ = STATE_ACCEPTED;
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ACCEPTED;
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = STATE_CONTENT;
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return WAITING;
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<HttpRequest> HttpRequestParser::GetRequest() {
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(STATE_ACCEPTED, state_);
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<HttpRequest> result = http_request_.Pass();
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Prepare for parsing a new request.
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = STATE_HEADERS;
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  http_request_.reset(new HttpRequest());
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  buffer_.clear();
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  buffer_position_ = 0;
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  declared_content_length_ = 0;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result.Pass();
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HttpMethod HttpRequestParser::GetMethodType(const std::string& token) const {
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (token == "get") {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return METHOD_GET;
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (token == "head") {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return METHOD_HEAD;
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (token == "post") {
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return METHOD_POST;
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (token == "put") {
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return METHOD_PUT;
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (token == "delete") {
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return METHOD_DELETE;
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (token == "patch") {
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return METHOD_PATCH;
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTREACHED() << "Method not implemented: " << token;
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return METHOD_UNKNOWN;
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace test_server
203b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}  // namespace net
204