1 // Copyright (c) 2012 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_test_utils.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 return true; 58 const BalsaHeaders* headers = message.headers(); 59 StringPiece content_length = headers->GetHeader(kContentLength); 60 if (!content_length.empty()) { 61 int parsed_content_length; 62 if (!base::StringToInt(content_length, &parsed_content_length)) { 63 return false; 64 } 65 return (message.body().size() == (uint)parsed_content_length); 66 } else { 67 // Assume messages without transfer coding or content-length are 68 // tagged correctly. 69 return message.has_complete_message(); 70 } 71 } 72 73 } // namespace 74 75 HTTPMessage::Method HTTPMessage::StringToMethod(StringPiece str) { 76 // Skip the first element of the array since it is empty string. 77 for (unsigned long i = 1; i < arraysize(kMethodString); ++i) { 78 if (strncmp(str.data(), kMethodString[i], str.length()) == 0) { 79 return static_cast<HTTPMessage::Method>(i); 80 } 81 } 82 return HttpConstants::UNKNOWN_METHOD; 83 } 84 85 HTTPMessage::Version HTTPMessage::StringToVersion(StringPiece str) { 86 // Skip the first element of the array since it is empty string. 87 for (unsigned long i = 1; i < arraysize(kHTTPVersionString); ++i) { 88 if (strncmp(str.data(), kHTTPVersionString[i], str.length()) == 0) { 89 return static_cast<HTTPMessage::Version>(i); 90 } 91 } 92 return HttpConstants::HTTP_UNKNOWN; 93 } 94 95 const char* HTTPMessage::MethodToString(Method method) { 96 CHECK_LT(static_cast<size_t>(method), arraysize(kMethodString)); 97 return kMethodString[method]; 98 } 99 100 const char* HTTPMessage::VersionToString(Version version) { 101 CHECK_LT(static_cast<size_t>(version), arraysize(kHTTPVersionString)); 102 return kHTTPVersionString[version]; 103 } 104 105 HTTPMessage::HTTPMessage() 106 : is_request_(true) { 107 InitializeFields(); 108 } 109 110 HTTPMessage::HTTPMessage(Version ver, Method request, const string& path) 111 : is_request_(true) { 112 InitializeFields(); 113 if (ver != HttpConstants::HTTP_0_9) { 114 headers()->SetRequestVersion(VersionToString(ver)); 115 } 116 headers()->SetRequestMethod(MethodToString(request)); 117 headers()->SetRequestUri(path); 118 } 119 120 HTTPMessage::~HTTPMessage() { 121 } 122 123 void HTTPMessage::InitializeFields() { 124 has_complete_message_ = true; 125 skip_message_validation_ = false; 126 } 127 128 void HTTPMessage::AddHeader(const string& header, const string& value) { 129 headers()->AppendHeader(header, value); 130 } 131 132 void HTTPMessage::RemoveHeader(const string& header) { 133 headers()->RemoveAllOfHeader(header); 134 } 135 136 void HTTPMessage::ReplaceHeader(const string& header, const string& value) { 137 headers()->ReplaceOrAppendHeader(header, value); 138 } 139 140 void HTTPMessage::AddBody(const string& body, bool add_content_length) { 141 body_ = body; 142 // Remove any transfer-encoding that was left by a previous body. 143 RemoveHeader(kTransferCoding); 144 if (add_content_length) { 145 ReplaceHeader(kContentLength, base::IntToString(body.size())); 146 } else { 147 RemoveHeader(kContentLength); 148 } 149 } 150 151 void HTTPMessage::ValidateMessage() const { 152 if (skip_message_validation_) { 153 return; 154 } 155 156 vector<StringPiece> transfer_encodings; 157 headers()->GetAllOfHeader(kTransferCoding, &transfer_encodings); 158 CHECK_GE(1ul, transfer_encodings.size()); 159 for (vector<StringPiece>::iterator it = transfer_encodings.begin(); 160 it != transfer_encodings.end(); 161 ++it) { 162 CHECK(StringPieceUtils::EqualIgnoreCase("identity", *it) || 163 StringPieceUtils::EqualIgnoreCase("chunked", *it)) << *it; 164 } 165 166 vector<StringPiece> content_lengths; 167 headers()->GetAllOfHeader(kContentLength, &content_lengths); 168 CHECK_GE(1ul, content_lengths.size()); 169 170 CHECK_EQ(has_complete_message_, IsCompleteMessage(*this)); 171 } 172 173 } // namespace test 174 } // namespace tools 175 } // namespace net 176