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