1885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// Copyright 2014 The Chromium Authors. All rights reserved.
2885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// Use of this source code is governed by a BSD-style license that can be
3885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// found in the LICENSE file.
4885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
5885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "net/tools/quic/test_tools/http_message.h"
6885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
7885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include <vector>
8885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
9885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "base/basictypes.h"
10885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "base/logging.h"
11885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "base/strings/string_number_conversions.h"
12885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
13885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgusing base::StringPiece;
14885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgusing std::string;
15885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgusing std::vector;
16885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
17885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgnamespace net {
18885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgnamespace tools {
19885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgnamespace test {
20885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
21885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgnamespace {
22885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
23885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org//const char* kContentEncoding = "content-encoding";
24885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgconst char* kContentLength = "content-length";
25885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgconst char* kTransferCoding = "transfer-encoding";
26885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
27885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// Both kHTTPVersionString and kMethodString arrays are constructed to match
28885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// the enum values defined in Version and Method of HTTPMessage.
29885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgconst char* kHTTPVersionString[] = {
30885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "",
31885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "HTTP/0.9",
32885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "HTTP/1.0",
33885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "HTTP/1.1"
34885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org};
35885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
36885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgconst char* kMethodString[] = {
37885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "",
38885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "OPTIONS",
39885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "GET",
40885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "HEAD",
41885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "POST",
42885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "PUT",
43885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "DELETE",
44885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "TRACE",
45885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "CONNECT",
46885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "MKCOL",
47885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  "UNLOCK",
48885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org};
49885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
50885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// Returns true if the message represents a complete request or response.
51885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// Messages are considered complete if:
52885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// - Transfer-Encoding: chunked is present and message has a final chunk.
53885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// - Content-Length header is present and matches the message body length.
54885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// - Neither Transfer-Encoding nor Content-Length is present and message
55885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org//   is tagged as complete.
56885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgbool IsCompleteMessage(const HTTPMessage& message) {
57885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  const BalsaHeaders* headers = message.headers();
58885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  StringPiece content_length = headers->GetHeader(kContentLength);
59885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  if (!content_length.empty()) {
60885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    int parsed_content_length;
61885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if (!base::StringToInt(content_length, &parsed_content_length)) {
62885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return false;
63885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
64885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    return (message.body().size() == (uint)parsed_content_length);
65885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  } else {
66885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    // Assume messages without transfer coding or content-length are
67885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    // tagged correctly.
68885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    return message.has_complete_message();
69885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
70885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
71885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
72885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}  // namespace
73885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
74885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgHTTPMessage::Method HTTPMessage::StringToMethod(StringPiece str) {
75885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  // Skip the first element of the array since it is empty string.
76885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  for (unsigned long i = 1; i < arraysize(kMethodString); ++i) {
77885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if (strncmp(str.data(), kMethodString[i], str.length()) == 0) {
78885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return static_cast<HTTPMessage::Method>(i);
79885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
80885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
81885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  return HttpConstants::UNKNOWN_METHOD;
82885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
83885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
84885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgHTTPMessage::Version HTTPMessage::StringToVersion(StringPiece str) {
85885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  // Skip the first element of the array since it is empty string.
86885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  for (unsigned long i = 1; i < arraysize(kHTTPVersionString); ++i) {
87885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if (strncmp(str.data(), kHTTPVersionString[i], str.length()) == 0) {
88885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return static_cast<HTTPMessage::Version>(i);
89885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
90885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
91885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  return HttpConstants::HTTP_UNKNOWN;
92885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
93885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
94885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgconst char* HTTPMessage::MethodToString(Method method) {
95885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  CHECK_LT(static_cast<size_t>(method), arraysize(kMethodString));
96885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  return kMethodString[method];
97885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
98885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
99885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgconst char* HTTPMessage::VersionToString(Version version) {
100885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  CHECK_LT(static_cast<size_t>(version), arraysize(kHTTPVersionString));
101885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  return kHTTPVersionString[version];
102885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
103885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
104885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgHTTPMessage::HTTPMessage()
105885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    : is_request_(true) {
106885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  InitializeFields();
107885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
108885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
109885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgHTTPMessage::HTTPMessage(Version ver, Method request, const string& path)
110885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    : is_request_(true) {
111885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  InitializeFields();
112885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  if (ver != HttpConstants::HTTP_0_9) {
113885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    headers()->SetRequestVersion(VersionToString(ver));
114885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
115885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  headers()->SetRequestMethod(MethodToString(request));
116885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  headers()->SetRequestUri(path);
117885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
118885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
119885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgHTTPMessage::~HTTPMessage() {
120885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
121885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
122885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid HTTPMessage::InitializeFields() {
123885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  has_complete_message_ = true;
124885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  skip_message_validation_ = false;
125885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
126885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
127885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid HTTPMessage::AddHeader(const string& header, const string& value) {
128885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  headers()->AppendHeader(header, value);
129885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
130885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
131885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid HTTPMessage::RemoveHeader(const string& header) {
132885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  headers()->RemoveAllOfHeader(header);
133885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
134885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
135885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid HTTPMessage::ReplaceHeader(const string& header, const string& value) {
136885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  headers()->ReplaceOrAppendHeader(header, value);
137885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
138885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
139885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid HTTPMessage::AddBody(const string& body, bool add_content_length) {
140885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  body_ = body;
141885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  // Remove any transfer-encoding that was left by a previous body.
142885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  RemoveHeader(kTransferCoding);
143885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  if (add_content_length) {
144885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ReplaceHeader(kContentLength, base::IntToString(body.size()));
145885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  } else {
146885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    RemoveHeader(kContentLength);
147885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
148885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
149885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
150885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid HTTPMessage::ValidateMessage() const {
151885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  if (skip_message_validation_) {
152885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    return;
153885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
154885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
155885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  vector<StringPiece> transfer_encodings;
156885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  headers()->GetAllOfHeader(kTransferCoding, &transfer_encodings);
157885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  CHECK_GE(1ul, transfer_encodings.size());
158885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  for (vector<StringPiece>::iterator it = transfer_encodings.begin();
159885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org       it != transfer_encodings.end();
160885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org       ++it) {
161885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    CHECK(StringPieceUtils::EqualIgnoreCase("identity", *it) ||
162885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org          StringPieceUtils::EqualIgnoreCase("chunked", *it)) << *it;
163885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
164885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
165885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  vector<StringPiece> content_lengths;
166885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  headers()->GetAllOfHeader(kContentLength, &content_lengths);
167885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  CHECK_GE(1ul, content_lengths.size());
168885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
169885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  CHECK_EQ(has_complete_message_, IsCompleteMessage(*this));
170885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
171885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
172885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}  // namespace test
173885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}  // namespace tools
174885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}  // namespace net
175885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org