summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormbelshe@chromium.org <mbelshe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-25 17:24:50 +0000
committermbelshe@chromium.org <mbelshe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-25 17:24:50 +0000
commit82918ccd87a794552905fc3a9b04c8afae1bc4ca (patch)
treee8bbe1df61dc06df43e2c2b94973c0bfb90147da
parent08f44aa3b9de47dec72f931ff36db9c1d067aeed (diff)
downloadchromium_src-82918ccd87a794552905fc3a9b04c8afae1bc4ca.zip
chromium_src-82918ccd87a794552905fc3a9b04c8afae1bc4ca.tar.gz
chromium_src-82918ccd87a794552905fc3a9b04c8afae1bc4ca.tar.bz2
Move the stream initialization out of the HttpStreamRequest and back
into the HttpNetworkTransaction. The reason is because the stream factory should get the stream connected, but not actually initialize the stream; stream initialization should only happen when the stream uses it. BUG=none TEST=none Review URL: http://codereview.chromium.org/3137034 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@57342 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/http/http_cache_transaction.h1
-rw-r--r--net/http/http_network_transaction.cc81
-rw-r--r--net/http/http_network_transaction.h5
-rw-r--r--net/http/http_stream_factory.h3
-rw-r--r--net/http/http_stream_handle.h2
-rw-r--r--net/http/http_stream_request.cc28
-rw-r--r--net/http/http_stream_request.h9
-rw-r--r--net/http/stream_factory.h4
-rw-r--r--net/spdy/spdy_http_stream.cc11
-rw-r--r--net/spdy/spdy_network_transaction_unittest.cc55
10 files changed, 138 insertions, 61 deletions
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index 05a8484..2883282 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -22,6 +22,7 @@ namespace net {
class HttpResponseHeaders;
class PartialData;
+struct HttpRequestInfo;
// This is the transaction that is returned by the HttpCache transaction
// factory.
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 1ff166c..4e46f2b 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -176,7 +176,7 @@ int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
request_ = request_info;
start_time_ = base::Time::Now();
- next_state_ = STATE_INIT_STREAM;
+ next_state_ = STATE_CREATE_STREAM;
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
user_callback_ = callback;
@@ -189,7 +189,7 @@ int HttpNetworkTransaction::RestartIgnoringLastError(
DCHECK(!stream_request_.get());
DCHECK_EQ(STATE_NONE, next_state_);
- next_state_ = STATE_INIT_STREAM;
+ next_state_ = STATE_CREATE_STREAM;
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
@@ -215,7 +215,7 @@ int HttpNetworkTransaction::RestartWithCertificate(
// Reset the other member variables.
// Note: this is necessary only with SSL renegotiation.
ResetStateForRestart();
- next_state_ = STATE_INIT_STREAM;
+ next_state_ = STATE_CREATE_STREAM;
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
user_callback_ = callback;
@@ -241,7 +241,7 @@ int HttpNetworkTransaction::RestartWithAuth(
if (target == HttpAuth::AUTH_PROXY && establishing_tunnel_) {
// In this case, we've gathered credentials for use with proxy
// authentication of a tunnel.
- DCHECK_EQ(STATE_INIT_STREAM_COMPLETE, next_state_);
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
DCHECK(stream_request_ != NULL);
auth_controllers_[target] = NULL;
ResetStateForRestart();
@@ -294,7 +294,7 @@ void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
stream_->SetConnectionReused();
}
stream_->Close(!keep_alive);
- next_state_ = STATE_INIT_STREAM;
+ next_state_ = STATE_CREATE_STREAM;
}
// Reset the other member variables.
@@ -353,7 +353,7 @@ LoadState HttpNetworkTransaction::GetLoadState() const {
// TODO(wtc): Define a new LoadState value for the
// STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
switch (next_state_) {
- case STATE_INIT_STREAM_COMPLETE:
+ case STATE_CREATE_STREAM_COMPLETE:
return stream_request_->GetLoadState();
case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE:
case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE:
@@ -376,7 +376,7 @@ uint64 HttpNetworkTransaction::GetUploadProgress() const {
}
void HttpNetworkTransaction::OnStreamReady(HttpStreamHandle* stream) {
- DCHECK_EQ(STATE_INIT_STREAM_COMPLETE, next_state_);
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
DCHECK(stream_request_.get());
stream_.reset(stream);
@@ -385,16 +385,12 @@ void HttpNetworkTransaction::OnStreamReady(HttpStreamHandle* stream) {
response_.was_npn_negotiated = stream_request_->was_npn_negotiated();
response_.was_fetched_via_spdy = stream_request_->using_spdy();
response_.was_fetched_via_proxy = !proxy_info_.is_direct();
- reused_socket_ = stream->IsConnectionReused();
-
- if (is_https_request())
- stream->GetSSLInfo(&response_.ssl_info);
OnIOComplete(OK);
}
void HttpNetworkTransaction::OnStreamFailed(int result) {
- DCHECK_EQ(STATE_INIT_STREAM_COMPLETE, next_state_);
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
DCHECK_NE(OK, result);
DCHECK(stream_request_.get());
DCHECK(!stream_.get());
@@ -404,7 +400,7 @@ void HttpNetworkTransaction::OnStreamFailed(int result) {
void HttpNetworkTransaction::OnCertificateError(int result,
const SSLInfo& ssl_info) {
- DCHECK_EQ(STATE_INIT_STREAM_COMPLETE, next_state_);
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
DCHECK_NE(OK, result);
DCHECK(stream_request_.get());
DCHECK(!stream_.get());
@@ -413,9 +409,9 @@ void HttpNetworkTransaction::OnCertificateError(int result,
// TODO(mbelshe): For now, we're going to pass the error through, and that
// will close the stream_request in all cases. This means that we're always
- // going to restart an entire INIT_STREAM, even if the connection is good and
- // the user chooses to ignore the error. This is not ideal, but not the end
- // of the world either.
+ // going to restart an entire STATE_CREATE_STREAM, even if the connection is
+ // good and the user chooses to ignore the error. This is not ideal, but not
+ // the end of the world either.
OnIOComplete(result);
}
@@ -424,7 +420,7 @@ void HttpNetworkTransaction::OnNeedsProxyAuth(
const scoped_refptr<HttpAuthController>& auth_controller,
const HttpResponseInfo& proxy_response) {
DCHECK(stream_request_.get());
- DCHECK_EQ(STATE_INIT_STREAM_COMPLETE, next_state_);
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
establishing_tunnel_ = true;
response_.headers = proxy_response.headers;
@@ -439,7 +435,7 @@ void HttpNetworkTransaction::OnNeedsProxyAuth(
void HttpNetworkTransaction::OnNeedsClientAuth(
const scoped_refptr<SSLCertRequestInfo>& cert_info) {
- DCHECK_EQ(STATE_INIT_STREAM_COMPLETE, next_state_);
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
response_.cert_request_info = cert_info;
OnIOComplete(ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
@@ -492,6 +488,13 @@ int HttpNetworkTransaction::DoLoop(int result) {
State state = next_state_;
next_state_ = STATE_NONE;
switch (state) {
+ case STATE_CREATE_STREAM:
+ DCHECK_EQ(OK, rv);
+ rv = DoCreateStream();
+ break;
+ case STATE_CREATE_STREAM_COMPLETE:
+ rv = DoCreateStreamComplete(rv);
+ break;
case STATE_INIT_STREAM:
DCHECK_EQ(OK, rv);
rv = DoInitStream();
@@ -561,8 +564,8 @@ int HttpNetworkTransaction::DoLoop(int result) {
return rv;
}
-int HttpNetworkTransaction::DoInitStream() {
- next_state_ = STATE_INIT_STREAM_COMPLETE;
+int HttpNetworkTransaction::DoCreateStream() {
+ next_state_ = STATE_CREATE_STREAM_COMPLETE;
session_->http_stream_factory()->RequestStream(request_,
&ssl_config_,
@@ -574,12 +577,10 @@ int HttpNetworkTransaction::DoInitStream() {
return ERR_IO_PENDING;
}
-int HttpNetworkTransaction::DoInitStreamComplete(int result) {
+int HttpNetworkTransaction::DoCreateStreamComplete(int result) {
if (result == OK) {
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
+ next_state_ = STATE_INIT_STREAM;
DCHECK(stream_.get());
- } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
- result = HandleCertificateRequest(result);
}
// At this point we are done with the stream_request_.
@@ -587,6 +588,30 @@ int HttpNetworkTransaction::DoInitStreamComplete(int result) {
return result;
}
+int HttpNetworkTransaction::DoInitStream() {
+ DCHECK(stream_.get());
+ next_state_ = STATE_INIT_STREAM_COMPLETE;
+ return stream_->InitializeStream(request_, net_log_, &io_callback_);
+}
+
+int HttpNetworkTransaction::DoInitStreamComplete(int result) {
+ if (result == OK) {
+ next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
+
+ reused_socket_ = stream_->IsConnectionReused();
+ if (is_https_request())
+ stream_->GetSSLInfo(&response_.ssl_info);
+ } else {
+ if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED)
+ result = HandleCertificateRequest(result);
+
+ if (result < 0)
+ return HandleIOError(result);
+ }
+
+ return result;
+}
+
int HttpNetworkTransaction::DoGenerateProxyAuthToken() {
next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE;
if (!ShouldApplyProxyAuth())
@@ -1019,7 +1044,7 @@ int HttpNetworkTransaction::HandleCertificateRequest(int error) {
// SSL session cache.
ssl_config_.client_cert = client_cert;
ssl_config_.send_client_cert = true;
- next_state_ = STATE_INIT_STREAM;
+ next_state_ = STATE_CREATE_STREAM;
// Reset the other member variables.
// Note: this is necessary only with SSL renegotiation.
ResetStateForRestart();
@@ -1089,7 +1114,7 @@ void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
// headers, but we may need to resend the CONNECT request first to recreate
// the SSL tunnel.
request_headers_.clear();
- next_state_ = STATE_INIT_STREAM; // Resend the request.
+ next_state_ = STATE_CREATE_STREAM; // Resend the request.
}
bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
@@ -1155,8 +1180,8 @@ GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const {
std::string HttpNetworkTransaction::DescribeState(State state) {
std::string description;
switch (state) {
- STATE_CASE(STATE_INIT_STREAM);
- STATE_CASE(STATE_INIT_STREAM_COMPLETE);
+ STATE_CASE(STATE_CREATE_STREAM);
+ STATE_CASE(STATE_CREATE_STREAM_COMPLETE);
STATE_CASE(STATE_SEND_REQUEST);
STATE_CASE(STATE_SEND_REQUEST_COMPLETE);
STATE_CASE(STATE_READ_HEADERS);
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index 9677275..8559885 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -29,6 +29,7 @@ class HttpNetworkSession;
class HttpStream;
class HttpStreamHandle;
class IOBuffer;
+struct HttpRequestInfo;
class HttpNetworkTransaction : public HttpTransaction,
public StreamFactory::StreamRequestDelegate {
@@ -72,6 +73,8 @@ class HttpNetworkTransaction : public HttpTransaction,
FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionTest, FlowControlStallResume);
enum State {
+ STATE_CREATE_STREAM,
+ STATE_CREATE_STREAM_COMPLETE,
STATE_INIT_STREAM,
STATE_INIT_STREAM_COMPLETE,
STATE_GENERATE_PROXY_AUTH_TOKEN,
@@ -101,6 +104,8 @@ class HttpNetworkTransaction : public HttpTransaction,
// argument receive the result from the previous state. If a method returns
// ERR_IO_PENDING, then the result from OnIOComplete will be passed to the
// next state method as the result arg.
+ int DoCreateStream();
+ int DoCreateStreamComplete(int result);
int DoInitStream();
int DoInitStreamComplete(int result);
int DoGenerateProxyAuthToken();
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h
index 8b64cda..5c6f179 100644
--- a/net/http/http_stream_factory.h
+++ b/net/http/http_stream_factory.h
@@ -8,7 +8,6 @@
#include <set>
#include <string>
-
#include "base/scoped_ptr.h"
#include "net/base/completion_callback.h"
#include "net/base/host_mapping_rules.h"
@@ -19,10 +18,10 @@
#include "net/proxy/proxy_service.h"
#include "net/socket/client_socket_handle.h"
-
namespace net {
class HttpNetworkSession;
+struct HttpRequestInfo;
class HttpStreamFactory : public StreamFactory,
public base::RefCounted<HttpStreamFactory> {
diff --git a/net/http/http_stream_handle.h b/net/http/http_stream_handle.h
index 213cc3a..2d43abb 100644
--- a/net/http/http_stream_handle.h
+++ b/net/http/http_stream_handle.h
@@ -14,6 +14,8 @@
namespace net {
+struct HttpRequestInfo;
+
// The HttpStreamHandle provides a container for a ClientSocketHandle and
// a stream. The HttpStream does not own the ClientSocketHandle which it uses.
// The HttpStreamHandle container can be used in cases where you just want a
diff --git a/net/http/http_stream_request.cc b/net/http/http_stream_request.cc
index 8ca375b..07e1e1f2 100644
--- a/net/http/http_stream_request.cc
+++ b/net/http/http_stream_request.cc
@@ -142,14 +142,12 @@ int HttpStreamRequest::RestartTunnelWithProxyAuth(const string16& username,
}
LoadState HttpStreamRequest::GetLoadState() const {
- // TODO(wtc): Define a new LoadState value for the
- // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
switch (next_state_) {
case STATE_RESOLVE_PROXY_COMPLETE:
return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
- case STATE_INIT_CONNECTION_COMPLETE:
+ case STATE_CREATE_STREAM_COMPLETE:
return connection_->GetLoadState();
- case STATE_INIT_STREAM_COMPLETE:
+ case STATE_INIT_CONNECTION_COMPLETE:
return LOAD_STATE_SENDING_REQUEST;
default:
return LOAD_STATE_IDLE;
@@ -320,12 +318,12 @@ int HttpStreamRequest::DoLoop(int result) {
case STATE_RESTART_TUNNEL_AUTH_COMPLETE:
rv = DoRestartTunnelAuthComplete(rv);
break;
- case STATE_INIT_STREAM:
+ case STATE_CREATE_STREAM:
DCHECK_EQ(OK, rv);
- rv = DoInitStream();
+ rv = DoCreateStream();
break;
- case STATE_INIT_STREAM_COMPLETE:
- rv = DoInitStreamComplete(rv);
+ case STATE_CREATE_STREAM_COMPLETE:
+ rv = DoCreateStreamComplete(rv);
break;
default:
NOTREACHED() << "bad state";
@@ -426,7 +424,7 @@ int HttpStreamRequest::DoInitConnection() {
HostPortProxyPair pair(endpoint_, proxy_info()->proxy_server());
if (session_->spdy_session_pool()->HasSession(pair)) {
using_spdy_ = true;
- next_state_ = STATE_INIT_STREAM;
+ next_state_ = STATE_CREATE_STREAM;
return OK;
}
@@ -656,7 +654,7 @@ int HttpStreamRequest::DoInitConnectionComplete(int result) {
return HandleSSLHandshakeError(result);
}
- next_state_ = STATE_INIT_STREAM;
+ next_state_ = STATE_CREATE_STREAM;
return OK;
}
@@ -669,13 +667,13 @@ int HttpStreamRequest::DoWaitingUserAction(int result) {
return ERR_IO_PENDING;
}
-int HttpStreamRequest::DoInitStream() {
- next_state_ = STATE_INIT_STREAM_COMPLETE;
+int HttpStreamRequest::DoCreateStream() {
+ next_state_ = STATE_CREATE_STREAM_COMPLETE;
if (!using_spdy_) {
HttpBasicStream* stream = new HttpBasicStream(connection_.get());
stream_.reset(new HttpStreamHandle(connection_.release(), stream));
- return stream_->InitializeStream(&request_info(), net_log_, &io_callback_);
+ return OK;
}
CHECK(!stream_.get());
@@ -705,10 +703,10 @@ int HttpStreamRequest::DoInitStream() {
SpdyHttpStream* stream = new SpdyHttpStream(spdy_session);
stream_.reset(new HttpStreamHandle(NULL, stream));
- return stream_->InitializeStream(&request_info(), net_log_, &io_callback_);
+ return OK;
}
-int HttpStreamRequest::DoInitStreamComplete(int result) {
+int HttpStreamRequest::DoCreateStreamComplete(int result) {
if (result < 0)
return result;
diff --git a/net/http/http_stream_request.h b/net/http/http_stream_request.h
index 3039839..c7c3cf2 100644
--- a/net/http/http_stream_request.h
+++ b/net/http/http_stream_request.h
@@ -24,6 +24,7 @@ class HttpAuthController;
class HttpNetworkSession;
class HttpStreamFactory;
class StreamRequestDelegate;
+struct HttpRequestInfo;
// An HttpStreamRequest exists for each stream which is in progress of being
// created for the StreamFactory.
@@ -67,8 +68,8 @@ class HttpStreamRequest : public StreamFactory::StreamRequestJob {
STATE_WAITING_USER_ACTION,
STATE_RESTART_TUNNEL_AUTH,
STATE_RESTART_TUNNEL_AUTH_COMPLETE,
- STATE_INIT_STREAM,
- STATE_INIT_STREAM_COMPLETE,
+ STATE_CREATE_STREAM,
+ STATE_CREATE_STREAM_COMPLETE,
STATE_DRAIN_BODY_FOR_AUTH_RESTART,
STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE,
STATE_NONE
@@ -101,8 +102,8 @@ class HttpStreamRequest : public StreamFactory::StreamRequestJob {
int DoInitConnection();
int DoInitConnectionComplete(int result);
int DoWaitingUserAction(int result);
- int DoInitStream();
- int DoInitStreamComplete(int result);
+ int DoCreateStream();
+ int DoCreateStreamComplete(int result);
int DoRestartTunnelAuth();
int DoRestartTunnelAuthComplete(int result);
diff --git a/net/http/stream_factory.h b/net/http/stream_factory.h
index 39b2241..fe906d3 100644
--- a/net/http/stream_factory.h
+++ b/net/http/stream_factory.h
@@ -12,7 +12,6 @@
namespace net {
-struct HttpRequestInfo;
class BoundNetLog;
class HostPortPair;
class HttpAlternateProtocols;
@@ -24,6 +23,9 @@ class HttpStreamHandle;
class ProxyInfo;
class SSLCertRequestInfo;
class SSLInfo;
+class X509Certificate;
+struct HttpRequestInfo;
+struct SSLConfig;
// The StreamFactory defines an interface for creating usable HttpStreams.
class StreamFactory {
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc
index 622d2c0..de0cc14 100644
--- a/net/spdy/spdy_http_stream.cc
+++ b/net/spdy/spdy_http_stream.cc
@@ -170,6 +170,9 @@ SpdyHttpStream::~SpdyHttpStream() {
int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info,
const BoundNetLog& stream_net_log,
CompletionCallback* callback) {
+ if (spdy_session_->IsClosed())
+ return ERR_CONNECTION_CLOSED;
+
request_info_ = request_info;
if (request_info_->method == "GET") {
int error = spdy_session_->GetPushStream(request_info_->url, &stream_,
@@ -180,10 +183,10 @@ int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info,
if (stream_.get())
return OK;
- else
- return spdy_session_->CreateStream(request_info_->url,
- request_info_->priority, &stream_,
- stream_net_log, callback);
+
+ return spdy_session_->CreateStream(request_info_->url,
+ request_info_->priority, &stream_,
+ stream_net_log, callback);
}
const HttpResponseInfo* SpdyHttpStream::GetResponseInfo() const {
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index f194eff..b3738a6 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -1307,13 +1307,11 @@ TEST_P(SpdyNetworkTransactionTest, PostWithEarlySynReply) {
scoped_ptr<UploadDataStream> stream(UploadDataStream::Create(
request.upload_data, NULL));
ASSERT_EQ(request.upload_data->GetContentLength(), stream->size());
-
- scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
-
- scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
+ scoped_ptr<spdy::SpdyFrame> stream_reply(ConstructSpdyPostSynReply(NULL, 0));
+ scoped_ptr<spdy::SpdyFrame> stream_body(ConstructSpdyBodyFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp.get(), 2),
- CreateMockRead(*body.get(), 3),
+ CreateMockRead(*stream_reply, 2),
+ CreateMockRead(*stream_body, 3),
MockRead(false, 0, 0) // EOF
};
@@ -1327,7 +1325,7 @@ TEST_P(SpdyNetworkTransactionTest, PostWithEarlySynReply) {
helper.VerifyDataConsumed();
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
+ EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv);
}
// The client upon cancellation tries to send a RST_STREAM frame. The mock
@@ -2228,6 +2226,49 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
}
+TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
+ static const unsigned char kPushBodyFrame[] = {
+ 0x00, 0x00, 0x00, 0x02, // header, ID
+ 0x01, 0x00, 0x00, 0x06, // FIN, length
+ 'p', 'u', 's', 'h', 'e', 'd' // "pushed"
+ };
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ MockWrite writes[] = {
+ CreateMockWrite(*stream1_syn, 1),
+ };
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_syn(ConstructSpdyPush(NULL, 0, 2, 1, "/foo.dat"));
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_body(ConstructSpdyBodyFrame(1, true));
+ MockRead reads[] = {
+ CreateMockRead(*stream1_reply, 2),
+ CreateMockRead(*stream2_syn, 3),
+ MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame),
+ arraysize(kPushBodyFrame), 5),
+ CreateMockRead(*stream1_body, 4, false),
+ MockRead(true, ERR_IO_PENDING, 6), // Force a pause
+ };
+
+ HttpResponseInfo response;
+ HttpResponseInfo response2;
+ std::string expected_push_result("pushed");
+ RunServerPushTest(writes, arraysize(writes), reads, arraysize(reads),
+ &response, &response2, expected_push_result);
+
+ // Verify the SYN_REPLY.
+ EXPECT_TRUE(response.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
+
+ // Verify the pushed stream.
+ EXPECT_TRUE(response2.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
+}
+
+
TEST_P(SpdyNetworkTransactionTest, ServerPushServerAborted) {
scoped_ptr<spdy::SpdyFrame>
stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));