| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/core/spdy_utils.h" | 5 #include "net/quic/core/spdy_utils.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| 11 #include "net/quic/platform/api/quic_logging.h" |
| 11 #include "net/quic/platform/api/quic_text_utils.h" | 12 #include "net/quic/platform/api/quic_text_utils.h" |
| 12 #include "net/spdy/spdy_flags.h" | 13 #include "net/spdy/spdy_flags.h" |
| 13 #include "net/spdy/spdy_frame_builder.h" | 14 #include "net/spdy/spdy_frame_builder.h" |
| 14 #include "net/spdy/spdy_framer.h" | 15 #include "net/spdy/spdy_framer.h" |
| 15 #include "net/spdy/spdy_protocol.h" | 16 #include "net/spdy/spdy_protocol.h" |
| 16 #include "url/gurl.h" | 17 #include "url/gurl.h" |
| 17 | 18 |
| 18 using base::StringPiece; | 19 using base::StringPiece; |
| 19 using base::ContainsKey; | 20 using base::ContainsKey; |
| 20 using std::string; | 21 using std::string; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 if (it == headers->end()) { | 57 if (it == headers->end()) { |
| 57 return false; | 58 return false; |
| 58 } else { | 59 } else { |
| 59 // Check whether multiple values are consistent. | 60 // Check whether multiple values are consistent. |
| 60 StringPiece content_length_header = it->second; | 61 StringPiece content_length_header = it->second; |
| 61 std::vector<StringPiece> values = | 62 std::vector<StringPiece> values = |
| 62 QuicTextUtils::Split(content_length_header, '\0'); | 63 QuicTextUtils::Split(content_length_header, '\0'); |
| 63 for (const StringPiece& value : values) { | 64 for (const StringPiece& value : values) { |
| 64 int64_t new_value; | 65 int64_t new_value; |
| 65 if (!base::StringToInt64(value, &new_value) || new_value < 0) { | 66 if (!base::StringToInt64(value, &new_value) || new_value < 0) { |
| 66 DLOG(ERROR) << "Content length was either unparseable or negative."; | 67 QUIC_DLOG(ERROR) |
| 68 << "Content length was either unparseable or negative."; |
| 67 return false; | 69 return false; |
| 68 } | 70 } |
| 69 if (*content_length < 0) { | 71 if (*content_length < 0) { |
| 70 *content_length = new_value; | 72 *content_length = new_value; |
| 71 continue; | 73 continue; |
| 72 } | 74 } |
| 73 if (new_value != *content_length) { | 75 if (new_value != *content_length) { |
| 74 DLOG(ERROR) << "Parsed content length " << new_value << " is " | 76 QUIC_DLOG(ERROR) |
| 75 << "inconsistent with previously detected content length " | 77 << "Parsed content length " << new_value << " is " |
| 76 << *content_length; | 78 << "inconsistent with previously detected content length " |
| 79 << *content_length; |
| 77 return false; | 80 return false; |
| 78 } | 81 } |
| 79 } | 82 } |
| 80 return true; | 83 return true; |
| 81 } | 84 } |
| 82 } | 85 } |
| 83 | 86 |
| 84 // static | 87 // static |
| 85 bool SpdyUtils::ParseTrailers(const char* data, | 88 bool SpdyUtils::ParseTrailers(const char* data, |
| 86 uint32_t data_len, | 89 uint32_t data_len, |
| 87 size_t* final_byte_offset, | 90 size_t* final_byte_offset, |
| 88 SpdyHeaderBlock* trailers) { | 91 SpdyHeaderBlock* trailers) { |
| 89 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | 92 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); |
| 90 if (!framer.ParseHeaderBlockInBuffer(data, data_len, trailers) || | 93 if (!framer.ParseHeaderBlockInBuffer(data, data_len, trailers) || |
| 91 trailers->empty()) { | 94 trailers->empty()) { |
| 92 DVLOG(1) << "Request Trailers are invalid."; | 95 QUIC_DVLOG(1) << "Request Trailers are invalid."; |
| 93 return false; // Trailers were invalid. | 96 return false; // Trailers were invalid. |
| 94 } | 97 } |
| 95 | 98 |
| 96 // Pull out the final offset pseudo header which indicates the number of | 99 // Pull out the final offset pseudo header which indicates the number of |
| 97 // response body bytes expected. | 100 // response body bytes expected. |
| 98 auto it = trailers->find(kFinalOffsetHeaderKey); | 101 auto it = trailers->find(kFinalOffsetHeaderKey); |
| 99 if (it == trailers->end() || | 102 if (it == trailers->end() || |
| 100 !base::StringToSizeT(it->second, final_byte_offset)) { | 103 !base::StringToSizeT(it->second, final_byte_offset)) { |
| 101 DVLOG(1) << "Required key '" << kFinalOffsetHeaderKey << "' not present"; | 104 QUIC_DVLOG(1) << "Required key '" << kFinalOffsetHeaderKey |
| 105 << "' not present"; |
| 102 return false; | 106 return false; |
| 103 } | 107 } |
| 104 // The final offset header is no longer needed. | 108 // The final offset header is no longer needed. |
| 105 trailers->erase(it->first); | 109 trailers->erase(it->first); |
| 106 | 110 |
| 107 // Trailers must not have empty keys, and must not contain pseudo headers. | 111 // Trailers must not have empty keys, and must not contain pseudo headers. |
| 108 for (const auto& trailer : *trailers) { | 112 for (const auto& trailer : *trailers) { |
| 109 StringPiece key = trailer.first; | 113 StringPiece key = trailer.first; |
| 110 StringPiece value = trailer.second; | 114 StringPiece value = trailer.second; |
| 111 if (QuicTextUtils::StartsWith(key, ":")) { | 115 if (QuicTextUtils::StartsWith(key, ":")) { |
| 112 DVLOG(1) << "Trailers must not contain pseudo-header: '" << key << "','" | 116 QUIC_DVLOG(1) << "Trailers must not contain pseudo-header: '" << key |
| 113 << value << "'."; | 117 << "','" << value << "'."; |
| 114 return false; | 118 return false; |
| 115 } | 119 } |
| 116 | 120 |
| 117 // TODO(rjshade): Check for other forbidden keys, following the HTTP/2 spec. | 121 // TODO(rjshade): Check for other forbidden keys, following the HTTP/2 spec. |
| 118 } | 122 } |
| 119 | 123 |
| 120 DVLOG(1) << "Successfully parsed Trailers."; | 124 QUIC_DVLOG(1) << "Successfully parsed Trailers."; |
| 121 return true; | 125 return true; |
| 122 } | 126 } |
| 123 | 127 |
| 124 bool SpdyUtils::CopyAndValidateHeaders(const QuicHeaderList& header_list, | 128 bool SpdyUtils::CopyAndValidateHeaders(const QuicHeaderList& header_list, |
| 125 int64_t* content_length, | 129 int64_t* content_length, |
| 126 SpdyHeaderBlock* headers) { | 130 SpdyHeaderBlock* headers) { |
| 127 for (const auto& p : header_list) { | 131 for (const auto& p : header_list) { |
| 128 const string& name = p.first; | 132 const string& name = p.first; |
| 129 if (name.empty()) { | 133 if (name.empty()) { |
| 130 DVLOG(1) << "Header name must not be empty."; | 134 QUIC_DVLOG(1) << "Header name must not be empty."; |
| 131 return false; | 135 return false; |
| 132 } | 136 } |
| 133 | 137 |
| 134 if (QuicTextUtils::ContainsUpperCase(name)) { | 138 if (QuicTextUtils::ContainsUpperCase(name)) { |
| 135 DVLOG(1) << "Malformed header: Header name " << name | 139 QUIC_DLOG(ERROR) << "Malformed header: Header name " << name |
| 136 << " contains upper-case characters."; | 140 << " contains upper-case characters."; |
| 137 return false; | 141 return false; |
| 138 } | 142 } |
| 139 | 143 |
| 140 headers->AppendValueOrAddHeader(name, p.second); | 144 headers->AppendValueOrAddHeader(name, p.second); |
| 141 } | 145 } |
| 142 | 146 |
| 143 if (ContainsKey(*headers, "content-length") && | 147 if (ContainsKey(*headers, "content-length") && |
| 144 !ExtractContentLengthFromHeaders(content_length, headers)) { | 148 !ExtractContentLengthFromHeaders(content_length, headers)) { |
| 145 return false; | 149 return false; |
| 146 } | 150 } |
| 147 | 151 |
| 148 DVLOG(1) << "Successfully parsed headers: " << headers->DebugString(); | 152 QUIC_DVLOG(1) << "Successfully parsed headers: " << headers->DebugString(); |
| 149 return true; | 153 return true; |
| 150 } | 154 } |
| 151 | 155 |
| 152 bool SpdyUtils::CopyAndValidateTrailers(const QuicHeaderList& header_list, | 156 bool SpdyUtils::CopyAndValidateTrailers(const QuicHeaderList& header_list, |
| 153 size_t* final_byte_offset, | 157 size_t* final_byte_offset, |
| 154 SpdyHeaderBlock* trailers) { | 158 SpdyHeaderBlock* trailers) { |
| 155 bool found_final_byte_offset = false; | 159 bool found_final_byte_offset = false; |
| 156 for (const auto& p : header_list) { | 160 for (const auto& p : header_list) { |
| 157 const string& name = p.first; | 161 const string& name = p.first; |
| 158 | 162 |
| 159 // Pull out the final offset pseudo header which indicates the number of | 163 // Pull out the final offset pseudo header which indicates the number of |
| 160 // response body bytes expected. | 164 // response body bytes expected. |
| 161 int offset; | 165 int offset; |
| 162 if (!found_final_byte_offset && name == kFinalOffsetHeaderKey && | 166 if (!found_final_byte_offset && name == kFinalOffsetHeaderKey && |
| 163 base::StringToInt(p.second, &offset)) { | 167 base::StringToInt(p.second, &offset)) { |
| 164 *final_byte_offset = offset; | 168 *final_byte_offset = offset; |
| 165 found_final_byte_offset = true; | 169 found_final_byte_offset = true; |
| 166 continue; | 170 continue; |
| 167 } | 171 } |
| 168 | 172 |
| 169 if (name.empty() || name[0] == ':') { | 173 if (name.empty() || name[0] == ':') { |
| 170 DVLOG(1) << "Trailers must not be empty, and must not contain pseudo-" | 174 QUIC_DVLOG(1) |
| 171 << "headers. Found: '" << name << "'"; | 175 << "Trailers must not be empty, and must not contain pseudo-" |
| 176 << "headers. Found: '" << name << "'"; |
| 172 return false; | 177 return false; |
| 173 } | 178 } |
| 174 | 179 |
| 175 if (QuicTextUtils::ContainsUpperCase(name)) { | 180 if (QuicTextUtils::ContainsUpperCase(name)) { |
| 176 DVLOG(1) << "Malformed header: Header name " << name | 181 QUIC_DLOG(INFO) << "Malformed header: Header name " << name |
| 177 << " contains upper-case characters."; | 182 << " contains upper-case characters."; |
| 178 return false; | 183 return false; |
| 179 } | 184 } |
| 180 | 185 |
| 181 if (trailers->find(name) != trailers->end()) { | 186 if (trailers->find(name) != trailers->end()) { |
| 182 DVLOG(1) << "Duplicate header '" << name << "' found in trailers."; | 187 QUIC_DLOG(INFO) << "Duplicate header '" << name << "' found in trailers."; |
| 183 return false; | 188 return false; |
| 184 } | 189 } |
| 185 | 190 |
| 186 (*trailers)[name] = p.second; | 191 (*trailers)[name] = p.second; |
| 187 } | 192 } |
| 188 | 193 |
| 189 if (!found_final_byte_offset) { | 194 if (!found_final_byte_offset) { |
| 190 DVLOG(1) << "Required key '" << kFinalOffsetHeaderKey << "' not present"; | 195 QUIC_DVLOG(1) << "Required key '" << kFinalOffsetHeaderKey |
| 196 << "' not present"; |
| 191 return false; | 197 return false; |
| 192 } | 198 } |
| 193 | 199 |
| 194 // TODO(rjshade): Check for other forbidden keys, following the HTTP/2 spec. | 200 // TODO(rjshade): Check for other forbidden keys, following the HTTP/2 spec. |
| 195 | 201 |
| 196 DVLOG(1) << "Successfully parsed Trailers: " << trailers->DebugString(); | 202 QUIC_DVLOG(1) << "Successfully parsed Trailers: " << trailers->DebugString(); |
| 197 return true; | 203 return true; |
| 198 } | 204 } |
| 199 | 205 |
| 200 // static | 206 // static |
| 201 string SpdyUtils::GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers) { | 207 string SpdyUtils::GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers) { |
| 202 SpdyHeaderBlock::const_iterator it = headers.find(":scheme"); | 208 SpdyHeaderBlock::const_iterator it = headers.find(":scheme"); |
| 203 if (it == headers.end()) { | 209 if (it == headers.end()) { |
| 204 return ""; | 210 return ""; |
| 205 } | 211 } |
| 206 std::string url = it->second.as_string(); | 212 std::string url = it->second.as_string(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 (*headers)[":authority"] = url.substr(start); | 253 (*headers)[":authority"] = url.substr(start); |
| 248 (*headers)[":path"] = "/"; | 254 (*headers)[":path"] = "/"; |
| 249 return true; | 255 return true; |
| 250 } | 256 } |
| 251 (*headers)[":authority"] = url.substr(start, pos - start); | 257 (*headers)[":authority"] = url.substr(start, pos - start); |
| 252 (*headers)[":path"] = url.substr(pos); | 258 (*headers)[":path"] = url.substr(pos); |
| 253 return true; | 259 return true; |
| 254 } | 260 } |
| 255 | 261 |
| 256 } // namespace net | 262 } // namespace net |
| OLD | NEW |