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.
5 #include "net/tools/quic/test_tools/http_message.h"
9 #include "base/basictypes.h"
10 #include "base/logging.h"
11 #include "base/strings/string_number_conversions.h"
13 using base::StringPiece
;
23 //const char kContentEncoding[] = "content-encoding";
24 const char kContentLength
[] = "content-length";
25 const char kTransferCoding
[] = "transfer-encoding";
27 // Both kHTTPVersionString and kMethodString arrays are constructed to match
28 // the enum values defined in Version and Method of HTTPMessage.
29 const char* const kHTTPVersionString
[] = {
36 const char* const kMethodString
[] = {
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
)) {
64 return (message
.body().size() == (uint
)parsed_content_length
);
66 // Assume messages without transfer coding or content-length are
68 return message
.has_complete_message();
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
);
81 return HttpConstants::UNKNOWN_METHOD
;
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
);
91 return HttpConstants::HTTP_UNKNOWN
;
94 const char* HTTPMessage::MethodToString(Method method
) {
95 CHECK_LT(static_cast<size_t>(method
), arraysize(kMethodString
));
96 return kMethodString
[method
];
99 const char* HTTPMessage::VersionToString(Version version
) {
100 CHECK_LT(static_cast<size_t>(version
), arraysize(kHTTPVersionString
));
101 return kHTTPVersionString
[version
];
104 HTTPMessage::HTTPMessage()
105 : is_request_(true) {
109 HTTPMessage::HTTPMessage(Version ver
, Method request
, const string
& path
)
110 : is_request_(true) {
112 if (ver
!= HttpConstants::HTTP_0_9
) {
113 headers()->SetRequestVersion(VersionToString(ver
));
115 headers()->SetRequestMethod(MethodToString(request
));
116 headers()->SetRequestUri(path
);
119 HTTPMessage::~HTTPMessage() {
122 void HTTPMessage::InitializeFields() {
123 has_complete_message_
= true;
124 skip_message_validation_
= false;
127 void HTTPMessage::AddHeader(const string
& header
, const string
& value
) {
128 headers()->AppendHeader(header
, value
);
131 void HTTPMessage::RemoveHeader(const string
& header
) {
132 headers()->RemoveAllOfHeader(header
);
135 void HTTPMessage::ReplaceHeader(const string
& header
, const string
& value
) {
136 headers()->ReplaceOrAppendHeader(header
, value
);
139 void HTTPMessage::AddBody(const string
& body
, bool add_content_length
) {
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()));
146 RemoveHeader(kContentLength
);
150 void HTTPMessage::ValidateMessage() const {
151 if (skip_message_validation_
) {
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();
161 CHECK(StringPieceUtils::EqualIgnoreCase("identity", *it
) ||
162 StringPieceUtils::EqualIgnoreCase("chunked", *it
)) << *it
;
165 vector
<StringPiece
> content_lengths
;
166 headers()->GetAllOfHeader(kContentLength
, &content_lengths
);
167 CHECK_GE(1ul, content_lengths
.size());
169 CHECK_EQ(has_complete_message_
, IsCompleteMessage(*this));