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