Home | History | Annotate | Download | only in test_tools
      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