1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "net/tools/quic/test_tools/http_message.h" 6 7#include <vector> 8 9#include "base/basictypes.h" 10#include "base/logging.h" 11#include "base/strings/string_number_conversions.h" 12 13using base::StringPiece; 14using std::string; 15using std::vector; 16 17namespace net { 18namespace tools { 19namespace test { 20 21namespace { 22 23//const char* kContentEncoding = "content-encoding"; 24const char* kContentLength = "content-length"; 25const char* kTransferCoding = "transfer-encoding"; 26 27// Both kHTTPVersionString and kMethodString arrays are constructed to match 28// the enum values defined in Version and Method of HTTPMessage. 29const char* kHTTPVersionString[] = { 30 "", 31 "HTTP/0.9", 32 "HTTP/1.0", 33 "HTTP/1.1" 34}; 35 36const char* kMethodString[] = { 37 "", 38 "OPTIONS", 39 "GET", 40 "HEAD", 41 "POST", 42 "PUT", 43 "DELETE", 44 "TRACE", 45 "CONNECT", 46 "MKCOL", 47 "UNLOCK", 48}; 49 50// Returns true if the message represents a complete request or response. 51// Messages are considered complete if: 52// - Transfer-Encoding: chunked is present and message has a final chunk. 53// - Content-Length header is present and matches the message body length. 54// - Neither Transfer-Encoding nor Content-Length is present and message 55// is tagged as complete. 56bool IsCompleteMessage(const HTTPMessage& message) { 57 const BalsaHeaders* headers = message.headers(); 58 StringPiece content_length = headers->GetHeader(kContentLength); 59 if (!content_length.empty()) { 60 int parsed_content_length; 61 if (!base::StringToInt(content_length, &parsed_content_length)) { 62 return false; 63 } 64 return (message.body().size() == (uint)parsed_content_length); 65 } else { 66 // Assume messages without transfer coding or content-length are 67 // tagged correctly. 68 return message.has_complete_message(); 69 } 70} 71 72} // namespace 73 74HTTPMessage::Method HTTPMessage::StringToMethod(StringPiece str) { 75 // Skip the first element of the array since it is empty string. 76 for (unsigned long i = 1; i < arraysize(kMethodString); ++i) { 77 if (strncmp(str.data(), kMethodString[i], str.length()) == 0) { 78 return static_cast<HTTPMessage::Method>(i); 79 } 80 } 81 return HttpConstants::UNKNOWN_METHOD; 82} 83 84HTTPMessage::Version HTTPMessage::StringToVersion(StringPiece str) { 85 // Skip the first element of the array since it is empty string. 86 for (unsigned long i = 1; i < arraysize(kHTTPVersionString); ++i) { 87 if (strncmp(str.data(), kHTTPVersionString[i], str.length()) == 0) { 88 return static_cast<HTTPMessage::Version>(i); 89 } 90 } 91 return HttpConstants::HTTP_UNKNOWN; 92} 93 94const char* HTTPMessage::MethodToString(Method method) { 95 CHECK_LT(static_cast<size_t>(method), arraysize(kMethodString)); 96 return kMethodString[method]; 97} 98 99const char* HTTPMessage::VersionToString(Version version) { 100 CHECK_LT(static_cast<size_t>(version), arraysize(kHTTPVersionString)); 101 return kHTTPVersionString[version]; 102} 103 104HTTPMessage::HTTPMessage() 105 : is_request_(true) { 106 InitializeFields(); 107} 108 109HTTPMessage::HTTPMessage(Version ver, Method request, const string& path) 110 : is_request_(true) { 111 InitializeFields(); 112 if (ver != HttpConstants::HTTP_0_9) { 113 headers()->SetRequestVersion(VersionToString(ver)); 114 } 115 headers()->SetRequestMethod(MethodToString(request)); 116 headers()->SetRequestUri(path); 117} 118 119HTTPMessage::~HTTPMessage() { 120} 121 122void HTTPMessage::InitializeFields() { 123 has_complete_message_ = true; 124 skip_message_validation_ = false; 125} 126 127void HTTPMessage::AddHeader(const string& header, const string& value) { 128 headers()->AppendHeader(header, value); 129} 130 131void HTTPMessage::RemoveHeader(const string& header) { 132 headers()->RemoveAllOfHeader(header); 133} 134 135void HTTPMessage::ReplaceHeader(const string& header, const string& value) { 136 headers()->ReplaceOrAppendHeader(header, value); 137} 138 139void HTTPMessage::AddBody(const string& body, bool add_content_length) { 140 body_ = body; 141 // Remove any transfer-encoding that was left by a previous body. 142 RemoveHeader(kTransferCoding); 143 if (add_content_length) { 144 ReplaceHeader(kContentLength, base::IntToString(body.size())); 145 } else { 146 RemoveHeader(kContentLength); 147 } 148} 149 150void HTTPMessage::ValidateMessage() const { 151 if (skip_message_validation_) { 152 return; 153 } 154 155 vector<StringPiece> transfer_encodings; 156 headers()->GetAllOfHeader(kTransferCoding, &transfer_encodings); 157 CHECK_GE(1ul, transfer_encodings.size()); 158 for (vector<StringPiece>::iterator it = transfer_encodings.begin(); 159 it != transfer_encodings.end(); 160 ++it) { 161 CHECK(StringPieceUtils::EqualIgnoreCase("identity", *it) || 162 StringPieceUtils::EqualIgnoreCase("chunked", *it)) << *it; 163 } 164 165 vector<StringPiece> content_lengths; 166 headers()->GetAllOfHeader(kContentLength, &content_lengths); 167 CHECK_GE(1ul, content_lengths.size()); 168 169 CHECK_EQ(has_complete_message_, IsCompleteMessage(*this)); 170} 171 172} // namespace test 173} // namespace tools 174} // namespace net 175