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