Commit 1e6a36e2 authored by bnc's avatar bnc Committed by Commit bot

Process HTTP/2 ALTSVC frames.

BUG=617177

Review-Url: https://codereview.chromium.org/2031373002
Cr-Commit-Position: refs/heads/master@{#397894}
parent ee366ce9
......@@ -326,6 +326,13 @@ void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id,
InitHeaderStreaming(stream_id);
}
void BufferedSpdyFramer::OnAltSvc(
SpdyStreamId stream_id,
base::StringPiece origin,
const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) {
visitor_->OnAltSvc(stream_id, origin, altsvc_vector);
}
void BufferedSpdyFramer::OnContinuation(SpdyStreamId stream_id, bool end) {
}
......
......@@ -15,6 +15,7 @@
#include "net/base/net_export.h"
#include "net/socket/next_proto.h"
#include "net/spdy/header_coalescer.h"
#include "net/spdy/spdy_alt_svc_wire_format.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_header_block.h"
#include "net/spdy/spdy_protocol.h"
......@@ -117,6 +118,12 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramerVisitorInterface {
SpdyStreamId promised_stream_id,
const SpdyHeaderBlock& headers) = 0;
// Called when an ALTSVC frame has been parsed.
virtual void OnAltSvc(
SpdyStreamId stream_id,
base::StringPiece origin,
const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) = 0;
// Called when a frame type we don't recognize is received.
// Return true if this appears to be a valid extension frame, false otherwise.
// We distinguish between extension frames and nonsense by checking
......@@ -186,6 +193,10 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramer
void OnPushPromise(SpdyStreamId stream_id,
SpdyStreamId promised_stream_id,
bool end) override;
void OnAltSvc(SpdyStreamId stream_id,
base::StringPiece origin,
const SpdyAltSvcWireFormat::AlternativeServiceVector&
altsvc_vector) override;
void OnDataFrameHeader(SpdyStreamId stream_id,
size_t length,
bool fin) override;
......
......@@ -23,6 +23,7 @@ class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
headers_frame_count_(0),
push_promise_frame_count_(0),
goaway_count_(0),
altsvc_count_(0),
header_stream_id_(static_cast<SpdyStreamId>(-1)),
promised_stream_id_(static_cast<SpdyStreamId>(-1)) {}
......@@ -132,6 +133,16 @@ class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
headers_ = headers;
}
void OnAltSvc(SpdyStreamId stream_id,
base::StringPiece origin,
const SpdyAltSvcWireFormat::AlternativeServiceVector&
altsvc_vector) override {
altsvc_count_++;
altsvc_stream_id_ = stream_id;
origin.CopyToString(&altsvc_origin_);
altsvc_vector_ = altsvc_vector;
}
bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override {
return true;
}
......@@ -166,6 +177,7 @@ class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
int headers_frame_count_;
int push_promise_frame_count_;
int goaway_count_;
int altsvc_count_;
// Header block streaming state:
SpdyStreamId header_stream_id_;
......@@ -179,6 +191,11 @@ class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
SpdyStreamId goaway_last_accepted_stream_id_;
SpdyGoAwayStatus goaway_status_;
std::string goaway_debug_data_;
// OnAltSvc parameters.
SpdyStreamId altsvc_stream_id_;
std::string altsvc_origin_;
SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector_;
};
} // namespace
......@@ -363,4 +380,31 @@ TEST_P(BufferedSpdyFramerTest, GoAwayDebugData) {
EXPECT_EQ("foo", visitor.goaway_debug_data_);
}
TEST_P(BufferedSpdyFramerTest, OnAltSvc) {
if (spdy_version() < HTTP2)
return;
const SpdyStreamId altsvc_stream_id(1);
const char altsvc_origin[] = "https://www.example.org";
SpdyAltSvcIR altsvc_ir(altsvc_stream_id);
SpdyAltSvcWireFormat::AlternativeService alternative_service(
"quic", "alternative.example.org", 443, 86400,
SpdyAltSvcWireFormat::VersionVector());
altsvc_ir.add_altsvc(alternative_service);
altsvc_ir.set_origin(altsvc_origin);
BufferedSpdyFramer framer(spdy_version());
SpdySerializedFrame altsvc_frame(framer.SerializeFrame(altsvc_ir));
TestBufferedSpdyVisitor visitor(spdy_version());
visitor.SimulateInFramer(
reinterpret_cast<unsigned char*>(altsvc_frame.data()),
altsvc_frame.size());
EXPECT_EQ(0, visitor.error_count_);
EXPECT_EQ(1, visitor.altsvc_count_);
EXPECT_EQ(altsvc_stream_id, visitor.altsvc_stream_id_);
EXPECT_EQ(altsvc_origin, visitor.altsvc_origin_);
ASSERT_EQ(1u, visitor.altsvc_vector_.size());
EXPECT_EQ(alternative_service, visitor.altsvc_vector_[0]);
}
} // namespace net
......@@ -2483,6 +2483,61 @@ void SpdySession::OnHeaders(SpdyStreamId stream_id,
}
}
void SpdySession::OnAltSvc(
SpdyStreamId stream_id,
base::StringPiece origin,
const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) {
if (!is_secure_)
return;
url::SchemeHostPort scheme_host_port;
if (stream_id == 0) {
if (origin.empty())
return;
const GURL gurl(origin);
if (!gurl.SchemeIs("https"))
return;
SSLInfo ssl_info;
bool was_npn_negotiated;
NextProto protocol_negotiated = kProtoUnknown;
if (!GetSSLInfo(&ssl_info, &was_npn_negotiated, &protocol_negotiated))
return;
if (!CanPool(transport_security_state_, ssl_info, host_port_pair().host(),
gurl.host())) {
return;
}
scheme_host_port = url::SchemeHostPort(gurl);
} else {
if (!origin.empty())
return;
const ActiveStreamMap::iterator it = active_streams_.find(stream_id);
if (it == active_streams_.end())
return;
const GURL& gurl(it->second.stream->url());
if (!gurl.SchemeIs("https"))
return;
scheme_host_port = url::SchemeHostPort(gurl);
}
AlternativeServiceInfoVector alternative_service_info_vector;
alternative_service_info_vector.reserve(altsvc_vector.size());
const base::Time now(base::Time::Now());
for (const SpdyAltSvcWireFormat::AlternativeService& altsvc : altsvc_vector) {
const AlternateProtocol protocol =
AlternateProtocolFromString(altsvc.protocol_id);
if (protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
continue;
const AlternativeService alternative_service(protocol, altsvc.host,
altsvc.port);
const base::Time expiration =
now + base::TimeDelta::FromSeconds(altsvc.max_age);
alternative_service_info_vector.push_back(
AlternativeServiceInfo(alternative_service, expiration));
}
http_server_properties_->SetAlternativeServices(
scheme_host_port, alternative_service_info_vector);
}
bool SpdySession::OnUnknownFrame(SpdyStreamId stream_id, int frame_type) {
// Validate stream id.
// Was the frame sent on a stream id that has not been used in this session?
......
......@@ -33,6 +33,7 @@
#include "net/socket/stream_socket.h"
#include "net/spdy/buffered_spdy_framer.h"
#include "net/spdy/http2_priority_dependencies.h"
#include "net/spdy/spdy_alt_svc_wire_format.h"
#include "net/spdy/spdy_buffer.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_header_block.h"
......@@ -908,6 +909,10 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
bool exclusive,
bool fin,
const SpdyHeaderBlock& headers) override;
void OnAltSvc(SpdyStreamId stream_id,
base::StringPiece origin,
const SpdyAltSvcWireFormat::AlternativeServiceVector&
altsvc_vector) override;
bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override;
// SpdyFramerDebugVisitorInterface
......
This diff is collapsed.
......@@ -25,6 +25,7 @@
#include "net/socket/ssl_client_socket.h"
#include "net/socket/transport_client_socket_pool.h"
#include "net/spdy/buffered_spdy_framer.h"
#include "net/spdy/spdy_alt_svc_wire_format.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/spdy/spdy_session.h"
......@@ -228,6 +229,10 @@ class PriorityGetter : public BufferedSpdyFramerVisitorInterface {
void OnPushPromise(SpdyStreamId stream_id,
SpdyStreamId promised_stream_id,
const SpdyHeaderBlock& headers) override {}
void OnAltSvc(SpdyStreamId stream_id,
base::StringPiece origin,
const SpdyAltSvcWireFormat::AlternativeServiceVector&
altsvc_vector) override {}
bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override {
return false;
}
......@@ -1235,6 +1240,10 @@ SpdySerializedFrame* SpdyTestUtil::ConstructWrappedSpdyFrame(
frame->size(), false);
}
SpdySerializedFrame SpdyTestUtil::SerializeFrame(const SpdyFrameIR& frame_ir) {
return headerless_spdy_framer_.SerializeFrame(frame_ir);
}
void SpdyTestUtil::UpdateWithStreamDestruction(int stream_id) {
for (auto priority_it = priority_to_stream_id_list_.begin();
priority_it != priority_to_stream_id_list_.end(); ++priority_it) {
......
......@@ -513,6 +513,9 @@ class SpdyTestUtil {
const std::unique_ptr<SpdySerializedFrame>& frame,
int stream_id);
// Serialize a SpdyFrameIR with |headerless_spdy_framer_|.
SpdySerializedFrame SerializeFrame(const SpdyFrameIR& frame_ir);
// Called when necessary (when it will affect stream dependency specification
// when setting dependencies based on priorioties) to notify the utility
// class of stream destruction.
......
......@@ -15,6 +15,7 @@
#include "base/compiler_specific.h"
#include "net/spdy/buffered_spdy_framer.h"
#include "net/spdy/spdy_alt_svc_wire_format.h"
#include "net/spdy/spdy_protocol.h"
#include "net/tools/balsa/balsa_headers.h"
#include "net/tools/balsa/balsa_visitor_interface.h"
......@@ -140,6 +141,12 @@ class SpdySM : public BufferedSpdyFramerVisitorInterface, public SMInterface {
SpdyStreamId promised_stream_id,
const SpdyHeaderBlock& headers) override {}
// Called when an ALTSVC frame has been parsed.
void OnAltSvc(SpdyStreamId stream_id,
base::StringPiece origin,
const SpdyAltSvcWireFormat::AlternativeServiceVector&
altsvc_vector) override {}
bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override;
public:
......
......@@ -81,6 +81,10 @@ class SpdyFramerVisitor : public BufferedSpdyFramerVisitorInterface {
MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId, int));
MOCK_METHOD3(OnPushPromise,
void(SpdyStreamId, SpdyStreamId, const SpdyHeaderBlock&));
MOCK_METHOD3(OnAltSvc,
void(SpdyStreamId,
base::StringPiece,
const SpdyAltSvcWireFormat::AlternativeServiceVector&));
MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type));
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment