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 13 using base::StringPiece; 14 using std::string; 15 using std::vector; 16 17 namespace net { 18 namespace tools { 19 namespace test { 20 21 namespace { 22 23 //const char* kContentEncoding = "content-encoding"; 24 const char* kContentLength = "content-length"; 25 const 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. 29 const char* kHTTPVersionString[] = { 30 "", 31 "HTTP/0.9", 32 "HTTP/1.0", 33 "HTTP/1.1" 34 }; 35 36 const 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. 56 bool 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 74 HTTPMessage::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 84 HTTPMessage::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 94 const char* HTTPMessage::MethodToString(Method method) { 95 CHECK_LT(static_cast<size_t>(method), arraysize(kMethodString)); 96 return kMethodString[method]; 97 } 98 99 const char* HTTPMessage::VersionToString(Version version) { 100 CHECK_LT(static_cast<size_t>(version), arraysize(kHTTPVersionString)); 101 return kHTTPVersionString[version]; 102 } 103 104 HTTPMessage::HTTPMessage() 105 : is_request_(true) { 106 InitializeFields(); 107 } 108 109 HTTPMessage::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 119 HTTPMessage::~HTTPMessage() { 120 } 121 122 void HTTPMessage::InitializeFields() { 123 has_complete_message_ = true; 124 skip_message_validation_ = false; 125 } 126 127 void HTTPMessage::AddHeader(const string& header, const string& value) { 128 headers()->AppendHeader(header, value); 129 } 130 131 void HTTPMessage::RemoveHeader(const string& header) { 132 headers()->RemoveAllOfHeader(header); 133 } 134 135 void HTTPMessage::ReplaceHeader(const string& header, const string& value) { 136 headers()->ReplaceOrAppendHeader(header, value); 137 } 138 139 void 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 150 void 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