blob: 72bd3878a3d3cee49eb2dbfddac4675325e34817 [file] [log] [blame]
[email protected]aea80602009-09-18 00:55:081// Copyright (c) 2009 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/flip/flip_session.h"
6
7#include "base/basictypes.h"
8#include "base/logging.h"
9#include "base/message_loop.h"
10#include "base/rand_util.h"
11#include "base/stats_counters.h"
12#include "base/string_util.h"
13#include "net/base/load_flags.h"
[email protected]33751562009-10-29 02:17:1114#include "net/base/net_util.h"
[email protected]aea80602009-09-18 00:55:0815#include "net/flip/flip_frame_builder.h"
16#include "net/flip/flip_protocol.h"
[email protected]cd314c822009-10-29 03:13:0617#include "net/flip/flip_stream.h"
[email protected]aea80602009-09-18 00:55:0818#include "net/http/http_network_session.h"
19#include "net/http/http_request_info.h"
20#include "net/http/http_response_headers.h"
21#include "net/http/http_response_info.h"
[email protected]18c53ae2009-10-01 18:18:5222#include "net/socket/client_socket_factory.h"
23#include "net/socket/ssl_client_socket.h"
[email protected]aea80602009-09-18 00:55:0824#include "net/tools/dump_cache/url_to_filename_encoder.h"
25
26namespace net {
27
28// static
[email protected]affe8fe2009-10-14 20:06:0529bool FlipSession::use_ssl_ = true;
[email protected]aea80602009-09-18 00:55:0830
[email protected]aea80602009-09-18 00:55:0831FlipSession::FlipSession(std::string host, HttpNetworkSession* session)
32 : ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]18c53ae2009-10-01 18:18:5233 connect_callback_(this, &FlipSession::OnTCPConnect)),
34 ALLOW_THIS_IN_INITIALIZER_LIST(
35 ssl_connect_callback_(this, &FlipSession::OnSSLConnect)),
[email protected]aea80602009-09-18 00:55:0836 ALLOW_THIS_IN_INITIALIZER_LIST(
37 read_callback_(this, &FlipSession::OnReadComplete)),
38 ALLOW_THIS_IN_INITIALIZER_LIST(
39 write_callback_(this, &FlipSession::OnWriteComplete)),
40 domain_(host),
41 session_(session),
42 connection_started_(false),
[email protected]18c53ae2009-10-01 18:18:5243 connection_ready_(false),
[email protected]230cadd2009-09-22 16:33:5944 read_buffer_(new IOBuffer(kReadBufferSize)),
[email protected]aea80602009-09-18 00:55:0845 read_pending_(false),
[email protected]ba051e312009-10-07 22:12:3346 stream_hi_water_mark_(1), // Always start at 1 for the first stream id.
47 delayed_write_pending_(false),
48 write_pending_(false) {
49 // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
[email protected]aea80602009-09-18 00:55:0850
51 flip_framer_.set_visitor(this);
[email protected]18c53ae2009-10-01 18:18:5252
53 session_->ssl_config_service()->GetSSLConfig(&ssl_config_);
[email protected]aea80602009-09-18 00:55:0854}
55
56FlipSession::~FlipSession() {
[email protected]93300672009-10-24 13:22:5157 // Cleanup all the streams.
58 CloseAllStreams(net::ERR_ABORTED);
59
[email protected]aea80602009-09-18 00:55:0860 if (connection_.is_initialized()) {
61 // With Flip we can't recycle sockets.
62 connection_.socket()->Disconnect();
63 }
[email protected]d1eda932009-11-04 01:03:1064
65 session_->flip_session_pool()->Remove(this);
[email protected]aea80602009-09-18 00:55:0866}
67
68net::Error FlipSession::Connect(const std::string& group_name,
69 const HostResolver::RequestInfo& host,
70 int priority) {
71 DCHECK(priority >= 0 && priority < 4);
72
73 // If the connect process is started, let the caller continue.
74 if (connection_started_)
75 return net::OK;
76
77 connection_started_ = true;
78
79 static StatsCounter flip_sessions("flip.sessions");
80 flip_sessions.Increment();
81
82 int rv = connection_.Init(group_name, host, priority, &connect_callback_,
83 session_->tcp_socket_pool(), NULL);
84
85 // If the connect is pending, we still return ok. The APIs enqueue
86 // work until after the connect completes asynchronously later.
87 if (rv == net::ERR_IO_PENDING)
88 return net::OK;
89 return static_cast<net::Error>(rv);
90}
91
92
93// Create a FlipHeaderBlock for a Flip SYN_STREAM Frame from
94// a HttpRequestInfo block.
95void CreateFlipHeadersFromHttpRequest(
96 const HttpRequestInfo* info, flip::FlipHeaderBlock* headers) {
97 static const std::string kHttpProtocolVersion("HTTP/1.1");
98
99 HttpUtil::HeadersIterator it(info->extra_headers.begin(),
100 info->extra_headers.end(),
101 "\r\n");
102 while (it.GetNext()) {
103 std::string name = StringToLowerASCII(it.name());
104 (*headers)[name] = it.values();
105 }
106
[email protected]aea80602009-09-18 00:55:08107 (*headers)["method"] = info->method;
[email protected]eebc0b42009-11-04 00:17:13108 (*headers)["url"] = info->url.PathForRequest();
[email protected]aea80602009-09-18 00:55:08109 (*headers)["version"] = kHttpProtocolVersion;
[email protected]33751562009-10-29 02:17:11110 (*headers)["host"] = GetHostAndOptionalPort(info->url);
[email protected]aea80602009-09-18 00:55:08111 if (info->user_agent.length())
112 (*headers)["user-agent"] = info->user_agent;
113 if (!info->referrer.is_empty())
114 (*headers)["referer"] = info->referrer.spec();
115
116 // Honor load flags that impact proxy caches.
117 if (info->load_flags & LOAD_BYPASS_CACHE) {
118 (*headers)["pragma"] = "no-cache";
119 (*headers)["cache-control"] = "no-cache";
120 } else if (info->load_flags & LOAD_VALIDATE_CACHE) {
121 (*headers)["cache-control"] = "max-age=0";
122 }
123}
124
125int FlipSession::CreateStream(FlipDelegate* delegate) {
126 flip::FlipStreamId stream_id = GetNewStreamId();
127
128 GURL url = delegate->request()->url;
129 std::string path = url.PathForRequest();
130
[email protected]cd314c822009-10-29 03:13:06131 FlipStream* stream = NULL;
[email protected]aea80602009-09-18 00:55:08132
133 // Check if we have a push stream for this path.
134 if (delegate->request()->method == "GET") {
135 stream = GetPushStream(path);
136 if (stream) {
137 if (stream->AttachDelegate(delegate)) {
138 DeactivateStream(stream->stream_id());
139 delete stream;
140 return 0;
141 }
142 return stream->stream_id();
143 }
144 }
145
[email protected]18c53ae2009-10-01 18:18:52146 // Check if we have a pending push stream for this url.
147 std::string url_path = delegate->request()->url.PathForRequest();
148 std::map<std::string, FlipDelegate*>::iterator it;
149 it = pending_streams_.find(url_path);
150 if (it != pending_streams_.end()) {
151 DCHECK(it->second == NULL);
152 it->second = delegate;
153 return 0; // TODO(mbelshe): this is overloaded with the fail case.
154 }
155
[email protected]aea80602009-09-18 00:55:08156 // If we still don't have a stream, activate one now.
157 stream = ActivateStream(stream_id, delegate);
158 if (!stream)
159 return net::ERR_FAILED;
160
161 LOG(INFO) << "FlipStream: Creating stream " << stream_id << " for "
162 << delegate->request()->url;
163
164 // TODO(mbelshe): Optimize memory allocations
165 int priority = delegate->request()->priority;
166
167 // Hack for the priorities
168 // TODO(mbelshe): These need to be plumbed through the Http Network Stack.
169 if (path.find(".css") != path.npos) {
170 priority = 1;
171 } else if (path.find(".html") != path.npos) {
172 priority = 0;
173 } else if (path.find(".js") != path.npos) {
174 priority = 1;
175 } else {
176 priority = 3;
177 }
178
179 DCHECK(priority >= FLIP_PRIORITY_HIGHEST &&
180 priority <= FLIP_PRIORITY_LOWEST);
181
182 // Convert from HttpRequestHeaders to Flip Headers.
183 flip::FlipHeaderBlock headers;
184 CreateFlipHeadersFromHttpRequest(delegate->request(), &headers);
185
[email protected]72552f02009-10-28 15:25:01186 flip::FlipControlFlags flags = flip::CONTROL_FLAG_NONE;
[email protected]23297922009-10-28 20:12:36187 if (!delegate->data())
[email protected]72552f02009-10-28 15:25:01188 flags = flip::CONTROL_FLAG_FIN;
189
[email protected]aea80602009-09-18 00:55:08190 // Create a SYN_STREAM packet and add to the output queue.
191 flip::FlipSynStreamControlFrame* syn_frame =
[email protected]72552f02009-10-28 15:25:01192 flip_framer_.CreateSynStream(stream_id, priority, flags, false, &headers);
[email protected]aea80602009-09-18 00:55:08193 int length = sizeof(flip::FlipFrame) + syn_frame->length();
194 IOBufferWithSize* buffer =
195 new IOBufferWithSize(length);
196 memcpy(buffer->data(), syn_frame, length);
[email protected]44f91fa2009-10-13 06:08:41197 delete[] syn_frame;
[email protected]eebc0b42009-11-04 00:17:13198 queue_.push(FlipIOBuffer(buffer, priority, stream));
[email protected]aea80602009-09-18 00:55:08199
200 static StatsCounter flip_requests("flip.requests");
201 flip_requests.Increment();
202
203 LOG(INFO) << "FETCHING: " << delegate->request()->url.spec();
204
205
206 // TODO(mbelshe): Implement POST Data here
207
208 // Schedule to write to the socket after we've made it back
209 // to the message loop so that we can aggregate multiple
210 // requests.
211 // TODO(mbelshe): Should we do the "first" request immediately?
212 // maybe we should only 'do later' for subsequent
213 // requests.
214 WriteSocketLater();
215
216 return stream_id;
217}
218
219bool FlipSession::CancelStream(int id) {
220 LOG(INFO) << "Cancelling stream " << id;
221 if (!IsStreamActive(id))
222 return false;
[email protected]93300672009-10-24 13:22:51223
224 // TODO(mbelshe): Write a method for tearing down a stream
225 // that cleans it out of the active list, the pending list,
226 // etc.
[email protected]cd314c822009-10-29 03:13:06227 FlipStream* stream = active_streams_[id];
[email protected]aea80602009-09-18 00:55:08228 DeactivateStream(id);
[email protected]93300672009-10-24 13:22:51229 delete stream;
[email protected]aea80602009-09-18 00:55:08230 return true;
231}
232
[email protected]d1eda932009-11-04 01:03:10233bool FlipSession::IsStreamActive(int id) const {
[email protected]aea80602009-09-18 00:55:08234 return active_streams_.find(id) != active_streams_.end();
235}
236
237LoadState FlipSession::GetLoadState() const {
238 // TODO(mbelshe): needs more work
239 return LOAD_STATE_CONNECTING;
240}
241
[email protected]18c53ae2009-10-01 18:18:52242void FlipSession::OnTCPConnect(int result) {
[email protected]aea80602009-09-18 00:55:08243 LOG(INFO) << "Flip socket connected (result=" << result << ")";
244
245 if (result != net::OK) {
246 net::Error err = static_cast<net::Error>(result);
247 CloseAllStreams(err);
248 this->Release();
249 return;
250 }
251
252 // Adjust socket buffer sizes.
253 // FLIP uses one socket, and we want a really big buffer.
254 // This greatly helps on links with packet loss - we can even
255 // outperform Vista's dynamic window sizing algorithm.
256 // TODO(mbelshe): more study.
257 const int kSocketBufferSize = 512 * 1024;
258 connection_.socket()->SetReceiveBufferSize(kSocketBufferSize);
259 connection_.socket()->SetSendBufferSize(kSocketBufferSize);
260
[email protected]affe8fe2009-10-14 20:06:05261 if (use_ssl_) {
[email protected]18c53ae2009-10-01 18:18:52262 // Add a SSL socket on top of our existing transport socket.
263 ClientSocket* socket = connection_.release_socket();
264 // TODO(mbelshe): Fix the hostname. This is BROKEN without having
265 // a real hostname.
266 socket = session_->socket_factory()->CreateSSLClientSocket(
267 socket, "" /* request_->url.HostNoBrackets() */ , ssl_config_);
268 connection_.set_socket(socket);
[email protected]5a05c47a2009-11-02 23:25:19269 // TODO(willchan): Plumb LoadLog into FLIP code.
270 int status = connection_.socket()->Connect(&ssl_connect_callback_, NULL);
[email protected]18c53ae2009-10-01 18:18:52271 CHECK(status == net::ERR_IO_PENDING);
272 } else {
273 connection_ready_ = true;
274
275 // Make sure we get any pending data sent.
276 WriteSocketLater();
277 // Start reading
278 ReadSocket();
279 }
280}
281
282void FlipSession::OnSSLConnect(int result) {
283 // TODO(mbelshe): We need to replicate the functionality of
284 // HttpNetworkTransaction::DoSSLConnectComplete here, where it calls
285 // HandleCertificateError() and such.
286 if (IsCertificateError(result))
287 result = OK; // TODO(mbelshe): pretend we're happy anyway.
288
[email protected]93300672009-10-24 13:22:51289 if (result == OK) {
290 connection_ready_ = true;
[email protected]18c53ae2009-10-01 18:18:52291
[email protected]93300672009-10-24 13:22:51292 // After we've connected, send any data to the server, and then issue
293 // our read.
294 WriteSocketLater();
295 ReadSocket();
296 } else {
297 NOTREACHED();
298 // TODO(mbelshe): handle the error case: could not connect
299 }
[email protected]aea80602009-09-18 00:55:08300}
301
302void FlipSession::OnReadComplete(int bytes_read) {
303 // Parse a frame. For now this code requires that the frame fit into our
304 // buffer (32KB).
305 // TODO(mbelshe): support arbitrarily large frames!
306
307 LOG(INFO) << "Flip socket read: " << bytes_read << " bytes";
308
309 read_pending_ = false;
310
311 if (bytes_read <= 0) {
312 // Session is tearing down.
313 net::Error err = static_cast<net::Error>(bytes_read);
314 CloseAllStreams(err);
315 this->Release();
316 return;
317 }
318
319 char *data = read_buffer_->data();
320 while (bytes_read &&
321 flip_framer_.error_code() == flip::FlipFramer::FLIP_NO_ERROR) {
322 uint32 bytes_processed = flip_framer_.ProcessInput(data, bytes_read);
323 bytes_read -= bytes_processed;
324 data += bytes_processed;
325 if (flip_framer_.state() == flip::FlipFramer::FLIP_DONE)
326 flip_framer_.Reset();
327 }
328 // NOTE(mbelshe): Could cause circular callbacks. (when ReadSocket
329 // completes synchronously, calling OnReadComplete, etc). Should
330 // probably return to the message loop.
331 ReadSocket();
332}
333
334void FlipSession::OnWriteComplete(int result) {
335 DCHECK(write_pending_);
336 write_pending_ = false;
337
338 LOG(INFO) << "Flip write complete (result=" << result << ")";
339
[email protected]93300672009-10-24 13:22:51340 if (result >= 0) {
[email protected]eebc0b42009-11-04 00:17:13341 // TODO(mbelshe) Verify that we wrote ALL the bytes we needed to.
342 // The code current is broken in the case of a partial write.
343 DCHECK_EQ(static_cast<size_t>(result), in_flight_write_.size());
344
[email protected]93300672009-10-24 13:22:51345 // Cleanup the write which just completed.
346 in_flight_write_.release();
[email protected]aea80602009-09-18 00:55:08347
[email protected]93300672009-10-24 13:22:51348 // Write more data. We're already in a continuation, so we can
349 // go ahead and write it immediately (without going back to the
350 // message loop).
351 WriteSocketLater();
352 } else {
353 // TODO(mbelshe): Deal with result < 0 error case.
354 NOTIMPLEMENTED();
355 }
[email protected]aea80602009-09-18 00:55:08356}
357
358void FlipSession::ReadSocket() {
359 if (read_pending_)
360 return;
361
[email protected]230cadd2009-09-22 16:33:59362 int bytes_read = connection_.socket()->Read(read_buffer_.get(),
363 kReadBufferSize,
[email protected]aea80602009-09-18 00:55:08364 &read_callback_);
365 switch (bytes_read) {
366 case 0:
367 // Socket is closed!
368 // TODO(mbelshe): Need to abort any active streams here.
369 DCHECK(!active_streams_.size());
370 return;
371 case net::ERR_IO_PENDING:
372 // Waiting for data. Nothing to do now.
373 read_pending_ = true;
374 return;
375 default:
376 // Data was read, process it.
377 // TODO(mbelshe): check that we can't get a recursive stack?
378 OnReadComplete(bytes_read);
379 break;
380 }
381}
382
383void FlipSession::WriteSocketLater() {
384 if (delayed_write_pending_)
385 return;
386
387 delayed_write_pending_ = true;
388 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]18c53ae2009-10-01 18:18:52389 this, &FlipSession::WriteSocket));
[email protected]aea80602009-09-18 00:55:08390}
391
392void FlipSession::WriteSocket() {
393 // This function should only be called via WriteSocketLater.
394 DCHECK(delayed_write_pending_);
395 delayed_write_pending_ = false;
396
397 // If the socket isn't connected yet, just wait; we'll get called
398 // again when the socket connection completes.
[email protected]18c53ae2009-10-01 18:18:52399 if (!connection_ready_)
[email protected]aea80602009-09-18 00:55:08400 return;
401
402 if (write_pending_) // Another write is in progress still.
403 return;
404
[email protected]eebc0b42009-11-04 00:17:13405 // Loop sending frames until we've sent everything or until the write
406 // returns error (or ERR_IO_PENDING).
[email protected]aea80602009-09-18 00:55:08407 while (queue_.size()) {
[email protected]eebc0b42009-11-04 00:17:13408 // Grab the next FlipFrame to send.
409 FlipIOBuffer next_buffer = queue_.top();
410 queue_.pop();
[email protected]aea80602009-09-18 00:55:08411
[email protected]eebc0b42009-11-04 00:17:13412 // We've deferred compression until just before we write it to the socket,
413 // which is now.
414 flip::FlipFrame* uncompressed_frame =
415 reinterpret_cast<flip::FlipFrame*>(next_buffer.buffer()->data());
416 scoped_array<flip::FlipFrame> compressed_frame(
417 flip_framer_.CompressFrame(uncompressed_frame));
418 size_t size = compressed_frame.get()->length() + sizeof(flip::FlipFrame);
[email protected]aea80602009-09-18 00:55:08419
[email protected]eebc0b42009-11-04 00:17:13420 DCHECK(size > 0);
421
422 // TODO(mbelshe): We have too much copying of data here.
423 IOBufferWithSize* buffer = new IOBufferWithSize(size);
424 memcpy(buffer->data(), compressed_frame.get(), size);
425
426 // Attempt to send the frame.
427 in_flight_write_ = FlipIOBuffer(buffer, 0, next_buffer.stream());
[email protected]93300672009-10-24 13:22:51428 write_pending_ = true;
[email protected]aea80602009-09-18 00:55:08429 int rv = connection_.socket()->Write(in_flight_write_.buffer(),
[email protected]eebc0b42009-11-04 00:17:13430 size, &write_callback_);
[email protected]93300672009-10-24 13:22:51431 if (rv == net::ERR_IO_PENDING)
[email protected]aea80602009-09-18 00:55:08432 break;
[email protected]eebc0b42009-11-04 00:17:13433
434 // We sent the frame successfully.
[email protected]93300672009-10-24 13:22:51435 OnWriteComplete(rv);
[email protected]eebc0b42009-11-04 00:17:13436
437 // TODO(mbelshe): Test this error case. Maybe we should mark the socket
438 // as in an error state.
439 if (rv < 0)
440 break;
[email protected]aea80602009-09-18 00:55:08441 }
442}
443
444void FlipSession::CloseAllStreams(net::Error code) {
445 LOG(INFO) << "Closing all FLIP Streams";
446
447 static StatsCounter abandoned_streams("flip.abandoned_streams");
448 static StatsCounter abandoned_push_streams("flip.abandoned_push_streams");
449
450 if (active_streams_.size()) {
451 abandoned_streams.Add(active_streams_.size());
452
453 // Create a copy of the list, since aborting streams can invalidate
454 // our list.
[email protected]cd314c822009-10-29 03:13:06455 FlipStream** list = new FlipStream*[active_streams_.size()];
[email protected]aea80602009-09-18 00:55:08456 ActiveStreamMap::const_iterator it;
457 int index = 0;
458 for (it = active_streams_.begin(); it != active_streams_.end(); ++it)
459 list[index++] = it->second;
460
461 // Issue the aborts.
462 for (--index; index >= 0; index--) {
[email protected]7f78b592009-11-06 17:46:56463 LOG(ERROR) << "ABANDONED (stream_id=" << list[index]->stream_id()
464 << "): " << list[index]->path();
[email protected]93300672009-10-24 13:22:51465 list[index]->OnError(ERR_ABORTED);
[email protected]aea80602009-09-18 00:55:08466 delete list[index];
467 }
468
469 // Clear out anything pending.
470 active_streams_.clear();
471
[email protected]289bd7f2009-10-29 17:32:40472 delete[] list;
[email protected]aea80602009-09-18 00:55:08473 }
474
475 if (pushed_streams_.size()) {
476 abandoned_push_streams.Add(pushed_streams_.size());
477 pushed_streams_.clear();
478 }
479}
480
481int FlipSession::GetNewStreamId() {
482 int id = stream_hi_water_mark_;
483 stream_hi_water_mark_ += 2;
484 if (stream_hi_water_mark_ > 0x7fff)
485 stream_hi_water_mark_ = 1;
486 return id;
487}
488
[email protected]cd314c822009-10-29 03:13:06489FlipStream* FlipSession::ActivateStream(flip::FlipStreamId id,
[email protected]ba051e312009-10-07 22:12:33490 FlipDelegate* delegate) {
[email protected]aea80602009-09-18 00:55:08491 DCHECK(!IsStreamActive(id));
492
[email protected]cd314c822009-10-29 03:13:06493 FlipStream* stream = new FlipStream(id, delegate);
[email protected]aea80602009-09-18 00:55:08494 active_streams_[id] = stream;
495 return stream;
496}
497
[email protected]ba051e312009-10-07 22:12:33498void FlipSession::DeactivateStream(flip::FlipStreamId id) {
[email protected]aea80602009-09-18 00:55:08499 DCHECK(IsStreamActive(id));
500
501 // Verify it is not on the pushed_streams_ list.
502 ActiveStreamList::iterator it;
503 for (it = pushed_streams_.begin(); it != pushed_streams_.end(); ++it) {
[email protected]cd314c822009-10-29 03:13:06504 FlipStream* impl = *it;
[email protected]aea80602009-09-18 00:55:08505 if (id == impl->stream_id()) {
506 pushed_streams_.erase(it);
507 break;
508 }
509 }
510
511 active_streams_.erase(id);
512}
513
[email protected]cd314c822009-10-29 03:13:06514FlipStream* FlipSession::GetPushStream(std::string path) {
[email protected]aea80602009-09-18 00:55:08515 static StatsCounter used_push_streams("flip.claimed_push_streams");
516
517 LOG(INFO) << "Looking for push stream: " << path;
518
519 // We just walk a linear list here.
520 ActiveStreamList::iterator it;
521 for (it = pushed_streams_.begin(); it != pushed_streams_.end(); ++it) {
[email protected]cd314c822009-10-29 03:13:06522 FlipStream* impl = *it;
[email protected]aea80602009-09-18 00:55:08523 if (path == impl->path()) {
524 pushed_streams_.erase(it);
525 used_push_streams.Increment();
526 LOG(INFO) << "Push Stream Claim for: " << path;
527 return impl;
528 }
529 }
530 return NULL;
531}
532
533void FlipSession::OnError(flip::FlipFramer* framer) {
534 LOG(ERROR) << "FlipSession error!";
535 CloseAllStreams(net::ERR_UNEXPECTED);
[email protected]18c53ae2009-10-01 18:18:52536 Release();
[email protected]aea80602009-09-18 00:55:08537}
538
539void FlipSession::OnStreamFrameData(flip::FlipStreamId stream_id,
540 const char* data,
[email protected]aeac1e42009-10-10 00:26:01541 size_t len) {
[email protected]aea80602009-09-18 00:55:08542 LOG(INFO) << "Flip data for stream " << stream_id << ", " << len << " bytes";
543 bool valid_stream = IsStreamActive(stream_id);
544 if (!valid_stream) {
[email protected]affe8fe2009-10-14 20:06:05545 LOG(WARNING) << "Received data frame for invalid stream " << stream_id;
[email protected]aea80602009-09-18 00:55:08546 return;
547 }
[email protected]93300672009-10-24 13:22:51548
[email protected]cd314c822009-10-29 03:13:06549 FlipStream* stream = active_streams_[stream_id];
[email protected]aea80602009-09-18 00:55:08550 if (stream->OnData(data, len)) {
551 DeactivateStream(stream->stream_id());
552 delete stream;
553 }
554}
555
556void FlipSession::OnSyn(const flip::FlipSynStreamControlFrame* frame,
557 const flip::FlipHeaderBlock* headers) {
558 flip::FlipStreamId stream_id = frame->stream_id();
559
[email protected]93300672009-10-24 13:22:51560 // Server-initiated streams should have even sequence numbers.
[email protected]aea80602009-09-18 00:55:08561 if ((stream_id & 0x1) != 0) {
[email protected]18c53ae2009-10-01 18:18:52562 LOG(ERROR) << "Received invalid OnSyn stream id " << stream_id;
[email protected]aea80602009-09-18 00:55:08563 return;
564 }
565
566 if (IsStreamActive(stream_id)) {
[email protected]18c53ae2009-10-01 18:18:52567 LOG(ERROR) << "Received OnSyn for active stream " << stream_id;
[email protected]aea80602009-09-18 00:55:08568 return;
569 }
570
[email protected]18c53ae2009-10-01 18:18:52571 // Activate a stream and parse the headers.
[email protected]cd314c822009-10-29 03:13:06572 FlipStream* stream = ActivateStream(stream_id, NULL);
[email protected]aea80602009-09-18 00:55:08573 stream->OnReply(headers);
574
[email protected]18c53ae2009-10-01 18:18:52575 // TODO(mbelshe): DCHECK that this is a GET method?
576
[email protected]aea80602009-09-18 00:55:08577 // Verify that the response had a URL for us.
578 DCHECK(stream->path().length() != 0);
579 if (stream->path().length() == 0) {
580 LOG(WARNING) << "Pushed stream did not contain a path.";
581 DeactivateStream(stream_id);
582 delete stream;
583 return;
584 }
[email protected]18c53ae2009-10-01 18:18:52585
586 // Check if we already have a delegate awaiting this stream.
587 std::map<std::string, FlipDelegate*>::iterator it;
588 it = pending_streams_.find(stream->path());
589 if (it != pending_streams_.end()) {
590 FlipDelegate* delegate = it->second;
591 pending_streams_.erase(it);
592 if (delegate)
593 stream->AttachDelegate(delegate);
594 else
595 pushed_streams_.push_back(stream);
596 } else {
597 pushed_streams_.push_back(stream);
598 }
[email protected]aea80602009-09-18 00:55:08599
600 LOG(INFO) << "Got pushed stream for " << stream->path();
601
602 static StatsCounter push_requests("flip.pushed_streams");
603 push_requests.Increment();
604}
605
606void FlipSession::OnSynReply(const flip::FlipSynReplyControlFrame* frame,
607 const flip::FlipHeaderBlock* headers) {
608 DCHECK(headers);
609 flip::FlipStreamId stream_id = frame->stream_id();
610 bool valid_stream = IsStreamActive(stream_id);
611 if (!valid_stream) {
[email protected]affe8fe2009-10-14 20:06:05612 LOG(WARNING) << "Received SYN_REPLY for invalid stream " << stream_id;
[email protected]aea80602009-09-18 00:55:08613 return;
614 }
615
[email protected]18c53ae2009-10-01 18:18:52616 // We record content declared as being pushed so that we don't
617 // request a duplicate stream which is already scheduled to be
618 // sent to us.
619 flip::FlipHeaderBlock::const_iterator it;
620 it = headers->find("X-Associated-Content");
621 if (it != headers->end()) {
622 const std::string& content = it->second;
623 std::string::size_type start = 0;
624 std::string::size_type end = 0;
625 do {
626 end = content.find("||", start);
[email protected]ba051e312009-10-07 22:12:33627 if (end == std::string::npos)
[email protected]18c53ae2009-10-01 18:18:52628 end = content.length();
629 std::string url = content.substr(start, end - start);
630 std::string::size_type pos = url.find("??");
[email protected]ba051e312009-10-07 22:12:33631 if (pos == std::string::npos)
[email protected]18c53ae2009-10-01 18:18:52632 break;
[email protected]ba051e312009-10-07 22:12:33633 url = url.substr(pos + 2);
[email protected]18c53ae2009-10-01 18:18:52634 GURL gurl(url);
635 pending_streams_[gurl.PathForRequest()] = NULL;
636 start = end + 2;
637 } while (end < content.length());
638 }
639
[email protected]cd314c822009-10-29 03:13:06640 FlipStream* stream = active_streams_[stream_id];
[email protected]aea80602009-09-18 00:55:08641 stream->OnReply(headers);
642}
643
644void FlipSession::OnControl(const flip::FlipControlFrame* frame) {
645 flip::FlipHeaderBlock headers;
[email protected]aea80602009-09-18 00:55:08646 uint32 type = frame->type();
647 if (type == flip::SYN_STREAM || type == flip::SYN_REPLY) {
648 if (!flip_framer_.ParseHeaderBlock(
649 reinterpret_cast<const flip::FlipFrame*>(frame), &headers)) {
650 LOG(WARNING) << "Could not parse Flip Control Frame Header";
651 return;
652 }
653 }
654
655 switch (type) {
656 case flip::SYN_STREAM:
657 LOG(INFO) << "Flip SynStream for stream " << frame->stream_id();
658 OnSyn(reinterpret_cast<const flip::FlipSynStreamControlFrame*>(frame),
659 &headers);
660 break;
661 case flip::SYN_REPLY:
662 LOG(INFO) << "Flip SynReply for stream " << frame->stream_id();
663 OnSynReply(
664 reinterpret_cast<const flip::FlipSynReplyControlFrame*>(frame),
665 &headers);
666 break;
667 case flip::FIN_STREAM:
668 LOG(INFO) << "Flip Fin for stream " << frame->stream_id();
669 OnFin(reinterpret_cast<const flip::FlipFinStreamControlFrame*>(frame));
670 break;
671 default:
672 DCHECK(false); // Error!
673 }
674}
675
676void FlipSession::OnFin(const flip::FlipFinStreamControlFrame* frame) {
677 flip::FlipStreamId stream_id = frame->stream_id();
678 bool valid_stream = IsStreamActive(stream_id);
679 if (!valid_stream) {
680 LOG(WARNING) << "Received FIN for invalid stream" << stream_id;
681 return;
682 }
[email protected]cd314c822009-10-29 03:13:06683 FlipStream* stream = active_streams_[stream_id];
[email protected]aea80602009-09-18 00:55:08684 bool cleanup_stream = false;
[email protected]93300672009-10-24 13:22:51685 if (frame->status() == 0) {
[email protected]aea80602009-09-18 00:55:08686 cleanup_stream = stream->OnData(NULL, 0);
687 } else {
[email protected]93300672009-10-24 13:22:51688 LOG(ERROR) << "Flip stream closed: " << frame->status();
689 // TODO(mbelshe): Map from Flip-protocol errors to something sensical.
690 // For now, it doesn't matter much - it is a protocol error.
691 stream->OnError(ERR_FAILED);
[email protected]aea80602009-09-18 00:55:08692 cleanup_stream = true;
693 }
694
695 if (cleanup_stream) {
696 DeactivateStream(stream_id);
697 delete stream;
698 }
699}
700
701void FlipSession::OnLameDuck() {
702 NOTIMPLEMENTED();
703}
704
[email protected]aea80602009-09-18 00:55:08705} // namespace net