summaryrefslogtreecommitdiff
path: root/chromium/net/tools/quic/test_tools/http_message_test_utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/tools/quic/test_tools/http_message_test_utils.cc')
-rw-r--r--chromium/net/tools/quic/test_tools/http_message_test_utils.cc175
1 files changed, 175 insertions, 0 deletions
diff --git a/chromium/net/tools/quic/test_tools/http_message_test_utils.cc b/chromium/net/tools/quic/test_tools/http_message_test_utils.cc
new file mode 100644
index 00000000000..7d6df7a7649
--- /dev/null
+++ b/chromium/net/tools/quic/test_tools/http_message_test_utils.cc
@@ -0,0 +1,175 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/tools/quic/test_tools/http_message_test_utils.h"
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+
+using base::StringPiece;
+using std::string;
+using std::vector;
+
+namespace net {
+namespace tools {
+namespace test {
+
+namespace {
+
+//const char* kContentEncoding = "content-encoding";
+const char* kContentLength = "content-length";
+const char* kTransferCoding = "transfer-encoding";
+
+// Both kHTTPVersionString and kMethodString arrays are constructed to match
+// the enum values defined in Version and Method of HTTPMessage.
+const char* kHTTPVersionString[] = {
+ "",
+ "HTTP/0.9",
+ "HTTP/1.0",
+ "HTTP/1.1"
+};
+
+const char* kMethodString[] = {
+ "",
+ "OPTIONS",
+ "GET",
+ "HEAD",
+ "POST",
+ "PUT",
+ "DELETE",
+ "TRACE",
+ "CONNECT",
+ "MKCOL",
+ "UNLOCK",
+};
+
+// Returns true if the message represents a complete request or response.
+// Messages are considered complete if:
+// - Transfer-Encoding: chunked is present and message has a final chunk.
+// - Content-Length header is present and matches the message body length.
+// - Neither Transfer-Encoding nor Content-Length is present and message
+// is tagged as complete.
+bool IsCompleteMessage(const HTTPMessage& message) {
+ return true;
+ const BalsaHeaders* headers = message.headers();
+ StringPiece content_length = headers->GetHeader(kContentLength);
+ if (!content_length.empty()) {
+ int parsed_content_length;
+ if (!base::StringToInt(content_length, &parsed_content_length)) {
+ return false;
+ }
+ return (message.body().size() == (uint)parsed_content_length);
+ } else {
+ // Assume messages without transfer coding or content-length are
+ // tagged correctly.
+ return message.has_complete_message();
+ }
+}
+
+} // namespace
+
+HTTPMessage::Method HTTPMessage::StringToMethod(StringPiece str) {
+ // Skip the first element of the array since it is empty string.
+ for (unsigned long i = 1; i < arraysize(kMethodString); ++i) {
+ if (strncmp(str.data(), kMethodString[i], str.length()) == 0) {
+ return static_cast<HTTPMessage::Method>(i);
+ }
+ }
+ return HttpConstants::UNKNOWN_METHOD;
+}
+
+HTTPMessage::Version HTTPMessage::StringToVersion(StringPiece str) {
+ // Skip the first element of the array since it is empty string.
+ for (unsigned long i = 1; i < arraysize(kHTTPVersionString); ++i) {
+ if (strncmp(str.data(), kHTTPVersionString[i], str.length()) == 0) {
+ return static_cast<HTTPMessage::Version>(i);
+ }
+ }
+ return HttpConstants::HTTP_UNKNOWN;
+}
+
+const char* HTTPMessage::MethodToString(Method method) {
+ CHECK_LT(static_cast<size_t>(method), arraysize(kMethodString));
+ return kMethodString[method];
+}
+
+const char* HTTPMessage::VersionToString(Version version) {
+ CHECK_LT(static_cast<size_t>(version), arraysize(kHTTPVersionString));
+ return kHTTPVersionString[version];
+}
+
+HTTPMessage::HTTPMessage()
+ : is_request_(true) {
+ InitializeFields();
+}
+
+HTTPMessage::HTTPMessage(Version ver, Method request, const string& path)
+ : is_request_(true) {
+ InitializeFields();
+ if (ver != HttpConstants::HTTP_0_9) {
+ headers()->SetRequestVersion(VersionToString(ver));
+ }
+ headers()->SetRequestMethod(MethodToString(request));
+ headers()->SetRequestUri(path);
+}
+
+HTTPMessage::~HTTPMessage() {
+}
+
+void HTTPMessage::InitializeFields() {
+ has_complete_message_ = true;
+ skip_message_validation_ = false;
+}
+
+void HTTPMessage::AddHeader(const string& header, const string& value) {
+ headers()->AppendHeader(header, value);
+}
+
+void HTTPMessage::RemoveHeader(const string& header) {
+ headers()->RemoveAllOfHeader(header);
+}
+
+void HTTPMessage::ReplaceHeader(const string& header, const string& value) {
+ headers()->ReplaceOrAppendHeader(header, value);
+}
+
+void HTTPMessage::AddBody(const string& body, bool add_content_length) {
+ body_ = body;
+ // Remove any transfer-encoding that was left by a previous body.
+ RemoveHeader(kTransferCoding);
+ if (add_content_length) {
+ ReplaceHeader(kContentLength, base::IntToString(body.size()));
+ } else {
+ RemoveHeader(kContentLength);
+ }
+}
+
+void HTTPMessage::ValidateMessage() const {
+ if (skip_message_validation_) {
+ return;
+ }
+
+ vector<StringPiece> transfer_encodings;
+ headers()->GetAllOfHeader(kTransferCoding, &transfer_encodings);
+ CHECK_GE(1ul, transfer_encodings.size());
+ for (vector<StringPiece>::iterator it = transfer_encodings.begin();
+ it != transfer_encodings.end();
+ ++it) {
+ CHECK(StringPieceUtils::EqualIgnoreCase("identity", *it) ||
+ StringPieceUtils::EqualIgnoreCase("chunked", *it)) << *it;
+ }
+
+ vector<StringPiece> content_lengths;
+ headers()->GetAllOfHeader(kContentLength, &content_lengths);
+ CHECK_GE(1ul, content_lengths.size());
+
+ CHECK_EQ(has_complete_message_, IsCompleteMessage(*this));
+}
+
+} // namespace test
+} // namespace tools
+} // namespace net