| OLD | NEW |
| (Empty) |
| 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/flip_server/spdy_interface.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <string> | |
| 9 #include <utility> | |
| 10 | |
| 11 #include "net/spdy/spdy_framer.h" | |
| 12 #include "net/spdy/spdy_protocol.h" | |
| 13 #include "net/tools/flip_server/constants.h" | |
| 14 #include "net/tools/flip_server/flip_config.h" | |
| 15 #include "net/tools/flip_server/http_interface.h" | |
| 16 #include "net/tools/flip_server/spdy_util.h" | |
| 17 #include "net/tools/flip_server/url_utilities.h" | |
| 18 | |
| 19 namespace net { | |
| 20 | |
| 21 // static | |
| 22 std::string SpdySM::forward_ip_header_; | |
| 23 | |
| 24 class SpdyFrameDataFrame : public DataFrame { | |
| 25 public: | |
| 26 explicit SpdyFrameDataFrame(SpdySerializedFrame* spdy_frame) | |
| 27 : frame(spdy_frame) { | |
| 28 data = spdy_frame->data(); | |
| 29 size = spdy_frame->size(); | |
| 30 } | |
| 31 | |
| 32 ~SpdyFrameDataFrame() override { delete frame; } | |
| 33 | |
| 34 const SpdySerializedFrame* frame; | |
| 35 }; | |
| 36 | |
| 37 SpdySM::SpdySM(SMConnection* connection, | |
| 38 SMInterface* sm_http_interface, | |
| 39 EpollServer* epoll_server, | |
| 40 MemoryCache* memory_cache, | |
| 41 FlipAcceptor* acceptor) | |
| 42 : buffered_spdy_framer_(new BufferedSpdyFramer()), | |
| 43 valid_spdy_session_(false), | |
| 44 connection_(connection), | |
| 45 client_output_list_(connection->output_list()), | |
| 46 client_output_ordering_(connection), | |
| 47 next_outgoing_stream_id_(2), | |
| 48 epoll_server_(epoll_server), | |
| 49 acceptor_(acceptor), | |
| 50 memory_cache_(memory_cache), | |
| 51 close_on_error_(false) { | |
| 52 buffered_spdy_framer_->set_visitor(this); | |
| 53 } | |
| 54 | |
| 55 SpdySM::~SpdySM() { } | |
| 56 | |
| 57 void SpdySM::InitSMConnection(SMConnectionPoolInterface* connection_pool, | |
| 58 SMInterface* sm_interface, | |
| 59 EpollServer* epoll_server, | |
| 60 int fd, | |
| 61 std::string server_ip, | |
| 62 std::string server_port, | |
| 63 std::string remote_ip, | |
| 64 bool use_ssl) { | |
| 65 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Initializing server connection."; | |
| 66 connection_->InitSMConnection(connection_pool, | |
| 67 sm_interface, | |
| 68 epoll_server, | |
| 69 fd, | |
| 70 server_ip, | |
| 71 server_port, | |
| 72 remote_ip, | |
| 73 use_ssl); | |
| 74 } | |
| 75 | |
| 76 SMInterface* SpdySM::NewConnectionInterface() { | |
| 77 SMConnection* server_connection = | |
| 78 SMConnection::NewSMConnection(epoll_server_, | |
| 79 NULL, | |
| 80 memory_cache_, | |
| 81 acceptor_, | |
| 82 "http_conn: "); | |
| 83 if (server_connection == NULL) { | |
| 84 LOG(ERROR) << "SpdySM: Could not create server connection"; | |
| 85 return NULL; | |
| 86 } | |
| 87 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Creating new HTTP interface"; | |
| 88 SMInterface* sm_http_interface = | |
| 89 new HttpSM(server_connection, this, memory_cache_, acceptor_); | |
| 90 return sm_http_interface; | |
| 91 } | |
| 92 | |
| 93 SMInterface* SpdySM::FindOrMakeNewSMConnectionInterface( | |
| 94 const std::string& server_ip, | |
| 95 const std::string& server_port) { | |
| 96 SMInterface* sm_http_interface; | |
| 97 int32_t server_idx; | |
| 98 if (unused_server_interface_list.empty()) { | |
| 99 sm_http_interface = NewConnectionInterface(); | |
| 100 server_idx = server_interface_list.size(); | |
| 101 server_interface_list.push_back(sm_http_interface); | |
| 102 VLOG(2) << ACCEPTOR_CLIENT_IDENT | |
| 103 << "SpdySM: Making new server connection on index: " << server_idx; | |
| 104 } else { | |
| 105 server_idx = unused_server_interface_list.back(); | |
| 106 unused_server_interface_list.pop_back(); | |
| 107 sm_http_interface = server_interface_list.at(server_idx); | |
| 108 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Reusing connection on " | |
| 109 << "index: " << server_idx; | |
| 110 } | |
| 111 | |
| 112 sm_http_interface->InitSMInterface(this, server_idx); | |
| 113 sm_http_interface->InitSMConnection(NULL, | |
| 114 sm_http_interface, | |
| 115 epoll_server_, | |
| 116 -1, | |
| 117 server_ip, | |
| 118 server_port, | |
| 119 std::string(), | |
| 120 false); | |
| 121 | |
| 122 return sm_http_interface; | |
| 123 } | |
| 124 | |
| 125 int SpdySM::SpdyHandleNewStream(SpdyStreamId stream_id, | |
| 126 SpdyPriority priority, | |
| 127 const SpdyHeaderBlock& headers, | |
| 128 std::string& http_data, | |
| 129 bool* is_https_scheme) { | |
| 130 *is_https_scheme = false; | |
| 131 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnSyn(" << stream_id << ")"; | |
| 132 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: # headers: " << headers.size(); | |
| 133 | |
| 134 SpdyHeaderBlock::const_iterator method = headers.end(); | |
| 135 SpdyHeaderBlock::const_iterator host = headers.end(); | |
| 136 SpdyHeaderBlock::const_iterator path = headers.end(); | |
| 137 SpdyHeaderBlock::const_iterator scheme = headers.end(); | |
| 138 SpdyHeaderBlock::const_iterator version = headers.end(); | |
| 139 SpdyHeaderBlock::const_iterator url = headers.end(); | |
| 140 | |
| 141 std::string path_string, host_string, version_string; | |
| 142 | |
| 143 method = headers.find(":method"); | |
| 144 host = headers.find(":host"); | |
| 145 path = headers.find(":path"); | |
| 146 scheme = headers.find(":scheme"); | |
| 147 if (method == headers.end() || host == headers.end() || | |
| 148 path == headers.end() || scheme == headers.end()) { | |
| 149 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: A mandatory header is " | |
| 150 << "missing. Not creating stream"; | |
| 151 return 0; | |
| 152 } | |
| 153 host_string = host->second.as_string(); | |
| 154 path_string = path->second.as_string(); | |
| 155 version_string = "HTTP/1.1"; | |
| 156 | |
| 157 if (scheme->second.compare("https") == 0) { | |
| 158 *is_https_scheme = true; | |
| 159 } | |
| 160 | |
| 161 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_SPDY_SERVER) { | |
| 162 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Request: " << method->second | |
| 163 << " " << path_string; | |
| 164 std::string filename = | |
| 165 EncodeURL(path_string, host_string, method->second.as_string()); | |
| 166 NewStream(stream_id, priority, filename); | |
| 167 } else { | |
| 168 http_data += method->second.as_string() + " " + path_string + " " + | |
| 169 version_string + "\r\n"; | |
| 170 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Request: " << method->second << " " | |
| 171 << path_string << " " << version_string; | |
| 172 http_data += "Host: " + (*is_https_scheme ? | |
| 173 acceptor_->https_server_ip_ : | |
| 174 acceptor_->http_server_ip_) + "\r\n"; | |
| 175 for (SpdyHeaderBlock::const_iterator i = headers.begin(); | |
| 176 i != headers.end(); ++i) { | |
| 177 if ((i->first.size() > 0 && i->first[0] == ':') || | |
| 178 i->first == "host" || | |
| 179 i == method || | |
| 180 i == host || | |
| 181 i == path || | |
| 182 i == scheme || | |
| 183 i == version || | |
| 184 i == url) { | |
| 185 // Ignore the entry. | |
| 186 } else { | |
| 187 http_data += | |
| 188 i->first.as_string() + ": " + i->second.as_string() + "\r\n"; | |
| 189 VLOG(2) << ACCEPTOR_CLIENT_IDENT << i->first << ":" << i->second; | |
| 190 } | |
| 191 } | |
| 192 if (forward_ip_header_.length()) { | |
| 193 // X-Client-Cluster-IP header | |
| 194 http_data += forward_ip_header_ + ": " + | |
| 195 connection_->client_ip() + "\r\n"; | |
| 196 } | |
| 197 http_data += "\r\n"; | |
| 198 } | |
| 199 | |
| 200 VLOG(3) << ACCEPTOR_CLIENT_IDENT << "SpdySM: HTTP Request:\n" << http_data; | |
| 201 return 1; | |
| 202 } | |
| 203 | |
| 204 void SpdySM::OnStreamFrameData(SpdyStreamId stream_id, | |
| 205 const char* data, | |
| 206 size_t len) { | |
| 207 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: StreamData(" << stream_id | |
| 208 << ", [" << len << "])"; | |
| 209 StreamToSmif::iterator it = stream_to_smif_.find(stream_id); | |
| 210 if (it == stream_to_smif_.end()) { | |
| 211 VLOG(2) << "Dropping frame from unknown stream " << stream_id; | |
| 212 if (!valid_spdy_session_) | |
| 213 close_on_error_ = true; | |
| 214 return; | |
| 215 } | |
| 216 | |
| 217 SMInterface* interface = it->second; | |
| 218 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) | |
| 219 interface->ProcessWriteInput(data, len); | |
| 220 } | |
| 221 | |
| 222 void SpdySM::OnStreamEnd(SpdyStreamId stream_id) { | |
| 223 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: StreamEnd(" << stream_id << ")"; | |
| 224 StreamToSmif::iterator it = stream_to_smif_.find(stream_id); | |
| 225 if (it == stream_to_smif_.end()) { | |
| 226 VLOG(2) << "Dropping frame from unknown stream " << stream_id; | |
| 227 if (!valid_spdy_session_) | |
| 228 close_on_error_ = true; | |
| 229 return; | |
| 230 } | |
| 231 | |
| 232 SMInterface* interface = it->second; | |
| 233 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) | |
| 234 interface->ProcessWriteInput(nullptr, 0); | |
| 235 } | |
| 236 | |
| 237 void SpdySM::OnStreamPadding(SpdyStreamId stream_id, size_t len) { | |
| 238 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: StreamPadding(" << stream_id | |
| 239 << ", [" << len << "])"; | |
| 240 } | |
| 241 | |
| 242 void SpdySM::OnHeaders(SpdyStreamId stream_id, | |
| 243 bool has_priority, | |
| 244 int weight, | |
| 245 SpdyStreamId parent_stream_id, | |
| 246 bool exclusive, | |
| 247 bool fin, | |
| 248 const SpdyHeaderBlock& headers) { | |
| 249 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnHeaders(" << stream_id << ")"; | |
| 250 } | |
| 251 | |
| 252 void SpdySM::OnRstStream(SpdyStreamId stream_id, SpdyRstStreamStatus status) { | |
| 253 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnRstStream(" << stream_id | |
| 254 << ")"; | |
| 255 client_output_ordering_.RemoveStreamId(stream_id); | |
| 256 } | |
| 257 | |
| 258 bool SpdySM::OnUnknownFrame(SpdyStreamId stream_id, int frame_type) { | |
| 259 return false; | |
| 260 } | |
| 261 | |
| 262 size_t SpdySM::ProcessReadInput(const char* data, size_t len) { | |
| 263 DCHECK(buffered_spdy_framer_); | |
| 264 return buffered_spdy_framer_->ProcessInput(data, len); | |
| 265 } | |
| 266 | |
| 267 size_t SpdySM::ProcessWriteInput(const char* data, size_t len) { return 0; } | |
| 268 | |
| 269 bool SpdySM::MessageFullyRead() const { | |
| 270 DCHECK(buffered_spdy_framer_); | |
| 271 return buffered_spdy_framer_->MessageFullyRead(); | |
| 272 } | |
| 273 | |
| 274 bool SpdySM::Error() const { | |
| 275 DCHECK(buffered_spdy_framer_); | |
| 276 return close_on_error_ || buffered_spdy_framer_->HasError(); | |
| 277 } | |
| 278 | |
| 279 const char* SpdySM::ErrorAsString() const { | |
| 280 DCHECK(Error()); | |
| 281 DCHECK(buffered_spdy_framer_); | |
| 282 return SpdyFramer::ErrorCodeToString(buffered_spdy_framer_->error_code()); | |
| 283 } | |
| 284 | |
| 285 void SpdySM::ResetForNewInterface(int32_t server_idx) { | |
| 286 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Reset for new interface: " | |
| 287 << "server_idx: " << server_idx; | |
| 288 unused_server_interface_list.push_back(server_idx); | |
| 289 } | |
| 290 | |
| 291 void SpdySM::ResetForNewConnection() { | |
| 292 // seq_num is not cleared, intentionally. | |
| 293 buffered_spdy_framer_.reset(); | |
| 294 valid_spdy_session_ = false; | |
| 295 client_output_ordering_.Reset(); | |
| 296 next_outgoing_stream_id_ = 2; | |
| 297 } | |
| 298 | |
| 299 // Send a settings frame | |
| 300 int SpdySM::PostAcceptHook() { | |
| 301 // We should have buffered_spdy_framer_ set after reuse | |
| 302 DCHECK(buffered_spdy_framer_); | |
| 303 SettingsMap settings; | |
| 304 settings[SETTINGS_MAX_CONCURRENT_STREAMS] = | |
| 305 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, 100); | |
| 306 SpdySerializedFrame* settings_frame = | |
| 307 buffered_spdy_framer_->CreateSettings(settings); | |
| 308 | |
| 309 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Sending Settings Frame"; | |
| 310 EnqueueDataFrame(new SpdyFrameDataFrame(settings_frame)); | |
| 311 return 1; | |
| 312 } | |
| 313 | |
| 314 void SpdySM::NewStream(uint32_t stream_id, | |
| 315 uint32_t priority, | |
| 316 const std::string& filename) { | |
| 317 MemCacheIter mci; | |
| 318 mci.stream_id = stream_id; | |
| 319 mci.priority = priority; | |
| 320 // TODO(yhirano): The program will crash when | |
| 321 // acceptor_->flip_handler_type_ != FLIP_HANDLER_SPDY_SERVER. | |
| 322 // It should be fixed or an assertion should be placed. | |
| 323 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_SPDY_SERVER) { | |
| 324 if (!memory_cache_->AssignFileData(filename, &mci)) { | |
| 325 // error creating new stream. | |
| 326 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Sending ErrorNotFound"; | |
| 327 SendErrorNotFound(stream_id); | |
| 328 } else { | |
| 329 AddToOutputOrder(mci); | |
| 330 } | |
| 331 } else { | |
| 332 AddToOutputOrder(mci); | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 void SpdySM::AddToOutputOrder(const MemCacheIter& mci) { | |
| 337 client_output_ordering_.AddToOutputOrder(mci); | |
| 338 } | |
| 339 | |
| 340 void SpdySM::SendEOF(uint32_t stream_id) { | |
| 341 SendEOFImpl(stream_id); | |
| 342 } | |
| 343 | |
| 344 void SpdySM::SendErrorNotFound(uint32_t stream_id) { | |
| 345 SendErrorNotFoundImpl(stream_id); | |
| 346 } | |
| 347 | |
| 348 size_t SpdySM::SendSynStream(uint32_t stream_id, const BalsaHeaders& headers) { | |
| 349 return SendSynStreamImpl(stream_id, headers); | |
| 350 } | |
| 351 | |
| 352 size_t SpdySM::SendSynReply(uint32_t stream_id, const BalsaHeaders& headers) { | |
| 353 return SendSynReplyImpl(stream_id, headers); | |
| 354 } | |
| 355 | |
| 356 void SpdySM::SendDataFrame(uint32_t stream_id, | |
| 357 const char* data, | |
| 358 int64_t len, | |
| 359 uint32_t flags, | |
| 360 bool compress) { | |
| 361 SpdyDataFlags spdy_flags = static_cast<SpdyDataFlags>(flags); | |
| 362 SendDataFrameImpl(stream_id, data, len, spdy_flags, compress); | |
| 363 } | |
| 364 | |
| 365 void SpdySM::SendEOFImpl(uint32_t stream_id) { | |
| 366 SendDataFrame(stream_id, NULL, 0, DATA_FLAG_FIN, false); | |
| 367 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending EOF: " << stream_id; | |
| 368 KillStream(stream_id); | |
| 369 stream_to_smif_.erase(stream_id); | |
| 370 } | |
| 371 | |
| 372 void SpdySM::SendErrorNotFoundImpl(uint32_t stream_id) { | |
| 373 BalsaHeaders my_headers; | |
| 374 my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "404", "Not Found"); | |
| 375 SendSynReplyImpl(stream_id, my_headers); | |
| 376 SendDataFrame(stream_id, "wtf?", 4, DATA_FLAG_FIN, false); | |
| 377 client_output_ordering_.RemoveStreamId(stream_id); | |
| 378 } | |
| 379 | |
| 380 void SpdySM::KillStream(uint32_t stream_id) { | |
| 381 client_output_ordering_.RemoveStreamId(stream_id); | |
| 382 } | |
| 383 | |
| 384 void SpdySM::CopyHeaders(SpdyHeaderBlock& dest, const BalsaHeaders& headers) { | |
| 385 for (BalsaHeaders::const_header_lines_iterator hi = | |
| 386 headers.header_lines_begin(); | |
| 387 hi != headers.header_lines_end(); | |
| 388 ++hi) { | |
| 389 // It is illegal to send SPDY headers with empty value or header | |
| 390 // names. | |
| 391 if (!hi->first.length() || !hi->second.length()) | |
| 392 continue; | |
| 393 | |
| 394 // Key must be all lower case in SPDY headers. | |
| 395 std::string key = hi->first.as_string(); | |
| 396 std::transform(key.begin(), key.end(), key.begin(), ::tolower); | |
| 397 SpdyHeaderBlock::iterator fhi = dest.find(key); | |
| 398 if (fhi == dest.end()) { | |
| 399 dest[key] = hi->second.as_string(); | |
| 400 } else { | |
| 401 dest[key] = (std::string(fhi->second.data(), fhi->second.size()) + "\0" + | |
| 402 std::string(hi->second.data(), hi->second.size())); | |
| 403 } | |
| 404 } | |
| 405 | |
| 406 // These headers have no value | |
| 407 dest.erase("X-Associated-Content"); // TODO(mbelshe): case-sensitive | |
| 408 dest.erase("X-Original-Url"); // TODO(mbelshe): case-sensitive | |
| 409 } | |
| 410 | |
| 411 size_t SpdySM::SendSynStreamImpl(uint32_t stream_id, | |
| 412 const BalsaHeaders& headers) { | |
| 413 SpdyHeaderBlock block; | |
| 414 CopyHeaders(block, headers); | |
| 415 block[":method"] = headers.request_method().as_string(); | |
| 416 block[":version"] = headers.request_version().as_string(); | |
| 417 if (headers.HasHeader("X-Original-Url")) { | |
| 418 std::string original_url = headers.GetHeader("X-Original-Url").as_string(); | |
| 419 block[":path"] = UrlUtilities::GetUrlPath(original_url); | |
| 420 block[":host"] = UrlUtilities::GetUrlPath(original_url); | |
| 421 } else { | |
| 422 block[":path"] = headers.request_uri().as_string(); | |
| 423 if (block.find("host") != block.end()) { | |
| 424 block[":host"] = headers.GetHeader("Host").as_string(); | |
| 425 block.erase("host"); | |
| 426 } | |
| 427 } | |
| 428 | |
| 429 DCHECK(buffered_spdy_framer_); | |
| 430 SpdySerializedFrame* fsrcf = buffered_spdy_framer_->CreateSynStream( | |
| 431 stream_id, 0, 0, CONTROL_FLAG_NONE, std::move(block)); | |
| 432 size_t df_size = fsrcf->size(); | |
| 433 EnqueueDataFrame(new SpdyFrameDataFrame(fsrcf)); | |
| 434 | |
| 435 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending SynStreamheader " | |
| 436 << stream_id; | |
| 437 return df_size; | |
| 438 } | |
| 439 | |
| 440 size_t SpdySM::SendSynReplyImpl(uint32_t stream_id, | |
| 441 const BalsaHeaders& headers) { | |
| 442 SpdyHeaderBlock block; | |
| 443 CopyHeaders(block, headers); | |
| 444 block[":status"] = headers.response_code().as_string() + " " + | |
| 445 headers.response_reason_phrase().as_string(); | |
| 446 block[":version"] = headers.response_version().as_string(); | |
| 447 | |
| 448 DCHECK(buffered_spdy_framer_); | |
| 449 SpdySerializedFrame* fsrcf = buffered_spdy_framer_->CreateSynReply( | |
| 450 stream_id, CONTROL_FLAG_NONE, std::move(block)); | |
| 451 size_t df_size = fsrcf->size(); | |
| 452 EnqueueDataFrame(new SpdyFrameDataFrame(fsrcf)); | |
| 453 | |
| 454 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending SynReplyheader " | |
| 455 << stream_id; | |
| 456 return df_size; | |
| 457 } | |
| 458 | |
| 459 void SpdySM::SendDataFrameImpl(uint32_t stream_id, | |
| 460 const char* data, | |
| 461 int64_t len, | |
| 462 SpdyDataFlags flags, | |
| 463 bool compress) { | |
| 464 DCHECK(buffered_spdy_framer_); | |
| 465 // TODO(mbelshe): We can't compress here - before going into the | |
| 466 // priority queue. Compression needs to be done | |
| 467 // with late binding. | |
| 468 if (len == 0) { | |
| 469 SpdySerializedFrame* fdf = | |
| 470 buffered_spdy_framer_->CreateDataFrame(stream_id, data, len, flags); | |
| 471 EnqueueDataFrame(new SpdyFrameDataFrame(fdf)); | |
| 472 return; | |
| 473 } | |
| 474 | |
| 475 // Chop data frames into chunks so that one stream can't monopolize the | |
| 476 // output channel. | |
| 477 while (len > 0) { | |
| 478 int64_t size = std::min(len, static_cast<int64_t>(kSpdySegmentSize)); | |
| 479 SpdyDataFlags chunk_flags = flags; | |
| 480 | |
| 481 // If we chunked this block, and the FIN flag was set, there is more | |
| 482 // data coming. So, remove the flag. | |
| 483 if ((size < len) && (flags & DATA_FLAG_FIN)) | |
| 484 chunk_flags = static_cast<SpdyDataFlags>(chunk_flags & ~DATA_FLAG_FIN); | |
| 485 | |
| 486 SpdySerializedFrame* fdf = buffered_spdy_framer_->CreateDataFrame( | |
| 487 stream_id, data, size, chunk_flags); | |
| 488 EnqueueDataFrame(new SpdyFrameDataFrame(fdf)); | |
| 489 | |
| 490 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending data frame " | |
| 491 << stream_id << " [" << size << "] shrunk to " | |
| 492 << (fdf->size() - kSpdyOverhead) << ", flags=" << flags; | |
| 493 | |
| 494 data += size; | |
| 495 len -= size; | |
| 496 } | |
| 497 } | |
| 498 | |
| 499 void SpdySM::EnqueueDataFrame(DataFrame* df) { | |
| 500 connection_->EnqueueDataFrame(df); | |
| 501 } | |
| 502 | |
| 503 void SpdySM::GetOutput() { | |
| 504 while (client_output_list_->size() < 2) { | |
| 505 MemCacheIter* mci = client_output_ordering_.GetIter(); | |
| 506 if (mci == NULL) { | |
| 507 VLOG(2) << ACCEPTOR_CLIENT_IDENT | |
| 508 << "SpdySM: GetOutput: nothing to output!?"; | |
| 509 return; | |
| 510 } | |
| 511 if (!mci->transformed_header) { | |
| 512 mci->transformed_header = true; | |
| 513 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: GetOutput transformed " | |
| 514 << "header stream_id: [" << mci->stream_id << "]"; | |
| 515 if ((mci->stream_id % 2) == 0) { | |
| 516 // this is a server initiated stream. | |
| 517 // Ideally, we'd do a 'syn-push' here, instead of a syn-reply. | |
| 518 BalsaHeaders headers; | |
| 519 headers.CopyFrom(*(mci->file_data->headers())); | |
| 520 headers.ReplaceOrAppendHeader("status", "200"); | |
| 521 headers.ReplaceOrAppendHeader("version", "http/1.1"); | |
| 522 headers.SetRequestFirstlineFromStringPieces( | |
| 523 "PUSH", mci->file_data->filename(), ""); | |
| 524 mci->bytes_sent = SendSynStream(mci->stream_id, headers); | |
| 525 } else { | |
| 526 BalsaHeaders headers; | |
| 527 headers.CopyFrom(*(mci->file_data->headers())); | |
| 528 mci->bytes_sent = SendSynReply(mci->stream_id, headers); | |
| 529 } | |
| 530 return; | |
| 531 } | |
| 532 if (mci->body_bytes_consumed >= mci->file_data->body().size()) { | |
| 533 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: GetOutput " | |
| 534 << "remove_stream_id: [" << mci->stream_id << "]"; | |
| 535 SendEOF(mci->stream_id); | |
| 536 return; | |
| 537 } | |
| 538 size_t num_to_write = | |
| 539 mci->file_data->body().size() - mci->body_bytes_consumed; | |
| 540 if (num_to_write > mci->max_segment_size) | |
| 541 num_to_write = mci->max_segment_size; | |
| 542 | |
| 543 bool should_compress = false; | |
| 544 if (!mci->file_data->headers()->HasHeader("content-encoding")) { | |
| 545 if (mci->file_data->headers()->HasHeader("content-type")) { | |
| 546 std::string content_type = | |
| 547 mci->file_data->headers()->GetHeader("content-type").as_string(); | |
| 548 if (content_type.find("image") == content_type.npos) | |
| 549 should_compress = true; | |
| 550 } | |
| 551 } | |
| 552 | |
| 553 SendDataFrame(mci->stream_id, | |
| 554 mci->file_data->body().data() + mci->body_bytes_consumed, | |
| 555 num_to_write, | |
| 556 0, | |
| 557 should_compress); | |
| 558 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: GetOutput SendDataFrame[" | |
| 559 << mci->stream_id << "]: " << num_to_write; | |
| 560 mci->body_bytes_consumed += num_to_write; | |
| 561 mci->bytes_sent += num_to_write; | |
| 562 } | |
| 563 } | |
| 564 | |
| 565 void SpdySM::CreateFramer() { | |
| 566 DCHECK(!buffered_spdy_framer_); | |
| 567 buffered_spdy_framer_.reset(new BufferedSpdyFramer()); | |
| 568 buffered_spdy_framer_->set_visitor(this); | |
| 569 } | |
| 570 | |
| 571 } // namespace net | |
| OLD | NEW |