You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ji...@apache.org on 2014/05/01 13:39:32 UTC

svn commit: r1591620 [5/14] - in /httpd/mod_spdy/branches/httpd-2.2.x: ./ base/ base/metrics/ build/ install/ install/common/ install/debian/ install/rpm/ mod_spdy/ mod_spdy/apache/ mod_spdy/apache/filters/ mod_spdy/apache/testing/ mod_spdy/common/ mod...

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,190 @@
+// Copyright 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mod_spdy/apache/slave_connection.h"
+
+#include "apr_strings.h"
+// Temporarily define CORE_PRIVATE so we can see the declarations for
+// ap_create_conn_config (in http_config.h), ap_process_connection (in
+// http_connection.h), and core_module (in http_core.h).
+#define CORE_PRIVATE
+#include "httpd.h"
+#include "http_config.h"
+#include "http_connection.h"
+#include "http_core.h"
+#undef CORE_PRIVATE
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "mod_spdy/apache/config_util.h"
+#include "mod_spdy/apache/id_pool.h"
+#include "mod_spdy/apache/log_message_handler.h"
+#include "mod_spdy/apache/master_connection_context.h"
+#include "mod_spdy/apache/slave_connection_context.h"
+#include "mod_spdy/apache/sockaddr_util.h"
+#include "mod_spdy/apache/ssl_util.h"
+
+namespace mod_spdy {
+
+SlaveConnectionFactory::SlaveConnectionFactory(conn_rec* master_connection) {
+  // If the parent connection is using mod_spdy, we can extract relevant info
+  // on whether we're using it there.
+  if (HasMasterConnectionContext(master_connection)) {
+    MasterConnectionContext* master_context =
+        GetMasterConnectionContext(master_connection);
+    is_using_ssl_ = master_context->is_using_ssl();
+    spdy_version_ = (master_context->is_using_spdy() ?
+                     master_context->spdy_version() :
+                     spdy::SPDY_VERSION_NONE);
+  } else {
+    is_using_ssl_ = IsUsingSslForConnection(master_connection);
+    spdy_version_ = spdy::SPDY_VERSION_NONE;
+  }
+
+  base_server_ = master_connection->base_server;
+  local_addr_ = DeepCopySockAddr(master_connection->local_addr, pool_.pool());
+  local_ip_ = apr_pstrdup(pool_.pool(), master_connection->local_ip);
+  remote_addr_ = DeepCopySockAddr(master_connection->remote_addr, pool_.pool());
+  remote_ip_ = apr_pstrdup(pool_.pool(), master_connection->remote_ip);
+  master_connection_id_ = master_connection->id;
+}
+
+SlaveConnectionFactory::~SlaveConnectionFactory() {
+  // Nothing to do --- pool_ dtor will clean everything up.
+}
+
+SlaveConnection* SlaveConnectionFactory::Create() {
+  return new SlaveConnection(this);
+}
+
+SlaveConnection::SlaveConnection(SlaveConnectionFactory* factory) {
+  apr_pool_t* pool = pool_.pool();
+
+  slave_connection_ =
+      static_cast<conn_rec*>(apr_pcalloc(pool, sizeof(conn_rec)));
+
+  // Initialize what fields of the connection object we can (the rest are
+  // zeroed out by apr_pcalloc).  In particular, we should set at least those
+  // fields set by core_create_conn() in core.c in Apache.
+  // -> id will be set once we are actually running the connection, in
+  // ::Run().
+  slave_connection_->clogging_input_filters = 0;
+  slave_connection_->sbh = NULL;
+  // We will manage this connection and all the associated resources with the
+  // pool we just created.
+  slave_connection_->pool = pool;
+  slave_connection_->bucket_alloc = apr_bucket_alloc_create(pool);
+  slave_connection_->conn_config = ap_create_conn_config(pool);
+  slave_connection_->notes = apr_table_make(pool, 5);
+  // Use the same server settings and client address for the slave connection
+  // as for the master connection --- the factory saved them for us.
+  slave_connection_->base_server = factory->base_server_;
+  slave_connection_->local_addr = factory->local_addr_;
+  slave_connection_->local_ip = factory->local_ip_;
+  slave_connection_->remote_addr = factory->remote_addr_;
+  slave_connection_->remote_ip = factory->remote_ip_;
+
+  // One of the other things we will need in slave_connection is a
+  // connection id. One of the bits of info we will need for it is the
+  // id of the master connection. We save it here, and use it inside ::Run().
+  master_connection_id_ = factory->master_connection_id_;
+
+  // We're supposed to pass a socket object to ap_process_connection below, but
+  // there's no meaningful object to pass for this slave connection, because
+  // we're not really talking to the network.  Our pre-connection hook will
+  // prevent the core filters, which talk to the socket, from being inserted,
+  // so they won't notice anyway; nonetheless, we can't pass NULL to
+  // ap_process_connection because that can cause some other modules to
+  // segfault if they try to muck with the socket's settings.  So, we'll just
+  // allocate our own socket object for those modules to mess with.  This is a
+  // kludge, but it seems to work.
+  slave_socket_ = NULL;
+  apr_status_t status = apr_socket_create(
+      &slave_socket_, APR_INET, SOCK_STREAM, APR_PROTO_TCP, pool);
+  DCHECK(status == APR_SUCCESS);
+  DCHECK(slave_socket_ != NULL);
+
+  // In our context object for this connection, mark this connection as being
+  // a slave.  Our pre-connection and process-connection hooks will notice
+  // this, and act accordingly, when they are called for the slave
+  // connection.
+  SlaveConnectionContext* slave_context =
+      CreateSlaveConnectionContext(slave_connection_);
+
+  // Now store the SSL and SPDY info.
+  slave_context->set_is_using_ssl(factory->is_using_ssl_);
+  slave_context->set_spdy_version(factory->spdy_version_);
+}
+
+SlaveConnection::~SlaveConnection() {
+  // pool_ destructor will take care of everything.
+}
+
+SlaveConnectionContext* SlaveConnection::GetSlaveConnectionContext() {
+  return mod_spdy::GetSlaveConnectionContext(slave_connection_);
+}
+
+void SlaveConnection::Run() {
+  // Pick a globally-unique ID for the slave connection; this must be unique
+  // at any given time.  Normally the MPM is responsible for assigning these,
+  // and each MPM does it differently, so we're cheating in a dangerous way by
+  // trying to assign one here.  However, most MPMs seem to do it in a similar
+  // way: for non-threaded MPMs (e.g. Prefork, WinNT), the ID is just the
+  // child ID, which is a small nonnegative integer (i.e. an array index into
+  // the list of active child processes); for threaded MPMs (e.g. Worker,
+  // Event) the ID is typically ((child_index * thread_limit) + thread_index),
+  // which will again be a positive integer, most likely (but not necessarily,
+  // if thread_limit is set absurdly high) smallish.
+  //
+  // Therefore, the approach that we take is to concatenate the Apache
+  // connection ID for the master connection with a small integer from IDPool
+  // that's unique within the process, and, to avoid conflicts with
+  // MPM-assigned connection IDs, we make our slave connection ID negative.
+  // We only have so many bits to work with
+  // (especially if long is only four bytes instead of eight), so we could
+  // potentially run into trouble if the master connection ID gets very large
+  // or we have too many active tasks simultaneously (i.e. more than 2^16).
+  // So, this approach definitely isn't any kind of robust; but it will
+  // probably usually work. It would, of course, be great to replace this
+  // with a better strategy, if we find one.
+  //
+  // TODO(mdsteele): We could also consider using an #if here to widen the
+  //   masks and the shift distance on systems where sizeof(long)==8.
+  //   We might as well use those extra bits if we have them.
+  COMPILE_ASSERT(sizeof(long) >= 4, long_is_at_least_32_bits);
+  const uint16 in_process_id = IdPool::Instance()->Alloc();
+  const long slave_connectionid =
+      -(((master_connection_id_ & 0x7fffL) << 16) | in_process_id);
+  slave_connection_->id = slave_connectionid;
+
+  // Normally, the core pre-connection hook sets the core module's connection
+  // context to the socket passed to ap_process_connection; certain other
+  // modules, such as mod_reqtimeout, read the core module's connection
+  // context directly so as to read this socket's settings.  However, we
+  // purposely don't allow the core pre-connection hook to run, because we
+  // don't want the core connection filters to be inserted.  So, to avoid
+  // breaking other modules, we take it upon oursevles to set the core
+  // module's connection context to the socket we are passing to
+  // ap_process_connection.  This is ugly, but seems to work.
+  ap_set_module_config(slave_connection_->conn_config,
+                       &core_module, slave_socket_);
+
+  // Invoke Apache's usual processing pipeline.  This will block until the
+  // connection is complete.
+  ap_process_connection(slave_connection_, slave_socket_);
+
+  IdPool::Instance()->Free(in_process_id);
+}
+
+}  // namespace mod_spdy

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection.h
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection.h?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection.h (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection.h Thu May  1 11:39:27 2014
@@ -0,0 +1,112 @@
+/* Copyright 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOD_SPDY_APACHE_SLAVE_CONNECTION_H_
+#define MOD_SPDY_APACHE_SLAVE_CONNECTION_H_
+
+#include "base/basictypes.h"
+#include "mod_spdy/apache/pool_util.h"
+#include "mod_spdy/common/protocol_util.h"
+
+struct apr_sockaddr_t;
+struct apr_socket_t;
+struct conn_rec;
+struct server_rec;
+
+namespace mod_spdy {
+
+class SlaveConnection;
+class SlaveConnectionContext;
+
+// SlaveConnectionFactory + SlaveConnection helps execute requests within
+// the current Apache process, with the request and response both going to
+// some other code and not an external client talking over TCP.
+//
+// SlaveConnectionFactory + SlaveConnection help create a fake Apache conn_rec
+// object and run it. That conn_rec will have a SlaveConnectionContext
+// attached to it, which various hooks in mod_spdy.cc will recognize and handle
+// specially. In particular, they will arrange to have the I/O for connection
+// routed to and from the input & output filters set on the
+// SlaveConnectionContext.
+class SlaveConnectionFactory {
+ public:
+  // Prepares the factory to create slave connections with endpoint, SPDY and
+  // SSL information matching that of the master_connection.
+  //
+  // Does not retain any pointers to data from master_connection, so may be
+  // used after master_connection is destroyed.
+  explicit SlaveConnectionFactory(conn_rec* master_connection);
+
+  ~SlaveConnectionFactory();
+
+  // Creates a slave connection matching the settings in the constructor.
+  // You should attach I/O filters on its GetSlaveConnectionContext() before
+  // calling Run().
+  //
+  // The resulted object lives on the C++ heap, and must be deleted.
+  SlaveConnection* Create();
+
+ private:
+  friend class SlaveConnection;
+
+  // Saved information from master_connection
+  bool is_using_ssl_;
+  spdy::SpdyVersion spdy_version_;
+  server_rec* base_server_;
+  LocalPool pool_;
+  // All of these are in pool_:
+  apr_sockaddr_t* local_addr_;
+  char* local_ip_;
+  apr_sockaddr_t* remote_addr_;
+  char* remote_ip_;
+  long master_connection_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(SlaveConnectionFactory);
+};
+
+class SlaveConnection {
+ public:
+  ~SlaveConnection();
+
+  // Returns the Apache conn_rec object this manages.
+  conn_rec* apache_connection() { return slave_connection_; }
+
+  // Returns the underlying SlaveConnectionContext, which lets you query
+  // information about the connection and hook in I/O filters.
+  //
+  // This is the same as GetSlaveConnectionContext(apache_connection()), and
+  // can thus be accessed via the conn_rec* as well.
+  SlaveConnectionContext* GetSlaveConnectionContext();
+
+  // Executes the requests associated with this connection, taking a request
+  // from the input filter set on the SlaveConnectionContext(), and directing
+  // the response to the output filter. Note that this is a blocking operation.
+  void Run();
+
+ private:
+  SlaveConnection(SlaveConnectionFactory* factory);
+  friend class SlaveConnectionFactory;
+
+  LocalPool pool_;
+  conn_rec* slave_connection_;  // owned by pool_
+  apr_socket_t* slave_socket_;  // owned by pool_
+  long master_connection_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(SlaveConnection);
+};
+
+}  // namespace mod_spdy
+
+#endif  /* MOD_SPDY_APACHE_SLAVE_CONNECTION_H_ */

Propchange: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_api.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_api.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_api.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_api.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,79 @@
+/* Copyright 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mod_spdy/apache/slave_connection_api.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "mod_spdy/apache/slave_connection.h"
+#include "mod_spdy/apache/slave_connection_context.h"
+
+using mod_spdy::SlaveConnection;
+using mod_spdy::SlaveConnectionContext;
+using mod_spdy::SlaveConnectionFactory;
+
+struct spdy_slave_connection_factory {
+  explicit spdy_slave_connection_factory(SlaveConnectionFactory* impl)
+      : impl(impl) {}
+  scoped_ptr<SlaveConnectionFactory> impl;
+};
+
+struct spdy_slave_connection {
+  explicit spdy_slave_connection(SlaveConnection* impl)
+      : impl(impl) {}
+  scoped_ptr<SlaveConnection> impl;
+};
+
+spdy_slave_connection_factory* spdy_create_slave_connection_factory(
+    conn_rec* master_connection) {
+  return new spdy_slave_connection_factory(
+      new SlaveConnectionFactory(master_connection));
+}
+
+void spdy_destroy_slave_connection_factory(
+    spdy_slave_connection_factory* factory) {
+  delete factory;
+}
+
+spdy_slave_connection* spdy_create_slave_connection(
+    spdy_slave_connection_factory* factory,
+    ap_filter_rec_t* input_filter,
+    void* input_filter_ctx,
+    ap_filter_rec_t* output_filter,
+    void* output_filter_ctx) {
+  spdy_slave_connection* wrapper =
+      new spdy_slave_connection(factory->impl->Create());
+
+  SlaveConnectionContext* ctx = wrapper->impl->GetSlaveConnectionContext();
+  ctx->SetInputFilter(input_filter, input_filter_ctx);
+  ctx->SetOutputFilter(output_filter, output_filter_ctx);
+
+  return wrapper;
+}
+
+void spdy_run_slave_connection(spdy_slave_connection* conn) {
+  conn->impl->Run();
+}
+
+void spdy_destroy_slave_connection(spdy_slave_connection* conn) {
+  delete conn;
+}
+
+void ModSpdyExportSlaveConnectionFunctions() {
+  APR_REGISTER_OPTIONAL_FN(spdy_create_slave_connection_factory);
+  APR_REGISTER_OPTIONAL_FN(spdy_destroy_slave_connection_factory);
+  APR_REGISTER_OPTIONAL_FN(spdy_create_slave_connection);
+  APR_REGISTER_OPTIONAL_FN(spdy_run_slave_connection);
+  APR_REGISTER_OPTIONAL_FN(spdy_destroy_slave_connection);
+}

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_api.h
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_api.h?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_api.h (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_api.h Thu May  1 11:39:27 2014
@@ -0,0 +1,79 @@
+/* Copyright 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This is a public header file, to be used by other Apache modules.  So,
+ * identifiers declared here should follow Apache module naming conventions
+ * (specifically, identifiers should be lowercase_with_underscores, and our
+ * identifiers should start with the spdy_ prefix), and this header file must
+ * be valid in old-school C (not just C++). */
+
+#ifndef MOD_SPDY_APACHE_SLAVE_CONNECTION_API_H_
+#define MOD_SPDY_APACHE_SLAVE_CONNECTION_API_H_
+
+#include "httpd.h"
+#include "apr_optional.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ap_filter_rec_t;
+
+struct spdy_slave_connection_factory;
+struct spdy_slave_connection;
+
+/** Creates a factory object that can be used to make in-process pseudo-fetches
+ * with the same origin and target hosts as in master_connection
+ */
+APR_DECLARE_OPTIONAL_FN(
+    struct spdy_slave_connection_factory*,
+    spdy_create_slave_connection_factory, (conn_rec* master_connection));
+
+/** Destroys a factory object. */
+APR_DECLARE_OPTIONAL_FN(
+    void, spdy_destroy_slave_connection_factory,
+        (struct spdy_slave_connection_factory* factory));
+
+/** Asks mod_spdy to help with fetching a request on a slave connection.
+ * The input_filter must produce the request, and output_filter must
+ * handle the response. May return NULL if functionality is not available.
+ * The request will not be run until spdy_run_slave_connection() is invoked.
+ */
+APR_DECLARE_OPTIONAL_FN(
+    struct spdy_slave_connection*,
+    spdy_create_slave_connection, (
+        struct spdy_slave_connection_factory* factory,
+        struct ap_filter_rec_t* input_filter,
+        void* input_filter_ctx,
+        struct ap_filter_rec_t* output_filter,
+        void* output_filter_ctx));
+
+/** Actually performs the fetch on the object. Blocks, perhaps for a significant
+ *  amount of time. */
+APR_DECLARE_OPTIONAL_FN(
+    void, spdy_run_slave_connection, (struct spdy_slave_connection* conn));
+
+/** Cleans up the connection object. Must not be in active use. */
+APR_DECLARE_OPTIONAL_FN(
+    void, spdy_destroy_slave_connection, (struct spdy_slave_connection*));
+
+/* Used by mod_spdy to setup the exports. Not exported itself */
+void ModSpdyExportSlaveConnectionFunctions(void);
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif  /* MOD_SPDY_APACHE_SLAVE_CONNECTION_API_H_ */

Propchange: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_api.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_context.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_context.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_context.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_context.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,46 @@
+// Copyright 2012 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mod_spdy/apache/slave_connection_context.h"
+
+#include "base/logging.h"
+#include "mod_spdy/common/spdy_stream.h"
+
+namespace mod_spdy {
+
+SlaveConnectionContext::SlaveConnectionContext()
+    : using_ssl_(false),
+      spdy_version_(spdy::SPDY_VERSION_NONE),
+      slave_stream_(NULL),
+      output_filter_handle_(NULL),
+      output_filter_context_(NULL),
+      input_filter_handle_(NULL),
+      input_filter_context_(NULL) {
+}
+
+SlaveConnectionContext::~SlaveConnectionContext() {}
+
+void SlaveConnectionContext::SetOutputFilter(
+    ap_filter_rec_t* handle, void* context) {
+  output_filter_handle_ = handle;
+  output_filter_context_ = context;
+}
+
+void SlaveConnectionContext::SetInputFilter(
+    ap_filter_rec_t* handle, void* context) {
+  input_filter_handle_ = handle;
+  input_filter_context_ = context;
+}
+
+}  // namespace mod_spdy

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_context.h
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_context.h?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_context.h (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_context.h Thu May  1 11:39:27 2014
@@ -0,0 +1,99 @@
+// Copyright 2012 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef MOD_SPDY_APACHE_SLAVE_CONNECTION_CONTEXT_H_
+#define MOD_SPDY_APACHE_SLAVE_CONNECTION_CONTEXT_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "mod_spdy/common/protocol_util.h"
+
+struct ap_filter_rec_t;
+
+namespace mod_spdy {
+
+class SpdyStream;
+
+// Context for a 'slave' connection in mod_spdy, used to represent a fetch
+// of a given URL from within Apache (as opposed to outgoing SPDY session to
+// the client, which has a ConnectionContext).
+class SlaveConnectionContext {
+ public:
+  SlaveConnectionContext();
+  ~SlaveConnectionContext();
+
+  // Return true if the connection to the user is over SSL.  This is almost
+  // always true, but may be false if we've been set to use SPDY for non-SSL
+  // connections (for debugging).  Note that for a slave connection, this
+  // refers to whether the master network connection is using SSL.
+  bool is_using_ssl() const { return using_ssl_; }
+  void set_is_using_ssl(bool ssl_on) { using_ssl_ = ssl_on; }
+
+  // Return the SpdyStream object associated with this slave connection.
+  // Note that this may be NULL in case mod_spdy is acting on behalf of
+  // another module. Not owned.
+  SpdyStream* slave_stream() const { return slave_stream_; }
+  void set_slave_stream(SpdyStream* stream) { slave_stream_ = stream; }
+
+  // Return the SPDY version will be using, or SPDY_VERSION_NONE if we're not
+  // using SPDY.
+  spdy::SpdyVersion spdy_version() const { return spdy_version_; }
+  void set_spdy_version(spdy::SpdyVersion version) { spdy_version_ = version; }
+
+  // See SlaveConnection documentation for description of these.
+  void SetOutputFilter(ap_filter_rec_t* handle, void* context);
+  void SetInputFilter(ap_filter_rec_t* handle, void* context);
+
+  ap_filter_rec_t* output_filter_handle() const {
+    return output_filter_handle_;
+  }
+
+  void* output_filter_context() const {
+    return output_filter_context_;
+  }
+
+  ap_filter_rec_t* input_filter_handle() const {
+    return input_filter_handle_;
+  }
+
+  void* input_filter_context() const {
+    return input_filter_context_;
+  }
+
+ private:
+  // These are used to properly inform modules running on slave connections
+  // on whether the connection should be treated as using SPDY and SSL.
+  bool using_ssl_;
+  spdy::SpdyVersion spdy_version_;
+
+  // Used for SPDY push.
+  SpdyStream* slave_stream_;
+
+  // Filters to attach. These are set by clients of SlaveConnection
+  // between creation and Run(), and read by mod_spdy's PreConnection hook,
+  // where they are installed in Apache's filter chains.
+  ap_filter_rec_t* output_filter_handle_;
+  void* output_filter_context_;
+
+  ap_filter_rec_t* input_filter_handle_;
+  void* input_filter_context_;
+
+  DISALLOW_COPY_AND_ASSIGN(SlaveConnectionContext);
+};
+
+}  // namespace mod_spdy
+
+#endif  // MOD_SPDY_APACHE_SLAVE_CONNECTION_CONTEXT_H_

Propchange: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/slave_connection_context.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,55 @@
+// Copyright 2012 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mod_spdy/apache/sockaddr_util.h"
+
+#include <cstddef> // for ptrdiff_t
+#include <cstring>
+
+#include "apr_strings.h"
+
+namespace mod_spdy {
+
+apr_sockaddr_t* DeepCopySockAddr(const apr_sockaddr_t* in, apr_pool_t* pool) {
+  apr_sockaddr_t* out = static_cast<apr_sockaddr_t*>(
+      apr_palloc(pool, sizeof(apr_sockaddr_t)));
+  std::memcpy(out, in, sizeof(apr_sockaddr_t));
+  out->pool = pool;
+
+  if (in->hostname != NULL) {
+    out->hostname = apr_pstrdup(pool, in->hostname);
+  }
+
+  if (in->servname != NULL) {
+    out->servname = apr_pstrdup(pool, in->servname);
+  }
+
+  if (in->ipaddr_ptr != NULL) {
+    // ipaddr_ptr points inside the struct, towards the bits containing
+    // the actual IPv4/IPv6 address (e.g. to ->sa.sin.sin_addr or
+    // ->sa.sin6.sin6_addr). We point to the same offset in 'out' as was used
+    // in 'in'.
+    ptrdiff_t ipaddr_ptr_offset =
+        static_cast<char*>(in->ipaddr_ptr) - reinterpret_cast<const char*>(in);
+    out->ipaddr_ptr = reinterpret_cast<char*>(out) + ipaddr_ptr_offset;
+  }
+
+  if (in->next != NULL) {
+    out->next = DeepCopySockAddr(in->next, pool);
+  }
+
+  return out;
+}
+
+}  // namespace mod_spdy

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util.h
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util.h?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util.h (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util.h Thu May  1 11:39:27 2014
@@ -0,0 +1,29 @@
+// Copyright 2012 Google Inc
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef MOD_SPDY_APACHE_SOCKADDR_UTIL_H_
+#define MOD_SPDY_APACHE_SOCKADDR_UTIL_H_
+
+#include "apr_pools.h"
+#include "apr_network_io.h"
+
+namespace mod_spdy {
+
+// Deep-copies the apr_sockaddr_t 'in', with the result being allocated in the
+// pool 'pool'.
+apr_sockaddr_t* DeepCopySockAddr(const apr_sockaddr_t* in, apr_pool_t* pool);
+
+}  // namespace mod_spdy
+
+#endif  // MOD_SPDY_APACHE_SOCKADDR_UTIL_H_

Propchange: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util_test.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util_test.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util_test.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/sockaddr_util_test.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,104 @@
+// Copyright 2012 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mod_spdy/apache/sockaddr_util.h"
+
+#include "apr_strings.h"
+
+#include "base/basictypes.h"
+#include "mod_spdy/apache/pool_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void VerifySameAddr(apr_sockaddr_t* exp, apr_sockaddr_t* actual) {
+  // apr_sockaddr_equal checks the actual IP (4 or 6) portion of the address,
+  // and nothing else.
+  EXPECT_NE(0, apr_sockaddr_equal(exp, actual));
+
+  // Annoyingly this means we have to touch other fields directly.
+  EXPECT_STREQ(exp->hostname, actual->hostname);
+  EXPECT_STREQ(exp->servname, actual->servname);
+  EXPECT_EQ(exp->port, actual->port);
+  EXPECT_EQ(exp->salen, actual->salen);
+  EXPECT_EQ(exp->ipaddr_len, actual->ipaddr_len);
+  EXPECT_EQ(exp->addr_str_len, actual->addr_str_len);
+
+  // next fields must both be either null or non-null.
+  EXPECT_TRUE((exp->next == NULL) == (actual->next == NULL));
+  if (exp->next != NULL) {
+    VerifySameAddr(exp->next, actual->next);
+  }
+}
+
+TEST(SockAddrUtilTest, CloneIpv4) {
+  mod_spdy::LocalPool local, other;
+
+  apr_sockaddr_t* original = NULL;
+  ASSERT_EQ(APR_SUCCESS,
+            apr_sockaddr_info_get(
+                &original, "127.1.2.3", APR_INET, 80, 0, local.pool()));
+  original->hostname = apr_pstrdup(local.pool(), "localhost");
+  original->servname = apr_pstrdup(local.pool(), "http");
+
+  apr_sockaddr_t* clone = mod_spdy::DeepCopySockAddr(original, other.pool());
+  EXPECT_EQ(other.pool(), clone->pool);
+  VerifySameAddr(original, clone);
+}
+
+TEST(SockAddrUtilTest, CloneIpv6) {
+  mod_spdy::LocalPool local, other;
+
+  // The IPv6 address below was that of example.com on 2012-07-20.
+  apr_sockaddr_t* original = NULL;
+  ASSERT_EQ(APR_SUCCESS,
+            apr_sockaddr_info_get(
+                &original, "2001:500:88:200::10", APR_INET6,
+                443, 0, local.pool()));
+  original->hostname = apr_pstrdup(local.pool(), "example.com");
+  original->servname = apr_pstrdup(local.pool(), "https");
+
+  apr_sockaddr_t* clone = mod_spdy::DeepCopySockAddr(original, other.pool());
+  EXPECT_EQ(other.pool(), clone->pool);
+  VerifySameAddr(original, clone);
+}
+
+TEST(SockAddrUtilTest, Clone2Records) {
+  // Test where ->next links an IpV4 record from IPv6 one.
+  mod_spdy::LocalPool local, other;
+
+  // Both addresses are of example.com as of 2012-07-20.
+  apr_sockaddr_t* original = NULL;
+  ASSERT_EQ(APR_SUCCESS,
+            apr_sockaddr_info_get(
+                &original, "2001:500:88:200::10", APR_INET6,
+                443, 0, local.pool()));
+  original->hostname = apr_pstrdup(local.pool(), "example.com");
+  original->servname = apr_pstrdup(local.pool(), "https");
+
+  apr_sockaddr_t* original4 = NULL;
+  ASSERT_EQ(APR_SUCCESS,
+            apr_sockaddr_info_get(
+                &original4, "192.0.43.10", APR_INET,
+                443, 0, local.pool()));
+  original4->hostname = apr_pstrdup(local.pool(), "example.com");
+  original4->servname = apr_pstrdup(local.pool(), "https");
+  original->next = original4;
+
+  apr_sockaddr_t* clone = mod_spdy::DeepCopySockAddr(original, other.pool());
+  EXPECT_EQ(other.pool(), clone->pool);
+  VerifySameAddr(original, clone);
+}
+
+}  // namespace

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/ssl_util.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/ssl_util.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/ssl_util.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/ssl_util.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,79 @@
+// Copyright 2012 Google Inc
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mod_spdy/apache/ssl_util.h"
+
+#include "apr_optional.h"
+#include "apr_optional_hooks.h"
+
+#include "base/logging.h"
+
+// This file contains some utility functions for communicating to mod_ssl.
+
+// Declaring mod_ssl's optional hooks here (so that we don't need mod_ssl.h).
+APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec*));
+APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec*));
+
+namespace mod_spdy {
+
+namespace {
+
+// These global variables store pointers to "optional functions" defined in
+// mod_ssl.  See TAMB 10.1.2 for more about optional functions.  These are
+// assigned just once, at start-up, so concurrency is not an issue.
+int (*gDisableSslForConnection)(conn_rec*) = NULL;
+int (*gIsUsingSslForConnection)(conn_rec*) = NULL;
+
+}  // namespace
+
+void RetrieveModSslFunctions() {
+  gDisableSslForConnection = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable);
+  gIsUsingSslForConnection = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
+  // If mod_ssl isn't installed, we'll get back NULL for these functions.  Our
+  // other hook functions will fail gracefully (i.e. do nothing) if these
+  // functions are NULL, but if the user installed mod_spdy without mod_ssl and
+  // expected it to do anything, we should warn them otherwise.
+  //
+  // Note: Alternatively, it may be that there's no mod_ssl, but mod_spdy has
+  // been configured to assume SPDY for non-SSL connections, in which case this
+  // warning is untrue.  But there's no easy way to check the server config
+  // from here, and normal users should never use that config option anyway
+  // (it's for debugging), so I don't think the spurious warning is a big deal.
+  if (gDisableSslForConnection == NULL &&
+      gIsUsingSslForConnection == NULL) {
+    LOG(WARNING) << "It seems that mod_spdy is installed but mod_ssl isn't.  "
+                 << "Without SSL, the server cannot ever use SPDY.";
+  }
+  // Whether or not mod_ssl is installed, either both functions should be
+  // non-NULL or both functions should be NULL.  Otherwise, something is wrong
+  // (like, maybe some kind of bizarre mutant mod_ssl is installed) and
+  // mod_spdy probably won't work correctly.
+  if ((gDisableSslForConnection == NULL) ^
+      (gIsUsingSslForConnection == NULL)) {
+    LOG(DFATAL) << "Some, but not all, of mod_ssl's optional functions are "
+                << "available.  What's going on?";
+  }
+}
+
+bool DisableSslForConnection(conn_rec* connection) {
+  return (gDisableSslForConnection != NULL) &&
+         (gDisableSslForConnection(connection) != 0);
+}
+
+bool IsUsingSslForConnection(conn_rec* connection) {
+  return (gIsUsingSslForConnection != NULL) &&
+         (gIsUsingSslForConnection(connection) != 0);
+}
+
+}  // namespace mod_spdy

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/ssl_util.h
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/ssl_util.h?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/ssl_util.h (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/ssl_util.h Thu May  1 11:39:27 2014
@@ -0,0 +1,43 @@
+// Copyright 2012 Google Inc
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef MOD_SPDY_APACHE_SSL_UTIL_H_
+#define MOD_SPDY_APACHE_SSL_UTIL_H_
+
+// This file contains some utility functions for communicating to mod_ssl.
+
+struct conn_rec;
+
+namespace mod_spdy {
+
+// This must be called from optional_fn_retrieve hook at startup before
+// using any of the methods below.
+void RetrieveModSslFunctions();
+
+// Disables SSL on a connection. Returns true if successful, false if failed
+// for some reason (such as the optional function not being available, or
+// mod_ssl indicating a problem).
+bool DisableSslForConnection(conn_rec* connection);
+
+// Returns true if the given connection is using SSL. Note that this answers
+// whether the connection is really using SSL rather than whether we should tell
+// others that it is. This distinction matters for slave connection belonging to
+// an SSL master --- we're not really using SSL for them (so this method
+// will return false), but will claim we are (since they'll be encrypted once
+// going to other outside world).
+bool IsUsingSslForConnection(conn_rec* connection);
+
+}  // namespace mod_spdy
+
+#endif  // MOD_SPDY_APACHE_SSL_UTIL_H_

Propchange: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/ssl_util.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/testing/dummy_util_filter.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/testing/dummy_util_filter.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/testing/dummy_util_filter.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/testing/dummy_util_filter.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,32 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "httpd.h"
+#include "apr_buckets.h"
+#include "util_filter.h"
+
+// For unit tests, we don't link in Apache's util_filter.c, which defines the
+// below functions.  To make our lives easier, we define dummy versions of them
+// here that simply report success.
+
+extern "C" {
+
+AP_DECLARE(apr_status_t) ap_pass_brigade(
+    ap_filter_t* filter, apr_bucket_brigade* bucket) {
+  return APR_SUCCESS;
+}
+
+AP_DECLARE(void) ap_remove_output_filter(ap_filter_t* filter) {}
+
+}  // extern "C"

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/testing/spdy_apache_test_main.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/testing/spdy_apache_test_main.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/testing/spdy_apache_test_main.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/apache/testing/spdy_apache_test_main.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,46 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <iostream>
+
+#include "apr_general.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Class to ensure that APR gets initialized and torn down.
+class AprInitializer {
+ public:
+  AprInitializer() {
+    const apr_status_t status = apr_initialize();
+    CHECK(status == APR_SUCCESS) << "APR initialization failed.";
+  }
+  ~AprInitializer() {
+    apr_terminate();
+  }
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AprInitializer);
+};
+
+}  // namespace
+
+int main(int argc, char **argv) {
+  std::cout << "Running main() from spdy_apache_test_main.cc\n";
+  testing::InitGoogleTest(&argc, argv);
+  AprInitializer apr_initializer;
+  return RUN_ALL_TESTS();
+}

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/VERSION
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/VERSION?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/VERSION (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/VERSION Thu May  1 11:39:27 2014
@@ -0,0 +1,4 @@
+MAJOR=0
+MINOR=1
+BUILD=0
+PATCH=0

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/executor.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/executor.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/executor.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/executor.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,23 @@
+// Copyright 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mod_spdy/common/executor.h"
+
+namespace mod_spdy {
+
+Executor::Executor() {}
+
+Executor::~Executor() {}
+
+}  // namespace mod_spdy

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/executor.h
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/executor.h?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/executor.h (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/executor.h Thu May  1 11:39:27 2014
@@ -0,0 +1,53 @@
+// Copyright 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef MOD_SPDY_COMMON_EXECUTOR_H_
+#define MOD_SPDY_COMMON_EXECUTOR_H_
+
+#include "base/basictypes.h"
+#include "net/spdy/spdy_protocol.h"
+
+namespace net_instaweb { class Function; }
+
+namespace mod_spdy {
+
+// An interface for a service that can execute tasks.  A thread pool (using
+// net_instaweb::QueuedWorkerPool or an apr_thread_pool_t) would be one obvious
+// implementation.  In the future we may want to adjust this interface for use
+// in an event-driven environment (e.g. Nginx).
+class Executor {
+ public:
+  Executor();
+  virtual ~Executor();
+
+  // Add a new task to be run; the executor takes ownership of the task.  The
+  // priority argument hints at how important this task is to get done, but the
+  // executor is free to ignore it.  If Stop has already been called, the
+  // executor may immediately cancel the task rather than running it.
+  virtual void AddTask(net_instaweb::Function* task,
+                       net::SpdyPriority priority) = 0;
+
+  // Stop the executor.  Cancel all tasks that were pushed onto this executor
+  // but that have not yet begun to run.  Tasks that were already running will
+  // continue to run, and this function must block until they have completed.
+  // It must be safe to call this method more than once.
+  virtual void Stop() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Executor);
+};
+
+}  // namespace mod_spdy
+
+#endif  // MOD_SPDY_COMMON_EXECUTOR_H_

Propchange: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/executor.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_request_visitor_interface.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_request_visitor_interface.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_request_visitor_interface.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_request_visitor_interface.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,22 @@
+// Copyright 2010 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mod_spdy/common/http_request_visitor_interface.h"
+
+namespace mod_spdy {
+
+HttpRequestVisitorInterface::HttpRequestVisitorInterface() {}
+HttpRequestVisitorInterface::~HttpRequestVisitorInterface() {}
+
+}  // namespace mod_spdy

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_request_visitor_interface.h
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_request_visitor_interface.h?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_request_visitor_interface.h (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_request_visitor_interface.h Thu May  1 11:39:27 2014
@@ -0,0 +1,86 @@
+// Copyright 2010 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef MOD_SPDY_COMMON_HTTP_REQUEST_VISITOR_INTERFACE_H_
+#define MOD_SPDY_COMMON_HTTP_REQUEST_VISITOR_INTERFACE_H_
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+
+namespace mod_spdy {
+
+// Interface that gets called back as an HTTP stream is visited.
+class HttpRequestVisitorInterface {
+ public:
+  HttpRequestVisitorInterface();
+  virtual ~HttpRequestVisitorInterface();
+
+  // Called when an HTTP request line is visited. Indicates that a new HTTP
+  // request is being visited.
+  virtual void OnRequestLine(const base::StringPiece& method,
+                             const base::StringPiece& path,
+                             const base::StringPiece& version) = 0;
+
+  // Called zero or more times, once for each leading (i.e. normal, not
+  // trailing) HTTP header.  This is called after OnRequestLine but before
+  // OnLeadingHeadersComplete.
+  virtual void OnLeadingHeader(const base::StringPiece& key,
+                               const base::StringPiece& value) = 0;
+
+  // Called after the leading HTTP headers have been visited.  This will be
+  // called exactly once when the leading headers are done (even if there were
+  // no leading headers).
+  virtual void OnLeadingHeadersComplete() = 0;
+
+  // Called zero or more times, after OnLeadingHeadersComplete.  This method is
+  // mutually exclusive with OnDataChunk and OnDataChunksComplete; either data
+  // will be raw or chunked, but not both.  If raw data is used, there cannot
+  // be trailing headers; the raw data section will be terminated by the call
+  // to OnComplete.
+  virtual void OnRawData(const base::StringPiece& data) = 0;
+
+  // Called zero or more times, after OnLeadingHeadersComplete, once for each
+  // "chunk" of the HTTP body.  This method is mutually exclusive with
+  // OnRawData; either data will be raw or chunked, but not both.
+  virtual void OnDataChunk(const base::StringPiece& data) = 0;
+
+  // Called when there will be no more data chunks.  There may still be
+  // trailing headers, however.  This method is mutually exclusive with
+  // OnRawData; either data will be raw or chunked, but not both.
+  virtual void OnDataChunksComplete() = 0;
+
+  // Called zero or more times, once for each trailing header.  This is called
+  // after OnDataChunksComplete but before OnTrailingHeadersComplete.  It
+  // cannot be called if OnRawData was used.
+  virtual void OnTrailingHeader(const base::StringPiece& key,
+                                const base::StringPiece& value) = 0;
+
+  // Called after all the trailing HTTP headers have been visited.  If there
+  // were any trailing headers, this will definitely be called; if there were
+  // no trailing headers, it is optional.
+  virtual void OnTrailingHeadersComplete() = 0;
+
+  // Called once when the HTTP request is totally done.  This is called
+  // immediately after one of OnLeadingHeadersComplete, OnRawData,
+  // OnDataChunksComplete, or OnTrailingHeadersComplete.  After this, no more
+  // methods will be called.
+  virtual void OnComplete() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HttpRequestVisitorInterface);
+};
+
+}  // namespace mod_spdy
+
+#endif  // MOD_SPDY_COMMON_HTTP_REQUEST_VISITOR_INTERFACE_H_

Propchange: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_request_visitor_interface.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,367 @@
+// Copyright 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mod_spdy/common/http_response_parser.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "mod_spdy/common/http_response_visitor_interface.h"
+#include "mod_spdy/common/protocol_util.h"
+
+namespace {
+
+// If the given position in the string is npos, then return the position of the
+// end of the string; otherwise, return the given position unchanged.
+size_t NposToEnd(const base::StringPiece& str, size_t pos) {
+  return pos == base::StringPiece::npos ? str.size() : pos;
+}
+
+}  // namespace
+
+namespace mod_spdy {
+
+HttpResponseParser::HttpResponseParser(HttpResponseVisitorInterface* visitor)
+    : visitor_(visitor),
+      state_(STATUS_LINE),
+      body_type_(NO_BODY),
+      remaining_bytes_(0) {}
+
+HttpResponseParser::~HttpResponseParser() {}
+
+bool HttpResponseParser::ProcessInput(const base::StringPiece& input_data) {
+  // Keep track of the slice of data we are currently looking at.  We will
+  // modify this variable as we go.
+  base::StringPiece data = input_data;
+
+  size_t last_length = data.size() + 1;
+  while (!data.empty()) {
+    // Safety check to avoid infinite loops in case our code is buggy; the
+    // slice of data we are looking at should get strictly smaller on every
+    // iteration of this loop.
+    if (data.size() >= last_length) {
+      LOG(DFATAL) << "Potential infinite loop.";
+      return false;
+    }
+    last_length = data.size();
+
+    // Process the data based on our current parser state.  Most of these
+    // methods receive a pointer to `data` and will mutate it as they consume
+    // bytes.  We continue looping until the whole input_data is consumed.
+    switch (state_) {
+      case STATUS_LINE:
+        if (!ProcessStatusLine(&data)) {
+          return false;
+        }
+        break;
+      case LEADING_HEADERS_CHECK_NEXT_LINE:
+        if (!CheckStartOfHeaderLine(data)) {
+          return false;
+        }
+        // fallthrough
+      case LEADING_HEADERS:
+        if (!ProcessLeadingHeaders(&data)) {
+          return false;
+        }
+        break;
+      case CHUNK_START:
+        if (!ProcessChunkStart(&data)) {
+          return false;
+        }
+        break;
+      case BODY_DATA:
+        if (!ProcessBodyData(&data)) {
+          return false;
+        }
+        break;
+      case CHUNK_ENDING:
+        if (!ProcessChunkEnding(&data)) {
+          return false;
+        }
+        break;
+      case COMPLETE:
+        DCHECK(buffer_.empty());
+        return true;
+      default:
+        LOG(DFATAL) << "Invalid parser state: " << state_;
+        return false;
+    }
+  }
+  return true;
+}
+
+bool HttpResponseParser::ProcessStatusLine(base::StringPiece* data) {
+  DCHECK(state_ == STATUS_LINE);
+  const size_t linebreak = data->find("\r\n");
+
+  // If we haven't reached the end of the line yet, buffer the data and quit.
+  if (linebreak == base::StringPiece::npos) {
+    data->AppendToString(&buffer_);
+    *data = base::StringPiece();
+    return true;
+  }
+
+  // Combine the data up to the linebreak with what we've buffered, and parse
+  // the status line out of it.
+  data->substr(0, linebreak).AppendToString(&buffer_);
+  if (!ParseStatusLine(buffer_)) {
+    return false;
+  }
+  buffer_.clear();
+
+  // Chop off the linebreak and all data before it, and move on to parsing the
+  // leading headers.
+  *data = data->substr(linebreak + 2);
+  state_ = LEADING_HEADERS;
+  return true;
+}
+
+bool HttpResponseParser::CheckStartOfHeaderLine(const base::StringPiece& data){
+  // This state is for when we have a complete header line buffered, and we
+  // need to check the next line to see if it starts with leading whitespace.
+  DCHECK(state_ == LEADING_HEADERS_CHECK_NEXT_LINE);
+  DCHECK(!buffer_.empty());
+  DCHECK(!data.empty());
+
+  // If this line _doesn't_ start with whitespace, then the buffered line is a
+  // complete header line, so we should parse it and clear the buffer.
+  // Otherwise, this next line is a continuation of the header, so we need to
+  // buffer more data.
+  const char first = data[0];
+  if (first != ' ' && first != '\t') {
+    if (!ParseLeadingHeader(buffer_)) {
+      return false;
+    }
+    buffer_.clear();
+  }
+
+  // Either way, we're ready to continuing parsing headers.
+  state_ = LEADING_HEADERS;
+  return true;
+}
+
+bool HttpResponseParser::ProcessLeadingHeaders(base::StringPiece* data) {
+  DCHECK(state_ == LEADING_HEADERS);
+  const size_t linebreak = data->find("\r\n");
+
+  // If we haven't reached the end of the line yet, buffer the data and quit.
+  if (linebreak == base::StringPiece::npos) {
+    data->AppendToString(&buffer_);
+    *data = base::StringPiece();
+    return true;
+  }
+
+  // If we're not in the middle of a header line (buffer is empty) and the
+  // linebreak comes at the very beginning, this must be the blank line that
+  // signals the end of the leading headers.  Skip the linebreak, switch states
+  // depending on what headers we saw (Is there body data?  Is it chunked?),
+  // and return.
+  if (linebreak == 0 && buffer_.empty()) {
+    switch (body_type_) {
+      case CHUNKED_BODY:
+        state_ = CHUNK_START;
+        break;
+      case UNCHUNKED_BODY:
+        state_ = BODY_DATA;
+        break;
+      case NO_BODY:
+        state_ = COMPLETE;
+        break;
+      default:
+        LOG(DFATAL) << "Invalid body type: " << body_type_;
+        return false;
+    }
+    visitor_->OnLeadingHeadersComplete(state_ == COMPLETE);
+    *data = data->substr(linebreak + 2);
+    return true;
+  }
+
+  // We've reached the end of the line, but we need to check the next line to
+  // see if it's a continuation of this header.  Buffer up to the linebreak,
+  // skip the linebreak itself, and set our state to check the next line.
+  data->substr(0, linebreak).AppendToString(&buffer_);
+  *data = data->substr(linebreak + 2);
+  state_ = LEADING_HEADERS_CHECK_NEXT_LINE;
+  return true;
+}
+
+bool HttpResponseParser::ProcessChunkStart(base::StringPiece* data) {
+  DCHECK(state_ == CHUNK_START);
+  const size_t linebreak = data->find("\r\n");
+
+  // If we haven't reached the end of the line yet, buffer the data and quit.
+  if (linebreak == base::StringPiece::npos) {
+    data->AppendToString(&buffer_);
+    *data = base::StringPiece();
+    return true;
+  }
+
+  // Combine the data up to the linebreak with what we've buffered, and parse
+  // the chunk length out of it.
+  data->substr(0, linebreak).AppendToString(&buffer_);
+  if (!ParseChunkStart(buffer_)) {
+    return false;
+  }
+  buffer_.clear();
+
+  // Skip the linebreak.
+  *data = data->substr(linebreak + 2);
+
+  // ParseChunkStart will put the size of the chunk into remaining_bytes_.  If
+  // the chunk size is zero, that means we've reached the end of the body data.
+  // Otherwise, we now need to read the data in this chunk.
+  if (remaining_bytes_ == 0) {
+    state_ = COMPLETE;
+    visitor_->OnData(base::StringPiece(), true);
+  } else {
+    state_ = BODY_DATA;
+  }
+  return true;
+}
+
+bool HttpResponseParser::ProcessBodyData(base::StringPiece* data) {
+  DCHECK(state_ == BODY_DATA);
+
+  // We never buffer anything when reading the body data.  This minimizes how
+  // much string copying we need to do for most responses.
+  DCHECK(buffer_.empty());
+
+  // If the available data is less that what remains of this chunk (if the data
+  // is chunked) or of the whole body (if there was instead an explicit
+  // content-length), then read in all the data we have and subtract from
+  // remaining_bytes_.
+  if (data->size() < remaining_bytes_) {
+    visitor_->OnData(*data, false);
+    remaining_bytes_ -= data->size();
+    *data = base::StringPiece();
+  }
+  // Otherwise, we have enough data here to fulfill remaining_bytes_, so read
+  // in that much data, and then switch states depending on whether we're using
+  // chunking or not.
+  else {
+    if (body_type_ == CHUNKED_BODY) {
+      state_ = CHUNK_ENDING;
+    } else {
+      DCHECK(body_type_ == UNCHUNKED_BODY);
+      state_ = COMPLETE;
+    }
+    visitor_->OnData(data->substr(0, remaining_bytes_), state_ == COMPLETE);
+    *data = data->substr(remaining_bytes_);
+    remaining_bytes_ = 0;
+  }
+  return true;
+}
+
+bool HttpResponseParser::ProcessChunkEnding(base::StringPiece* data) {
+  DCHECK(state_ == CHUNK_ENDING);
+  // For whatever reason, HTTP requires each chunk to end with a CRLF.  So,
+  // make sure it's there, and then skip it, before moving on to read the next
+  // chunk.
+  if (!data->starts_with("\r\n")) {
+    VLOG(1) << "Expected CRLF at end of chunk.";
+    return false;
+  }
+  *data = data->substr(2);
+  state_ = CHUNK_START;
+  return true;
+}
+
+bool HttpResponseParser::ParseStatusLine(const base::StringPiece& text) {
+  // An HTTP status line should look like:
+  // <HTTP version> <single space> <status code> <single space> <status phrase>
+  // For example, "HTTP/1.1 301 Moved permenantly".
+  // We'll be a little more lenient just in case, and allow multiple spaces
+  // between each part, and allow the phrase to be omitted.
+  const size_t first_space = text.find(' ');
+  if (first_space == base::StringPiece::npos) {
+    VLOG(1) << "Bad status line: " << text;
+    return false;
+  }
+  const size_t start_of_code = text.find_first_not_of(' ', first_space);
+  if (start_of_code == base::StringPiece::npos) {
+    VLOG(1) << "Bad status line: " << text;
+    return false;
+  }
+  const size_t second_space = NposToEnd(text, text.find(' ', start_of_code));
+  const size_t start_of_phrase =
+      NposToEnd(text, text.find_first_not_of(' ', second_space));
+
+  visitor_->OnStatusLine(
+      text.substr(0, first_space),
+      text.substr(start_of_code, second_space - start_of_code),
+      text.substr(start_of_phrase));
+  return true;
+}
+
+bool HttpResponseParser::ParseLeadingHeader(const base::StringPiece& text) {
+  // Even for multiline headers, we strip out the CRLFs, so there shouldn't be
+  // any left in the text that we're parsing.
+  DCHECK(text.find("\r\n") == base::StringPiece::npos);
+
+  // Find the colon separating the key from the value, and skip any leading
+  // whitespace between the colon and the value.
+  const size_t colon = text.find(':');
+  if (colon == base::StringPiece::npos) {
+    VLOG(1) << "Bad header line: " << text;
+    return false;
+  }
+  const size_t value_start =
+      NposToEnd(text, text.find_first_not_of(" \t", colon + 1));
+
+  const base::StringPiece key = text.substr(0, colon);
+  const base::StringPiece value = text.substr(value_start);
+
+  // We need to check the Content-Length and Transfer-Encoding headers to know
+  // if we're using chunking, and if not, how long the body is.
+  if (LowerCaseEqualsASCII(key.begin(), key.end(), http::kTransferEncoding)) {
+    if (value == http::kChunked) {
+      body_type_ = CHUNKED_BODY;
+    }
+  } else if (body_type_ != CHUNKED_BODY &&
+             LowerCaseEqualsASCII(key.begin(), key.end(),
+                                  http::kContentLength)) {
+    uint64 uint_value = 0u;
+    if (base::StringToUint64(value, &uint_value) && uint_value > 0u) {
+      remaining_bytes_ = uint_value;
+      body_type_ = UNCHUNKED_BODY;
+    } else {
+      VLOG(1) << "Bad content-length: " << value;
+    }
+  }
+
+  visitor_->OnLeadingHeader(key, value);
+  return true;
+}
+
+bool HttpResponseParser::ParseChunkStart(const base::StringPiece& text) {
+  // The line at the start of each chunk consists of the chunk length in
+  // hexadecimal, potentially followed by chunk-extension metadata that we
+  // don't care about anyway.  So just parse out the hex number and ignore the
+  // rest.
+  const size_t length =
+      NposToEnd(text, text.find_first_not_of("0123456789abcdefABCDEF"));
+  int int_value = 0;
+  if (!base::HexStringToInt(text.substr(0, length), &int_value) ||
+      int_value < 0) {
+    VLOG(1) << "Bad chunk line: " << text;
+    return false;
+  }
+  remaining_bytes_ = static_cast<size_t>(int_value);
+  return true;
+}
+
+}  // namespace mod_spdy

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser.h
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser.h?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser.h (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser.h Thu May  1 11:39:27 2014
@@ -0,0 +1,89 @@
+// Copyright 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef MOD_SPDY_COMMON_HTTP_RESPONSE_PARSER_H_
+#define MOD_SPDY_COMMON_HTTP_RESPONSE_PARSER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+
+namespace mod_spdy {
+
+class HttpResponseVisitorInterface;
+
+// Parses incoming HTTP response data.  Data is fed in piece by piece with the
+// ProcessInput method, and appropriate methods are called on the visitor.
+// There is no need to indicate the end of the input, as this is inferred from
+// the Content-Length or Transfer-Encoding headers.  If the response uses
+// chunked encoding, the parser will de-chunk it.  Note that all data after the
+// end of the response body, including trailing headers, will be completely
+// ignored.
+class HttpResponseParser {
+ public:
+  explicit HttpResponseParser(HttpResponseVisitorInterface* visitor);
+  ~HttpResponseParser();
+
+  // Return true on success, false on failure.
+  bool ProcessInput(const base::StringPiece& input_data);
+  bool ProcessInput(const char* data, size_t size) {
+    return ProcessInput(base::StringPiece(data, size));
+  }
+
+  // For unit testing only: Get the remaining number of bytes expected (in the
+  // whole response, if we used Content-Length, or just in the current chunk,
+  // if we used Transfer-Encoding: chunked).
+  uint64 GetRemainingBytesForTest() const { return remaining_bytes_; }
+
+ private:
+  enum ParserState {
+    STATUS_LINE,
+    LEADING_HEADERS,
+    LEADING_HEADERS_CHECK_NEXT_LINE,
+    CHUNK_START,
+    BODY_DATA,
+    CHUNK_ENDING,
+    COMPLETE
+  };
+
+  enum BodyType {
+    NO_BODY,
+    UNCHUNKED_BODY,
+    CHUNKED_BODY
+  };
+
+  bool ProcessStatusLine(base::StringPiece* data);
+  bool CheckStartOfHeaderLine(const base::StringPiece& data);
+  bool ProcessLeadingHeaders(base::StringPiece* data);
+  bool ProcessChunkStart(base::StringPiece* data);
+  bool ProcessBodyData(base::StringPiece* data);
+  bool ProcessChunkEnding(base::StringPiece* data);
+
+  bool ParseStatusLine(const base::StringPiece& text);
+  bool ParseLeadingHeader(const base::StringPiece& text);
+  bool ParseChunkStart(const base::StringPiece& text);
+
+  HttpResponseVisitorInterface* const visitor_;
+  ParserState state_;
+  BodyType body_type_;
+  uint64 remaining_bytes_;
+  std::string buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(HttpResponseParser);
+};
+
+}  // namespace mod_spdy
+
+#endif  // MOD_SPDY_COMMON_HTTP_RESPONSE_PARSER_H_

Propchange: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser_test.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser_test.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser_test.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_parser_test.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,273 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mod_spdy/common/http_response_parser.h"
+
+#include "base/strings/string_piece.h"
+#include "mod_spdy/common/http_response_visitor_interface.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using mod_spdy::HttpResponseParser;
+using testing::Eq;
+using testing::InSequence;
+
+namespace {
+
+class MockHttpResponseVisitor: public mod_spdy::HttpResponseVisitorInterface {
+ public:
+  MOCK_METHOD3(OnStatusLine, void(const base::StringPiece&,
+                                  const base::StringPiece&,
+                                  const base::StringPiece&));
+  MOCK_METHOD2(OnLeadingHeader, void(const base::StringPiece&,
+                                     const base::StringPiece&));
+  MOCK_METHOD1(OnLeadingHeadersComplete, void(bool));
+  MOCK_METHOD2(OnData, void(const base::StringPiece&, bool));
+};
+
+class HttpResponseParserTest : public testing::Test {
+ public:
+  HttpResponseParserTest() : parser_(&visitor_) {}
+
+ protected:
+  MockHttpResponseVisitor visitor_;
+  HttpResponseParser parser_;
+};
+
+TEST_F(HttpResponseParserTest, SimpleWithContentLength) {
+  InSequence seq;
+  EXPECT_CALL(visitor_, OnStatusLine(Eq("HTTP/1.1"), Eq("200"), Eq("OK")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(Eq("Content-Length"), Eq("14")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(Eq("Content-Type"), Eq("text/plain")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(Eq("X-Whatever"), Eq("foobar")));
+  EXPECT_CALL(visitor_, OnLeadingHeadersComplete(Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq("Hello, world!\n"), Eq(true)));
+
+  ASSERT_TRUE(parser_.ProcessInput(
+      "HTTP/1.1 200 OK\r\n"
+      "Content-Length: 14\r\n"
+      "Content-Type:      text/plain\r\n"
+      "X-Whatever:foobar\r\n"
+      "\r\n"
+      "Hello, world!\n"
+      "\r\n"));
+}
+
+TEST_F(HttpResponseParserTest, SimpleWithChunkedData) {
+  InSequence seq;
+  EXPECT_CALL(visitor_, OnStatusLine(Eq("HTTP/1.1"), Eq("200"), Eq("OK")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(
+      Eq("Transfer-Encoding"), Eq("chunked")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(Eq("Content-Type"), Eq("text/plain")));
+  EXPECT_CALL(visitor_, OnLeadingHeadersComplete(Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq("Hello, world!\n"), Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq("It sure is good to see you today."),
+                               Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq(""), Eq(true)));
+
+  ASSERT_TRUE(parser_.ProcessInput(
+      "HTTP/1.1 200 OK\r\n"
+      "Transfer-Encoding: chunked\r\n"
+      "Content-Type: text/plain\r\n"
+      "\r\n"
+      "E\r\n"
+      "Hello, world!\n\r\n"
+      "21; some-random-chunk-extension\r\n"
+      "It sure is good to see you today.\r\n"
+      "0\r\n"
+      "\r\n"));
+}
+
+// Check that Transfer-Encoding: chunked supersedes Content-Length.
+TEST_F(HttpResponseParserTest, ContentLengthAndTransferEncoding) {
+  InSequence seq;
+  EXPECT_CALL(visitor_, OnStatusLine(Eq("HTTP/1.1"), Eq("200"), Eq("OK")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(Eq("Content-Length"), Eq("3")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(
+      Eq("Transfer-Encoding"), Eq("chunked")));
+  EXPECT_CALL(visitor_, OnLeadingHeadersComplete(Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq("Hello,"), Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq(" world!\n"), Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq(""), Eq(true)));
+
+  ASSERT_TRUE(parser_.ProcessInput(
+      "HTTP/1.1 200 OK\r\n"
+      "Content-Length: 3\r\n"
+      "Transfer-Encoding: chunked\r\n"
+      "\r\n"
+      "6\r\n"
+      "Hello,\r\n"
+      "8\r\n"
+      " world!\n\r\n"
+      "0\r\n"
+      "\r\n"));
+}
+
+// Check that Transfer-Encoding: chunked supersedes Content-Length even if
+// Content-Length comes later.
+TEST_F(HttpResponseParserTest, TransferEncodingAndContentLength) {
+  InSequence seq;
+  EXPECT_CALL(visitor_, OnStatusLine(Eq("HTTP/1.1"), Eq("200"), Eq("OK")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(
+      Eq("Transfer-Encoding"), Eq("chunked")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(Eq("Content-Length"), Eq("3")));
+  EXPECT_CALL(visitor_, OnLeadingHeadersComplete(Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq("Hello,"), Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq(" world!\n"), Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq(""), Eq(true)));
+
+  ASSERT_TRUE(parser_.ProcessInput(
+      "HTTP/1.1 200 OK\r\n"
+      "Transfer-Encoding: chunked\r\n"
+      "Content-Length: 3\r\n"
+      "\r\n"
+      "6\r\n"
+      "Hello,\r\n"
+      "8\r\n"
+      " world!\n\r\n"
+      "0\r\n"
+      "\r\n"));
+}
+
+TEST_F(HttpResponseParserTest, NoBodyData) {
+  InSequence seq;
+  EXPECT_CALL(visitor_, OnStatusLine(Eq("HTTP/1.1"), Eq("301"),
+                                     Eq("Moved permenantly")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(Eq("X-Empty"), Eq("")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(Eq("Location"), Eq("/foo/bar.html")));
+  EXPECT_CALL(visitor_, OnLeadingHeadersComplete(Eq(true)));
+
+  ASSERT_TRUE(parser_.ProcessInput(
+      "HTTP/1.1  301  Moved permenantly\r\n"
+      "X-Empty:\r\n"
+      "Location: /foo/bar.html\r\n"
+      "\r\n"));
+}
+
+TEST_F(HttpResponseParserTest, NoStatusPhrase) {
+  InSequence seq;
+  EXPECT_CALL(visitor_, OnStatusLine(Eq("HTTP/1.1"), Eq("123"), Eq("")));
+  EXPECT_CALL(visitor_, OnLeadingHeadersComplete(Eq(true)));
+
+  ASSERT_TRUE(parser_.ProcessInput(
+      "HTTP/1.1 123\r\n"
+      "\r\n"));
+}
+
+TEST_F(HttpResponseParserTest, HeadersBrokenAcrossLines) {
+  InSequence seq;
+  EXPECT_CALL(visitor_, OnStatusLine(Eq("HTTP/1.1"), Eq("301"),
+                                     Eq("Moved permenantly")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(
+      Eq("X-NextLine"), Eq("Alas, this is legal HTTP.")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(Eq("Location"), Eq("/foo/bar.html")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(
+      Eq("X-ThreeLines"), Eq("foo    bar  baz     quux")));
+  EXPECT_CALL(visitor_, OnLeadingHeadersComplete(Eq(true)));
+
+  ASSERT_TRUE(parser_.ProcessInput(
+      "HTTP/1.1 301 Moved permenantly\r\n"
+      "X-NextLine:\r\n"
+      "\tAlas, this is legal HTTP.\r\n"
+      "Location: /foo/bar.html\r\n"
+      "X-ThreeLines: foo\r\n"
+      "    bar  baz \r\n"
+      "    quux\r\n"
+      "\r\n"));
+}
+
+TEST_F(HttpResponseParserTest, DividedUpIntoPieces) {
+  InSequence seq;
+  EXPECT_CALL(visitor_, OnStatusLine(Eq("HTTP/1.1"), Eq("418"),
+                                     Eq("I'm a teapot")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(
+      Eq("tRaNsFeR-EnCoDiNg"), Eq("chunked")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(Eq("X-TwoLines"), Eq("foo  bar")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(Eq("Content-Type"), Eq("text/plain")));
+  EXPECT_CALL(visitor_, OnLeadingHeadersComplete(Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq("Hello,"), Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq(" world!\n"), Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq("It sure"), Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq(" is good to see you today."), Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq(""), Eq(true)));
+
+  ASSERT_TRUE(parser_.ProcessInput("HTTP/1.1 418 I'm"));
+  ASSERT_TRUE(parser_.ProcessInput(" a teapot\r\ntRaNsFeR-EnCoDiNg:"));
+  ASSERT_TRUE(parser_.ProcessInput("chunked\r\n"));
+  ASSERT_TRUE(parser_.ProcessInput("X-TwoLines:\tfoo "));
+  ASSERT_TRUE(parser_.ProcessInput("\r\n"));
+  ASSERT_TRUE(parser_.ProcessInput(" bar"));
+  ASSERT_TRUE(parser_.ProcessInput("\r\nContent-Type: text/plain"));
+  ASSERT_TRUE(parser_.ProcessInput("\r\n\r\nE"));
+  ASSERT_TRUE(parser_.ProcessInput("\r\n"));
+  ASSERT_TRUE(parser_.ProcessInput("Hello,"));
+  ASSERT_TRUE(parser_.ProcessInput(" world!\n"));
+  ASSERT_TRUE(parser_.ProcessInput("\r\n"));
+  ASSERT_TRUE(parser_.ProcessInput("21; some-random-"));
+  ASSERT_TRUE(parser_.ProcessInput("chunk-extension\r\nIt sure"));
+  ASSERT_TRUE(parser_.ProcessInput(" is good to see you today.\r\n0"));
+  ASSERT_TRUE(parser_.ProcessInput("0\r\n\r\n"));
+}
+
+// Test that we gracefully handle bogus content-lengths.  We should effectively
+// ignore the header, assume that the response has no content, and ignore what
+// follows the headers.
+TEST_F(HttpResponseParserTest, BogusContentLength) {
+  EXPECT_CALL(visitor_, OnStatusLine(Eq("HTTP/1.1"), Eq("200"), Eq("OK")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(Eq("Content-Length"), Eq("bogus")));
+  EXPECT_CALL(visitor_, OnLeadingHeadersComplete(Eq(true)));
+
+  ASSERT_TRUE(parser_.ProcessInput(
+      "HTTP/1.1 200 OK\r\n"
+      "Content-Length: bogus\r\n"
+      "\r\n"
+      "bogus bogus bogus\r\n"));
+}
+
+// Test that we gracefully handle over-large content-lengths.  As with
+// unparsable Content-Length values, an overflow of the Content-Length value
+// should result in us ignoring it.
+TEST_F(HttpResponseParserTest, ContentLengthOverflow) {
+  EXPECT_CALL(visitor_, OnStatusLine(Eq("HTTP/1.1"), Eq("200"), Eq("OK")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(
+      Eq("Content-Length"), Eq("9999999999999999999999999999999999999")));
+  EXPECT_CALL(visitor_, OnLeadingHeadersComplete(Eq(true)));
+
+  ASSERT_TRUE(parser_.ProcessInput(
+      "HTTP/1.1 200 OK\r\n"
+      "Content-Length: 9999999999999999999999999999999999999\r\n"
+      "\r\n"
+      "bogus bogus bogus\r\n"));
+}
+
+// We should be able to handle pretty big content lengths without overflowing,
+// however!  Otherwise, downloads of extremely large files may fail.  Here, we
+// test (the beginning of) a response that will contain a 5TB of data.
+TEST_F(HttpResponseParserTest, LargeContentLength) {
+  EXPECT_CALL(visitor_, OnStatusLine(Eq("HTTP/1.1"), Eq("200"), Eq("OK")));
+  EXPECT_CALL(visitor_, OnLeadingHeader(
+      Eq("Content-Length"), Eq("5497558138880")));
+  EXPECT_CALL(visitor_, OnLeadingHeadersComplete(Eq(false)));
+  EXPECT_CALL(visitor_, OnData(Eq("This is the beginning of 5TB of data."),
+                               Eq(false)));
+
+  ASSERT_TRUE(parser_.ProcessInput(
+      "HTTP/1.1 200 OK\r\n"
+      "Content-Length: 5497558138880\r\n"
+      "\r\n"
+      "This is the beginning of 5TB of data."));
+  ASSERT_EQ(5497558138843uLL, parser_.GetRemainingBytesForTest());
+}
+
+}  // namespace

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_visitor_interface.cc
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_visitor_interface.cc?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_visitor_interface.cc (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_visitor_interface.cc Thu May  1 11:39:27 2014
@@ -0,0 +1,22 @@
+// Copyright 2010 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "mod_spdy/common/http_response_visitor_interface.h"
+
+namespace mod_spdy {
+
+HttpResponseVisitorInterface::HttpResponseVisitorInterface() {}
+HttpResponseVisitorInterface::~HttpResponseVisitorInterface() {}
+
+}  // namespace mod_spdy

Added: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_visitor_interface.h
URL: http://svn.apache.org/viewvc/httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_visitor_interface.h?rev=1591620&view=auto
==============================================================================
--- httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_visitor_interface.h (added)
+++ httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_visitor_interface.h Thu May  1 11:39:27 2014
@@ -0,0 +1,58 @@
+// Copyright 2010 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef MOD_SPDY_COMMON_HTTP_RESPONSE_VISITOR_INTERFACE_H_
+#define MOD_SPDY_COMMON_HTTP_RESPONSE_VISITOR_INTERFACE_H_
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+
+namespace mod_spdy {
+
+// Interface that gets called back as an HTTP response is visited.
+class HttpResponseVisitorInterface {
+ public:
+  HttpResponseVisitorInterface();
+  virtual ~HttpResponseVisitorInterface();
+
+  // Called when an HTTP response status line is visited.  Indicates that a new
+  // HTTP response is being visited.
+  virtual void OnStatusLine(const base::StringPiece& version,
+                            const base::StringPiece& status_code,
+                            const base::StringPiece& status_phrase) = 0;
+
+  // Called zero or more times, once for each leading (i.e. normal, not
+  // trailing) HTTP header.  This is called after OnStatusLine but before
+  // OnLeadingHeadersComplete.
+  virtual void OnLeadingHeader(const base::StringPiece& key,
+                               const base::StringPiece& value) = 0;
+
+  // Called after the leading HTTP headers have been visited.  This will be
+  // called exactly once when the leading headers are done (even if there were
+  // no leading headers).  If the `fin` argument is true, the response is now
+  // complete (i.e. it has no body) and no more methods will be called.
+  virtual void OnLeadingHeadersComplete(bool fin) = 0;
+
+  // Called zero or more times, after OnLeadingHeadersComplete.  If the `fin`
+  // argument is true, the response is now complete and no more methods will be
+  // called.
+  virtual void OnData(const base::StringPiece& data, bool fin) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HttpResponseVisitorInterface);
+};
+
+}  // namespace mod_spdy
+
+#endif  // MOD_SPDY_COMMON_HTTP_RESPONSE_VISITOR_INTERFACE_H_

Propchange: httpd/mod_spdy/branches/httpd-2.2.x/mod_spdy/common/http_response_visitor_interface.h
------------------------------------------------------------------------------
    svn:eol-style = native