1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Use of this source code is governed by a BSD-style license that can be
3dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// found in the LICENSE file.
4dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
5dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/tools/flip_server/spdy_interface.h"
6dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
7dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <string>
8dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
9dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/spdy/spdy_framer.h"
10dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/spdy/spdy_protocol.h"
11dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/tools/dump_cache/url_utilities.h"
12dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/tools/flip_server/flip_config.h"
13dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/tools/flip_server/http_interface.h"
14dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/tools/flip_server/spdy_util.h"
15dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::kSpdyStreamMaximumWindowSize;
17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::CONTROL_FLAG_NONE;
18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::DATA_FLAG_COMPRESSED;
19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::DATA_FLAG_FIN;
20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::RST_STREAM;
21dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SETTINGS_MAX_CONCURRENT_STREAMS;
22dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SYN_REPLY;
23dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SYN_STREAM;
24dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SettingsFlagsAndId;
25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdyControlFrame;
26dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdySettingsControlFrame;
27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdyDataFlags;
28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdyDataFrame;
29dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdyRstStreamControlFrame;
30dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdyFrame;
31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdyFramer;
32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdyFramerVisitorInterface;
33dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdyHeaderBlock;
34dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdySetting;
35dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdySettings;
36dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdyStreamId;
37dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdySynReplyControlFrame;
38dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing spdy::SpdySynStreamControlFrame;
39dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
40dc0f95d653279beabeb9817299e2902918ba123eKristian Monsennamespace net {
41dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
42dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static
43dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool SpdySM::disable_data_compression_ = true;
44dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static
45dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstd::string SpdySM::forward_ip_header_;
46dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
47dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenclass SpdyFrameDataFrame : public DataFrame {
48dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen public:
49dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdyFrameDataFrame(SpdyFrame* spdy_frame)
50dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    : frame(spdy_frame) {
51dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    data = spdy_frame->data();
52dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    size = spdy_frame->length() + SpdyFrame::size();
53dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
54dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
55dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  virtual ~SpdyFrameDataFrame() {
56dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delete frame;
57dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
58dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
59dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const SpdyFrame* frame;
60dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen};
61dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
62dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenSpdySM::SpdySM(SMConnection* connection,
63dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen               SMInterface* sm_http_interface,
64dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen               EpollServer* epoll_server,
65dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen               MemoryCache* memory_cache,
66dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen               FlipAcceptor* acceptor)
67dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    : seq_num_(0),
68dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      spdy_framer_(new SpdyFramer),
69dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      valid_spdy_session_(false),
70dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      connection_(connection),
71dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      client_output_list_(connection->output_list()),
72dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      client_output_ordering_(connection),
73dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      next_outgoing_stream_id_(2),
74dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      epoll_server_(epoll_server),
75dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      acceptor_(acceptor),
76dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      memory_cache_(memory_cache),
77dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      close_on_error_(false) {
78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  spdy_framer_->set_visitor(this);
79dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
80dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
81dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenSpdySM::~SpdySM() {
82dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  delete spdy_framer_;
83dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
84dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
85dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::InitSMConnection(SMConnectionPoolInterface* connection_pool,
86dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                              SMInterface* sm_interface,
87dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                              EpollServer* epoll_server,
88dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                              int fd,
89dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                              std::string server_ip,
90dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                              std::string server_port,
91dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                              std::string remote_ip,
92dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                              bool use_ssl) {
93dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(2) << ACCEPTOR_CLIENT_IDENT
94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          << "SpdySM: Initializing server connection.";
95dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  connection_->InitSMConnection(connection_pool, sm_interface,
96dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                epoll_server, fd, server_ip, server_port,
97dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                remote_ip, use_ssl);
98dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
99dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
100dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenSMInterface* SpdySM::NewConnectionInterface() {
101dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SMConnection* server_connection =
102dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SMConnection::NewSMConnection(epoll_server_,
103dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                  NULL,
104dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                  memory_cache_,
105dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                  acceptor_,
106dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                  "http_conn: ");
107dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (server_connection == NULL) {
108dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    LOG(ERROR) << "SpdySM: Could not create server connection";
109dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return NULL;
110dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
111dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Creating new HTTP interface";
112dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SMInterface *sm_http_interface = new HttpSM(server_connection,
113dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                              this,
114dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                              epoll_server_,
115dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                              memory_cache_,
116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                              acceptor_);
117dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return sm_http_interface;
118dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
120dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenSMInterface* SpdySM::FindOrMakeNewSMConnectionInterface(
121dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::string server_ip, std::string server_port) {
122dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SMInterface *sm_http_interface;
123dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  int32 server_idx;
124dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (unused_server_interface_list.empty()) {
125dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    sm_http_interface = NewConnectionInterface();
126dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    server_idx = server_interface_list.size();
127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    server_interface_list.push_back(sm_http_interface);
128dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    VLOG(2) << ACCEPTOR_CLIENT_IDENT
129dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            << "SpdySM: Making new server connection on index: "
130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            << server_idx;
131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else {
132dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    server_idx = unused_server_interface_list.back();
133dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    unused_server_interface_list.pop_back();
134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    sm_http_interface = server_interface_list.at(server_idx);
135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Reusing connection on "
136dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            << "index: " << server_idx;
137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  sm_http_interface->InitSMInterface(this, server_idx);
140dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  sm_http_interface->InitSMConnection(NULL, sm_http_interface,
141dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                      epoll_server_, -1,
142dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                      server_ip, server_port, "", false);
143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
144dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return sm_http_interface;
145dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
147dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenint SpdySM::SpdyHandleNewStream(const SpdyControlFrame* frame,
148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                std::string &http_data,
149dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                bool *is_https_scheme) {
150dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  bool parsed_headers = false;
151dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdyHeaderBlock headers;
152dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const SpdySynStreamControlFrame* syn_stream =
153dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    reinterpret_cast<const SpdySynStreamControlFrame*>(frame);
154dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
155dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  *is_https_scheme = false;
156dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  parsed_headers = spdy_framer_->ParseHeaderBlock(frame, &headers);
157dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnSyn("
158dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          << syn_stream->stream_id() << ")";
159dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: headers parsed?: "
160dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          << (parsed_headers? "yes": "no");
161dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (parsed_headers) {
162dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: # headers: "
163dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            << headers.size();
164dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
165dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdyHeaderBlock::iterator url = headers.find("url");
166dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdyHeaderBlock::iterator method = headers.find("method");
167dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (url == headers.end() || method == headers.end()) {
168dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: didn't find method or url "
169dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            << "or method. Not creating stream";
170dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return 0;
171dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
172dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
173dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdyHeaderBlock::iterator scheme = headers.find("scheme");
174dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (scheme->second.compare("https") == 0) {
175dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    *is_https_scheme = true;
176dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
177dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // url->second here only ever seems to contain just the path. When this
179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // path contains a query string with a http:// in one of its values,
180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // UrlUtilities::GetUrlPath will fail and always return a / breaking
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // the request. GetUrlPath assumes the absolute URL is being passed in.
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string uri;
183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (url->second.compare(0,4,"http") == 0)
184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    uri = UrlUtilities::GetUrlPath(url->second);
185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  else
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    uri = std::string(url->second);
187dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_SPDY_SERVER) {
188dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SpdyHeaderBlock::iterator referer = headers.find("referer");
189dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::string host = UrlUtilities::GetUrlHost(url->second);
190dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Request: " << method->second
191dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            << " " << uri;
192dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::string filename = EncodeURL(uri, host, method->second);
193dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    NewStream(syn_stream->stream_id(),
194dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen              reinterpret_cast<const SpdySynStreamControlFrame*>
195dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                  (frame)->priority(),
196dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen              filename);
197dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else {
198dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SpdyHeaderBlock::iterator version = headers.find("version");
199dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    http_data += method->second + " " + uri + " " + version->second + "\r\n";
200dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Request: " << method->second << " "
201dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            << uri << " " << version->second;
202dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    for (SpdyHeaderBlock::iterator i = headers.begin();
203dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen         i != headers.end(); ++i) {
204dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      http_data += i->first + ": " + i->second + "\r\n";
205dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      VLOG(2) << ACCEPTOR_CLIENT_IDENT << i->first.c_str() << ":"
206dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen              << i->second.c_str();
207dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
208dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (forward_ip_header_.length()) {
209dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // X-Client-Cluster-IP header
210dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      http_data += forward_ip_header_ + ": " +
211dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                    connection_->client_ip() + "\r\n";
212dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
213dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    http_data += "\r\n";
214dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
215dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
216dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(3) << ACCEPTOR_CLIENT_IDENT << "SpdySM: HTTP Request:\n" << http_data;
217dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return 1;
218dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
219dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
220dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::OnControl(const SpdyControlFrame* frame) {
221dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdyHeaderBlock headers;
222dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  bool parsed_headers = false;
223dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  switch (frame->type()) {
224dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    case SYN_STREAM:
225dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      {
226dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      const SpdySynStreamControlFrame* syn_stream =
227dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          reinterpret_cast<const SpdySynStreamControlFrame*>(frame);
228dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
229dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        std::string http_data;
230dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        bool is_https_scheme;
231dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        int ret = SpdyHandleNewStream(frame, http_data, &is_https_scheme);
232dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        if (!ret) {
233dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          LOG(ERROR) << "SpdySM: Could not convert spdy into http.";
234dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          break;
235dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        }
236dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        // We've seen a valid looking SYN_STREAM, consider this to have
237dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        // been a real spdy session.
238dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        valid_spdy_session_ = true;
239dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
240dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
241dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          std::string server_ip;
242dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          std::string server_port;
243dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          if (is_https_scheme) {
244dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            server_ip = acceptor_->https_server_ip_;
245dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            server_port = acceptor_->https_server_port_;
246dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          } else {
247dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            server_ip = acceptor_->http_server_ip_;
248dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            server_port = acceptor_->http_server_port_;
249dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          }
250dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          SMInterface *sm_http_interface =
251dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            FindOrMakeNewSMConnectionInterface(server_ip, server_port);
252dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          stream_to_smif_[syn_stream->stream_id()] = sm_http_interface;
253dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          sm_http_interface->SetStreamID(syn_stream->stream_id());
254dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          sm_http_interface->ProcessWriteInput(http_data.c_str(),
255dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                               http_data.size());
256dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        }
257dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
258dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      break;
259dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
260dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    case SYN_REPLY:
261dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      parsed_headers = spdy_framer_->ParseHeaderBlock(frame, &headers);
262dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnSynReply(" <<
263dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        reinterpret_cast<const SpdySynReplyControlFrame*>(frame)->stream_id()
264dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        << ")";
265dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      break;
266dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    case RST_STREAM:
267dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      {
268dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      const SpdyRstStreamControlFrame* rst_stream =
269dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          reinterpret_cast<const SpdyRstStreamControlFrame*>(frame);
270dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnRst("
271dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                << rst_stream->stream_id() << ")";
272dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        client_output_ordering_.RemoveStreamId(rst_stream ->stream_id());
273dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
274dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      break;
275dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
276dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    default:
277dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      LOG(ERROR) << "SpdySM: Unknown control frame type";
278dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
279dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
280dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
2812c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunbool SpdySM::OnControlFrameHeaderData(spdy::SpdyStreamId stream_id,
2822c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                      const char* header_data,
2832c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                      size_t len) {
2842c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK(false);
2852c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  return false;
2862c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
2872c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
2882c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurunvoid SpdySM::OnDataFrameHeader(const spdy::SpdyDataFrame* frame) {
2892c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  DCHECK(false);
2902c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun}
2912c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
292dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::OnStreamFrameData(SpdyStreamId stream_id,
293dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                               const char* data, size_t len) {
294dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: StreamData(" << stream_id
295dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          << ", [" << len << "])";
296dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  StreamToSmif::iterator it = stream_to_smif_.find(stream_id);
297dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (it == stream_to_smif_.end()) {
298dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    VLOG(2) << "Dropping frame from unknown stream " << stream_id;
299dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (!valid_spdy_session_)
300dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      close_on_error_ = true;
301dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
302dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
303dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
304dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SMInterface* interface = it->second;
305dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY)
306dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    interface->ProcessWriteInput(data, len);
307dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
308dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
309dc0f95d653279beabeb9817299e2902918ba123eKristian Monsensize_t SpdySM::ProcessReadInput(const char* data, size_t len) {
310dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return spdy_framer_->ProcessInput(data, len);
311dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
312dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
313dc0f95d653279beabeb9817299e2902918ba123eKristian Monsensize_t SpdySM::ProcessWriteInput(const char* data, size_t len) {
314dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return 0;
315dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
316dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
317dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool SpdySM::MessageFullyRead() const {
318dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return spdy_framer_->MessageFullyRead();
319dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
320dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
321dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool SpdySM::Error() const {
322dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return close_on_error_ || spdy_framer_->HasError();
323dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
324dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
325dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenconst char* SpdySM::ErrorAsString() const {
326dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(Error());
327dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return SpdyFramer::ErrorCodeToString(spdy_framer_->error_code());
328dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
329dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
330dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::ResetForNewInterface(int32 server_idx) {
331dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Reset for new interface: "
332dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          << "server_idx: " << server_idx;
333dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  unused_server_interface_list.push_back(server_idx);
334dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
335dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
336dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::ResetForNewConnection() {
337dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // seq_num is not cleared, intentionally.
338dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  delete spdy_framer_;
339dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  spdy_framer_ = new SpdyFramer;
340dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  spdy_framer_->set_visitor(this);
341dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  valid_spdy_session_ = false;
342dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  client_output_ordering_.Reset();
343dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  next_outgoing_stream_id_ = 2;
344dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
345dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
346dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Send a settings frame
347dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenint SpdySM::PostAcceptHook() {
348dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdySettings settings;
349dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SettingsFlagsAndId settings_id(SETTINGS_MAX_CONCURRENT_STREAMS);
350dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  settings.push_back(SpdySetting(settings_id, 100));
351dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdySettingsControlFrame* settings_frame =
352dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      spdy_framer_->CreateSettings(settings);
353dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
354dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Sending Settings Frame";
355dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EnqueueDataFrame(new SpdyFrameDataFrame(settings_frame));
356dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return 1;
357dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
358dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
359dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::NewStream(uint32 stream_id,
360dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                       uint32 priority,
361dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                       const std::string& filename) {
362dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  MemCacheIter mci;
363dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  mci.stream_id = stream_id;
364dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  mci.priority = priority;
365dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_SPDY_SERVER) {
366dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (!memory_cache_->AssignFileData(filename, &mci)) {
367dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // error creating new stream.
368dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Sending ErrorNotFound";
369dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      SendErrorNotFound(stream_id);
370dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    } else {
371dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      AddToOutputOrder(mci);
372dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
373dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else {
374dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    AddToOutputOrder(mci);
375dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
376dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
377dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
378dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::AddToOutputOrder(const MemCacheIter& mci) {
379dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  client_output_ordering_.AddToOutputOrder(mci);
380dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
381dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
382dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::SendEOF(uint32 stream_id) {
383dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SendEOFImpl(stream_id);
384dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
385dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
386dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::SendErrorNotFound(uint32 stream_id) {
387dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SendErrorNotFoundImpl(stream_id);
388dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
389dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
390dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::SendOKResponse(uint32 stream_id, std::string* output) {
391dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SendOKResponseImpl(stream_id, output);
392dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
393dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
394dc0f95d653279beabeb9817299e2902918ba123eKristian Monsensize_t SpdySM::SendSynStream(uint32 stream_id, const BalsaHeaders& headers) {
395dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return SendSynStreamImpl(stream_id, headers);
396dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
397dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
398dc0f95d653279beabeb9817299e2902918ba123eKristian Monsensize_t SpdySM::SendSynReply(uint32 stream_id, const BalsaHeaders& headers) {
399dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return SendSynReplyImpl(stream_id, headers);
400dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
401dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
402dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::SendDataFrame(uint32 stream_id, const char* data, int64 len,
403dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                   uint32 flags, bool compress) {
404dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdyDataFlags spdy_flags = static_cast<SpdyDataFlags>(flags);
405dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SendDataFrameImpl(stream_id, data, len, spdy_flags, compress);
406dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
407dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
408dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::SendEOFImpl(uint32 stream_id) {
409dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SendDataFrame(stream_id, NULL, 0, DATA_FLAG_FIN, false);
410dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending EOF: " << stream_id;
411dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  KillStream(stream_id);
412dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  stream_to_smif_.erase(stream_id);
413dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
414dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
415dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::SendErrorNotFoundImpl(uint32 stream_id) {
416dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  BalsaHeaders my_headers;
417dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "404", "Not Found");
418dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SendSynReplyImpl(stream_id, my_headers);
419dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SendDataFrame(stream_id, "wtf?", 4, DATA_FLAG_FIN, false);
420dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  client_output_ordering_.RemoveStreamId(stream_id);
421dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
422dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
423dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::SendOKResponseImpl(uint32 stream_id, std::string* output) {
424dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  BalsaHeaders my_headers;
425dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
426dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SendSynReplyImpl(stream_id, my_headers);
427dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SendDataFrame(
428dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      stream_id, output->c_str(), output->size(), DATA_FLAG_FIN, false);
429dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  client_output_ordering_.RemoveStreamId(stream_id);
430dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
431dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
432dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::KillStream(uint32 stream_id) {
433dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  client_output_ordering_.RemoveStreamId(stream_id);
434dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
435dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
436dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::CopyHeaders(SpdyHeaderBlock& dest, const BalsaHeaders& headers) {
437dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  for (BalsaHeaders::const_header_lines_iterator hi =
438dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen       headers.header_lines_begin();
439dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen       hi != headers.header_lines_end();
440dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen       ++hi) {
441dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // It is illegal to send SPDY headers with empty value or header
442dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // names.
443dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (!hi->first.length() || !hi->second.length())
444dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      continue;
445dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
446dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SpdyHeaderBlock::iterator fhi = dest.find(hi->first.as_string());
447dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (fhi == dest.end()) {
448dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      dest[hi->first.as_string()] = hi->second.as_string();
449dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    } else {
450dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      dest[hi->first.as_string()] = (
451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          std::string(fhi->second.data(), fhi->second.size()) + "\0" +
452dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          std::string(hi->second.data(), hi->second.size()));
453dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
454dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
455dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
456dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // These headers have no value
457dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  dest.erase("X-Associated-Content");  // TODO(mbelshe): case-sensitive
458dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  dest.erase("X-Original-Url");  // TODO(mbelshe): case-sensitive
459dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
460dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
461dc0f95d653279beabeb9817299e2902918ba123eKristian Monsensize_t SpdySM::SendSynStreamImpl(uint32 stream_id,
462dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                 const BalsaHeaders& headers) {
463dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdyHeaderBlock block;
464dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  block["method"] = headers.request_method().as_string();
465dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!headers.HasHeader("status"))
466dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    block["status"] = headers.response_code().as_string();
467dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!headers.HasHeader("version"))
468dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    block["version"] =headers.response_version().as_string();
469dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (headers.HasHeader("X-Original-Url")) {
470dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::string original_url = headers.GetHeader("X-Original-Url").as_string();
471dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    block["path"] = UrlUtilities::GetUrlPath(original_url);
472dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else {
473dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    block["path"] = headers.request_uri().as_string();
474dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
475dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  CopyHeaders(block, headers);
476dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
477dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdySynStreamControlFrame* fsrcf =
478dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    spdy_framer_->CreateSynStream(stream_id, 0, 0, CONTROL_FLAG_NONE, true,
479dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                  &block);
480dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  size_t df_size = fsrcf->length() + SpdyFrame::size();
481dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EnqueueDataFrame(new SpdyFrameDataFrame(fsrcf));
482dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
483dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending SynStreamheader "
484dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          << stream_id;
485dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return df_size;
486dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
487dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
488dc0f95d653279beabeb9817299e2902918ba123eKristian Monsensize_t SpdySM::SendSynReplyImpl(uint32 stream_id, const BalsaHeaders& headers) {
489dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdyHeaderBlock block;
490dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  CopyHeaders(block, headers);
491dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  block["status"] = headers.response_code().as_string() + " " +
492dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                    headers.response_reason_phrase().as_string();
493dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  block["version"] = headers.response_version().as_string();
494dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
495dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SpdySynReplyControlFrame* fsrcf =
496dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    spdy_framer_->CreateSynReply(stream_id, CONTROL_FLAG_NONE, true, &block);
497dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  size_t df_size = fsrcf->length() + SpdyFrame::size();
498dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EnqueueDataFrame(new SpdyFrameDataFrame(fsrcf));
499dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
500dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending SynReplyheader "
501dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          << stream_id;
502dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return df_size;
503dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
504dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
505dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::SendDataFrameImpl(uint32 stream_id, const char* data, int64 len,
506dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                       SpdyDataFlags flags, bool compress) {
507dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Force compression off if disabled via command line.
508dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (disable_data_compression())
509dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    flags = static_cast<SpdyDataFlags>(flags & ~DATA_FLAG_COMPRESSED);
510dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
511dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // TODO(mbelshe):  We can't compress here - before going into the
512dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  //                 priority queue.  Compression needs to be done
513dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  //                 with late binding.
514dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (len == 0) {
515dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SpdyDataFrame* fdf = spdy_framer_->CreateDataFrame(stream_id, data, len,
516dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                                       flags);
517dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    EnqueueDataFrame(new SpdyFrameDataFrame(fdf));
518dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
519dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
520dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
521dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Chop data frames into chunks so that one stream can't monopolize the
522dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // output channel.
523dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  while (len > 0) {
524dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int64 size = std::min(len, static_cast<int64>(kSpdySegmentSize));
525dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SpdyDataFlags chunk_flags = flags;
526dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
527dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // If we chunked this block, and the FIN flag was set, there is more
528dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // data coming.  So, remove the flag.
529dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if ((size < len) && (flags & DATA_FLAG_FIN))
530dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      chunk_flags = static_cast<SpdyDataFlags>(chunk_flags & ~DATA_FLAG_FIN);
531dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
532dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SpdyDataFrame* fdf = spdy_framer_->CreateDataFrame(stream_id, data, size,
533dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                                       chunk_flags);
534dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    EnqueueDataFrame(new SpdyFrameDataFrame(fdf));
535dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
536dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending data frame "
537dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            << stream_id << " [" << size << "] shrunk to " << fdf->length()
538dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            << ", flags=" << flags;
539dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
540dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    data += size;
541dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    len -= size;
542dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
543dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
544dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
545dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::EnqueueDataFrame(DataFrame* df) {
546dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  connection_->EnqueueDataFrame(df);
547dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
548dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
549dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdySM::GetOutput() {
550dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  while (client_output_list_->size() < 2) {
551dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    MemCacheIter* mci = client_output_ordering_.GetIter();
552dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (mci == NULL) {
553dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      VLOG(2) << ACCEPTOR_CLIENT_IDENT
554dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen              << "SpdySM: GetOutput: nothing to output!?";
555dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
556dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
557dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (!mci->transformed_header) {
558dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      mci->transformed_header = true;
559dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: GetOutput transformed "
560dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen              << "header stream_id: [" << mci->stream_id << "]";
561dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if ((mci->stream_id % 2) == 0) {
562dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        // this is a server initiated stream.
563dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        // Ideally, we'd do a 'syn-push' here, instead of a syn-reply.
564dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        BalsaHeaders headers;
565dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        headers.CopyFrom(*(mci->file_data->headers));
566dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        headers.ReplaceOrAppendHeader("status", "200");
567dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        headers.ReplaceOrAppendHeader("version", "http/1.1");
568dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        headers.SetRequestFirstlineFromStringPieces("PUSH",
569dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                                    mci->file_data->filename,
570dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                                    "");
571dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        mci->bytes_sent = SendSynStream(mci->stream_id, headers);
572dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      } else {
573dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        BalsaHeaders headers;
574dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        headers.CopyFrom(*(mci->file_data->headers));
575dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        mci->bytes_sent = SendSynReply(mci->stream_id, headers);
576dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
577dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
578dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
579dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (mci->body_bytes_consumed >= mci->file_data->body.size()) {
580dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: GetOutput "
581dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen              << "remove_stream_id: [" << mci->stream_id << "]";
582dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      SendEOF(mci->stream_id);
583dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
584dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
585dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    size_t num_to_write =
586dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      mci->file_data->body.size() - mci->body_bytes_consumed;
587dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (num_to_write > mci->max_segment_size)
588dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      num_to_write = mci->max_segment_size;
589dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
590dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    bool should_compress = false;
591dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (!mci->file_data->headers->HasHeader("content-encoding")) {
592dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (mci->file_data->headers->HasHeader("content-type")) {
593dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        std::string content_type =
594dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            mci->file_data->headers->GetHeader("content-type").as_string();
595dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        if (content_type.find("image") == content_type.npos)
596dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          should_compress = true;
597dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
598dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
599dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
600dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SendDataFrame(mci->stream_id,
601dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                  mci->file_data->body.data() + mci->body_bytes_consumed,
602dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                  num_to_write, 0, should_compress);
603dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: GetOutput SendDataFrame["
604dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            << mci->stream_id << "]: " << num_to_write;
605dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    mci->body_bytes_consumed += num_to_write;
606dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    mci->bytes_sent += num_to_write;
607dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
608dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
609dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
610dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}  // namespace net
611dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
612